mirror of
https://github.com/PaperMC/Paper.git
synced 2026-11-04 17:00:09 -05:00
Compare commits
70
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76d2ac758c | ||
|
|
20938c7217 | ||
|
|
ca5e948ace | ||
|
|
e2c7e5cff2 | ||
|
|
d4fe85375a | ||
|
|
3580fa4066 | ||
|
|
10a73fe40f | ||
|
|
34cf3ab0f9 | ||
|
|
fd45f4b2e3 | ||
|
|
5c917dabab | ||
|
|
2186e1e407 | ||
|
|
711c5de2b0 | ||
|
|
687ba1e391 | ||
|
|
8dea6f1761 | ||
|
|
b4682bfef6 | ||
|
|
b685281d74 | ||
|
|
b8b4a1c7cd | ||
|
|
11dbf11014 | ||
|
|
39bd1bac06 | ||
|
|
afea65c2d2 | ||
|
|
1835b0468f | ||
|
|
b80b604636 | ||
|
|
6048c2d97c | ||
|
|
2e7bb166b1 | ||
|
|
39a1aa5c7f | ||
|
|
174eab0192 | ||
|
|
5d62ec0ed9 | ||
|
|
17524d0ee0 | ||
|
|
7799bf28ae | ||
|
|
55be6c0ef5 | ||
|
|
5dc4afc1dd | ||
|
|
f4e769a74d | ||
|
|
651d8481b7 | ||
|
|
acfe105b9d | ||
|
|
a64ea13e8e | ||
|
|
1f8197327f | ||
|
|
8021488ef4 | ||
|
|
182b2f8a2a | ||
|
|
a8c05a35c2 | ||
|
|
945aea9961 | ||
|
|
4aef3f0a67 | ||
|
|
60073714ba | ||
|
|
4f184db3c9 | ||
|
|
57d84f68a3 | ||
|
|
49daadd25d | ||
|
|
b2b1e177cb | ||
|
|
90aee8e007 | ||
|
|
d74f6bc77a | ||
|
|
dd203a2716 | ||
|
|
dcf5577aae | ||
|
|
c39822ae08 | ||
|
|
4af86ff3e0 | ||
|
|
1a8417b12b | ||
|
|
65461225ef | ||
|
|
7b31cc2b6b | ||
|
|
aa6f09b098 | ||
|
|
944ce44a4a | ||
|
|
6fe7eb5aae | ||
|
|
948acae8c2 | ||
|
|
ef4e85d6db | ||
|
|
3611a815e6 | ||
|
|
1d14197790 | ||
|
|
6bac3c95bf | ||
|
|
9b1dd57135 | ||
|
|
4be1a310c2 | ||
|
|
66d3bbed38 | ||
|
|
d0be5e20fd | ||
|
|
dd0810c4af | ||
|
|
04ee8eac9b | ||
|
|
c58cba39fb |
No files matched your search
+12
-3
@@ -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?
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ public net.minecraft.stats.ServerRecipeBook known
|
||||
public net.minecraft.tags.TagEntry id
|
||||
public net.minecraft.tags.TagEntry required
|
||||
public net.minecraft.tags.TagEntry tag
|
||||
public net.minecraft.util.AbstractListBuilder
|
||||
public net.minecraft.util.Util onThreadException(Ljava/lang/Thread;Ljava/lang/Throwable;)V
|
||||
public net.minecraft.util.datafix.fixes.BlockStateData register(ILcom/mojang/serialization/Dynamic;[Lcom/mojang/serialization/Dynamic;)V
|
||||
public net.minecraft.util.datafix.fixes.ItemIdFix ITEM_NAMES
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
||||
|
||||
plugins {
|
||||
id("io.papermc.paperweight.core") version "2.0.0-SNAPSHOT" apply false
|
||||
id("io.papermc.paperweight.core") version "2.0.0-beta.21" apply false
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package io.papermc.paper.registry.keys;
|
||||
|
||||
import static net.kyori.adventure.key.Key.key;
|
||||
|
||||
import io.papermc.paper.annotation.GeneratedClass;
|
||||
import io.papermc.paper.entity.poi.PoiType;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.TypedKey;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Vanilla keys for {@link RegistryKey#POINT_OF_INTEREST_TYPE}.
|
||||
*
|
||||
* @apiNote The fields provided here are a direct representation of
|
||||
* what is available from the vanilla game source. They may be
|
||||
* changed (including removals) on any Minecraft version
|
||||
* bump, so cross-version compatibility is not provided on the
|
||||
* same level as it is on most of the other API.
|
||||
*/
|
||||
@SuppressWarnings({
|
||||
"unused",
|
||||
"SpellCheckingInspection"
|
||||
})
|
||||
@NullMarked
|
||||
@GeneratedClass
|
||||
public final class PoiTypeKeys {
|
||||
/**
|
||||
* {@code minecraft:armorer}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> ARMORER = create(key("armorer"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:bee_nest}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> BEE_NEST = create(key("bee_nest"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:beehive}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> BEEHIVE = create(key("beehive"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:butcher}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> BUTCHER = create(key("butcher"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:cartographer}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> CARTOGRAPHER = create(key("cartographer"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:cleric}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> CLERIC = create(key("cleric"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:farmer}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> FARMER = create(key("farmer"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:fisherman}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> FISHERMAN = create(key("fisherman"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:fletcher}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> FLETCHER = create(key("fletcher"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:home}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> HOME = create(key("home"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:leatherworker}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> LEATHERWORKER = create(key("leatherworker"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:librarian}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> LIBRARIAN = create(key("librarian"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:lightning_rod}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> LIGHTNING_ROD = create(key("lightning_rod"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:lodestone}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> LODESTONE = create(key("lodestone"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:mason}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> MASON = create(key("mason"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:meeting}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> MEETING = create(key("meeting"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:nether_portal}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> NETHER_PORTAL = create(key("nether_portal"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:shepherd}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> SHEPHERD = create(key("shepherd"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:test_instance}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> TEST_INSTANCE = create(key("test_instance"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:toolsmith}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> TOOLSMITH = create(key("toolsmith"));
|
||||
|
||||
/**
|
||||
* {@code minecraft:weaponsmith}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TypedKey<PoiType> WEAPONSMITH = create(key("weaponsmith"));
|
||||
|
||||
private PoiTypeKeys() {
|
||||
}
|
||||
|
||||
private static TypedKey<PoiType> create(final Key key) {
|
||||
return TypedKey.create(RegistryKey.POINT_OF_INTEREST_TYPE, key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.papermc.paper.registry.keys.tags;
|
||||
|
||||
import static net.kyori.adventure.key.Key.key;
|
||||
|
||||
import io.papermc.paper.annotation.GeneratedClass;
|
||||
import io.papermc.paper.entity.poi.PoiType;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Vanilla tag keys for {@link RegistryKey#POINT_OF_INTEREST_TYPE}.
|
||||
*
|
||||
* @apiNote The fields provided here are a direct representation of
|
||||
* what is available from the vanilla game source. They may be
|
||||
* changed (including removals) on any Minecraft version
|
||||
* bump, so cross-version compatibility is not provided on the
|
||||
* same level as it is on most of the other API.
|
||||
*/
|
||||
@SuppressWarnings({
|
||||
"unused",
|
||||
"SpellCheckingInspection"
|
||||
})
|
||||
@NullMarked
|
||||
@GeneratedClass
|
||||
public final class PoiTypeTagKeys {
|
||||
/**
|
||||
* {@code #minecraft:acquirable_job_site}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TagKey<PoiType> ACQUIRABLE_JOB_SITE = create(key("acquirable_job_site"));
|
||||
|
||||
/**
|
||||
* {@code #minecraft:bee_home}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TagKey<PoiType> BEE_HOME = create(key("bee_home"));
|
||||
|
||||
/**
|
||||
* {@code #minecraft:village}
|
||||
*
|
||||
* @apiNote This field is version-dependant and may be removed in future Minecraft versions
|
||||
*/
|
||||
public static final TagKey<PoiType> VILLAGE = create(key("village"));
|
||||
|
||||
private PoiTypeTagKeys() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tag key for {@link PoiType} in the registry {@code minecraft:point_of_interest_type}.
|
||||
*
|
||||
* @param key the tag key's key
|
||||
* @return a new tag key
|
||||
*/
|
||||
public static TagKey<PoiType> create(final Key key) {
|
||||
return TagKey.create(RegistryKey.POINT_OF_INTEREST_TYPE, key);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -75,7 +75,7 @@ public final class NamespacedTag implements com.destroystokyo.paper.Namespaced {
|
||||
Preconditions.checkArgument(key != null, "Key cannot be null");
|
||||
|
||||
this.namespace = plugin.getName().toLowerCase(Locale.ROOT);
|
||||
this.key = key.toLowerCase().toLowerCase(Locale.ROOT);
|
||||
this.key = key.toLowerCase(Locale.ROOT);
|
||||
|
||||
// Check validity after normalization
|
||||
Preconditions.checkArgument(VALID_NAMESPACE.matcher(this.namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace);
|
||||
|
||||
+8
-1
@@ -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();
|
||||
|
||||
@@ -257,16 +257,16 @@ public interface PlayerProfile extends org.bukkit.profile.PlayerProfile, PlayerH
|
||||
|
||||
@Override
|
||||
default void applySkinToPlayerHeadContents(final PlayerHeadObjectContents.Builder builder) {
|
||||
if (this.getProperties().isEmpty() && (this.getName() != null) != (this.getId() != null)) {
|
||||
if (this.getProperties().isEmpty()) {
|
||||
if (this.getId() != null) {
|
||||
builder.id(this.getId());
|
||||
} else {
|
||||
} else if (this.getName() != null) {
|
||||
builder.name(this.getName());
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
builder.id(this.getId())
|
||||
.name(this.getName())
|
||||
.profileProperties(this.getProperties().stream().map(prop -> property(prop.getName(), prop.getValue(), prop.getSignature())).toList());
|
||||
}
|
||||
builder.id(this.getId())
|
||||
.name(this.getName())
|
||||
.profileProperties(this.getProperties().stream().map(prop -> property(prop.getName(), prop.getValue(), prop.getSignature())).toList());
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package io.papermc.paper;
|
||||
import com.destroystokyo.paper.SkinParts;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import io.papermc.paper.datacomponent.item.ResolvableProfile;
|
||||
import io.papermc.paper.entity.poi.PoiType;
|
||||
import io.papermc.paper.world.damagesource.CombatEntry;
|
||||
import io.papermc.paper.world.damagesource.FallLocationType;
|
||||
import java.util.Set;
|
||||
@@ -52,6 +53,14 @@ public interface InternalAPIBridge {
|
||||
*/
|
||||
DamageEffect getDamageEffect(String key);
|
||||
|
||||
/**
|
||||
* Creates an occupancy instance for the passed enum entry name.
|
||||
*
|
||||
* @param enumNameEntry the enum entry
|
||||
* @return the occupancy
|
||||
*/
|
||||
PoiType.Occupancy createOccupancy(String enumNameEntry);
|
||||
|
||||
/**
|
||||
* Constructs the legacy custom biome instance for the biome enum.
|
||||
*
|
||||
|
||||
@@ -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).
|
||||
|
||||
+2
-3
@@ -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);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package io.papermc.paper.entity.poi;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Holds the result of searching for a point of interest.
|
||||
*
|
||||
* @see World#locateAllPoiInRange(Location, Predicate, int)
|
||||
* @see World#locateAllPoiInRange(Location, Predicate, int, PoiType.Occupancy)
|
||||
*/
|
||||
@NullMarked
|
||||
public interface PoiSearchResult {
|
||||
|
||||
/**
|
||||
* Returns the {@link PoiType}.
|
||||
*
|
||||
* @return the {@link PoiType}
|
||||
*/
|
||||
PoiType poiType();
|
||||
|
||||
/**
|
||||
* Return the location of the {@link PoiType}.
|
||||
*
|
||||
* @return the location the {@link PoiType} was found at
|
||||
*/
|
||||
Location location();
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package io.papermc.paper.entity.poi;
|
||||
|
||||
import io.papermc.paper.InternalAPIBridge;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Represents a point of interest (POI).
|
||||
* <p>
|
||||
* Many PoiTypes act as a marker vs storing occupants examples of this are most
|
||||
* explicitly {@link PoiTypes#NETHER_PORTAL}. This state can be checked using the method
|
||||
* {@link #hasOccupants()} which will return {@code true} if the PoiType can have occupants.
|
||||
*
|
||||
* @see PoiTypes
|
||||
*/
|
||||
@NullMarked
|
||||
public interface PoiType extends Keyed {
|
||||
|
||||
/**
|
||||
* Determines whether the provided BlockState is relevant to this
|
||||
* point of interest.
|
||||
*
|
||||
* @param data the BlockData to check
|
||||
* @return {@code true} if the BlockState is relevant, otherwise {@code false}
|
||||
*/
|
||||
boolean is(BlockData data);
|
||||
|
||||
/**
|
||||
* Determines whether this PoiType can actually hold occupants.
|
||||
*
|
||||
* @return {@code true} if this PoiType can hold occupants
|
||||
*/
|
||||
boolean hasOccupants();
|
||||
|
||||
/**
|
||||
* Determines the type of occupancy the point of interest has.
|
||||
* <p>
|
||||
* A PoiType occupancy is defined by how much "space" a point of interest
|
||||
* has.
|
||||
* <p>
|
||||
* With context to a Villager workstation if a villager is currently using
|
||||
* a workstation as a source of its profession the occupancy would be
|
||||
* {@link Occupancy#IS_OCCUPIED}, however, if no villager was attached to
|
||||
* a workstation its occupancy would be {@link Occupancy#HAS_SPACE}.
|
||||
*/
|
||||
interface Occupancy {
|
||||
|
||||
/**
|
||||
* The poi has space.
|
||||
*/
|
||||
Occupancy HAS_SPACE = occupancy("HAS_SPACE");
|
||||
/**
|
||||
* The poi is occupied.
|
||||
*/
|
||||
Occupancy IS_OCCUPIED = occupancy("IS_OCCUPIED");
|
||||
/**
|
||||
* The poi is either occupied or has space.
|
||||
*/
|
||||
Occupancy ANY = occupancy("ANY");
|
||||
|
||||
private static Occupancy occupancy(final String enumEntryName) {
|
||||
return InternalAPIBridge.get().createOccupancy(enumEntryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package io.papermc.paper.entity.poi;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.key.KeyPattern;
|
||||
import org.bukkit.Registry;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* All the built-in point of interest types.
|
||||
*/
|
||||
@NullMarked
|
||||
public final class PoiTypes {
|
||||
|
||||
// Start generate - PoiTypes
|
||||
public static final PoiType ARMORER = get("armorer");
|
||||
|
||||
public static final PoiType BEE_NEST = get("bee_nest");
|
||||
|
||||
public static final PoiType BEEHIVE = get("beehive");
|
||||
|
||||
public static final PoiType BUTCHER = get("butcher");
|
||||
|
||||
public static final PoiType CARTOGRAPHER = get("cartographer");
|
||||
|
||||
public static final PoiType CLERIC = get("cleric");
|
||||
|
||||
public static final PoiType FARMER = get("farmer");
|
||||
|
||||
public static final PoiType FISHERMAN = get("fisherman");
|
||||
|
||||
public static final PoiType FLETCHER = get("fletcher");
|
||||
|
||||
public static final PoiType HOME = get("home");
|
||||
|
||||
public static final PoiType LEATHERWORKER = get("leatherworker");
|
||||
|
||||
public static final PoiType LIBRARIAN = get("librarian");
|
||||
|
||||
public static final PoiType LIGHTNING_ROD = get("lightning_rod");
|
||||
|
||||
public static final PoiType LODESTONE = get("lodestone");
|
||||
|
||||
public static final PoiType MASON = get("mason");
|
||||
|
||||
public static final PoiType MEETING = get("meeting");
|
||||
|
||||
public static final PoiType NETHER_PORTAL = get("nether_portal");
|
||||
|
||||
public static final PoiType SHEPHERD = get("shepherd");
|
||||
|
||||
public static final PoiType TEST_INSTANCE = get("test_instance");
|
||||
|
||||
public static final PoiType TOOLSMITH = get("toolsmith");
|
||||
|
||||
public static final PoiType WEAPONSMITH = get("weaponsmith");
|
||||
// End generate - PoiTypes
|
||||
|
||||
private static PoiType get(@KeyPattern.Value final String key) {
|
||||
return Registry.POINT_OF_INTEREST_TYPE.getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key));
|
||||
}
|
||||
|
||||
private PoiTypes() {
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.papermc.paper.registry;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentType;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.entity.poi.PoiType;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.key.KeyPattern;
|
||||
@@ -92,6 +93,11 @@ public sealed interface RegistryKey<T> extends Keyed permits RegistryKeyImpl {
|
||||
* @see io.papermc.paper.registry.keys.VillagerProfessionKeys
|
||||
*/
|
||||
RegistryKey<Villager.Profession> VILLAGER_PROFESSION = create("villager_profession");
|
||||
/**
|
||||
* Built-in registry for poi types.
|
||||
* @see io.papermc.paper.registry.keys.PoiTypeKeys
|
||||
*/
|
||||
RegistryKey<PoiType> POINT_OF_INTEREST_TYPE = create("point_of_interest_type");
|
||||
/**
|
||||
* Built-in registry for villager types.
|
||||
* @see io.papermc.paper.registry.keys.VillagerTypeKeys
|
||||
|
||||
+3
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -857,11 +857,15 @@ public final class Bukkit {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world with the given name.
|
||||
* Gets the world with the given legacy Bukkit name.
|
||||
*
|
||||
* @param name the name of the world to retrieve
|
||||
* @return a world with the given name, or null if none exists
|
||||
* <p>This method is considered obsolete and is a candidate for future deprecation.
|
||||
* Prefer using {@link #getWorld(NamespacedKey)}.</p>
|
||||
*
|
||||
* @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
|
||||
public static World getWorld(@NotNull String name) {
|
||||
return server.getWorld(name);
|
||||
@@ -877,7 +881,7 @@ public final class Bukkit {
|
||||
public static World getWorld(@NotNull UUID uid) {
|
||||
return server.getWorld(uid);
|
||||
}
|
||||
// Paper start
|
||||
|
||||
/**
|
||||
* Gets the world from the given NamespacedKey
|
||||
*
|
||||
@@ -899,7 +903,6 @@ public final class Bukkit {
|
||||
public static World getWorld(@NotNull net.kyori.adventure.key.Key worldKey) {
|
||||
return server.getWorld(worldKey);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
/**
|
||||
* Create a new virtual {@link WorldBorder}.
|
||||
|
||||
@@ -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")));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import io.papermc.paper.world.MoonPhase;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -526,12 +527,12 @@ public interface RegionAccessor extends Keyed, io.papermc.paper.world.flag.Featu
|
||||
@NotNull
|
||||
public <T extends Entity> T addEntity(@NotNull T entity);
|
||||
|
||||
// Paper start
|
||||
/**
|
||||
* @return the current moon phase at the current time in the world
|
||||
* @apiNote the returned value may be inaccurate in custom biome using environmental attribute override
|
||||
*/
|
||||
@NotNull
|
||||
io.papermc.paper.world.MoonPhase getMoonPhase();
|
||||
MoonPhase getMoonPhase();
|
||||
|
||||
/**
|
||||
* Get the world's key
|
||||
@@ -559,5 +560,4 @@ public interface RegionAccessor extends Keyed, io.papermc.paper.world.flag.Featu
|
||||
* @return collides or not
|
||||
*/
|
||||
boolean hasCollisionsIn(@NotNull org.bukkit.util.BoundingBox boundingBox);
|
||||
// Paper end
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import io.papermc.paper.datacomponent.DataComponentType;
|
||||
import io.papermc.paper.entity.poi.PoiType;
|
||||
import io.papermc.paper.registry.RegistryAccess;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.TypedKey;
|
||||
@@ -280,6 +281,12 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
|
||||
* @see Villager.Profession
|
||||
*/
|
||||
Registry<Villager.Profession> VILLAGER_PROFESSION = registryFor(RegistryKey.VILLAGER_PROFESSION);
|
||||
/**
|
||||
* Point of interest types.
|
||||
*
|
||||
* @see PoiType
|
||||
*/
|
||||
Registry<PoiType> POINT_OF_INTEREST_TYPE = registryFor(RegistryKey.POINT_OF_INTEREST_TYPE);
|
||||
/**
|
||||
* Villager type.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.bukkit;
|
||||
|
||||
import io.papermc.paper.entity.poi.PoiSearchResult;
|
||||
import io.papermc.paper.entity.poi.PoiType;
|
||||
import io.papermc.paper.raytracing.PositionedRayTraceConfigurationBuilder;
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
@@ -43,6 +45,7 @@ import org.bukkit.util.BoundingBox;
|
||||
import org.bukkit.util.RayTraceResult;
|
||||
import org.bukkit.util.StructureSearchResult;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.checkerframework.checker.index.qual.Positive;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -2091,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
|
||||
@@ -2769,10 +2770,11 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
/**
|
||||
* Gets if this world is natural.
|
||||
* <p>
|
||||
* When false, the moon is not visible and eyeblossoms do not open/close
|
||||
* When true, eyeblossoms cycle open/close, nether portals can spawn
|
||||
* zombified piglins and creaking heart works
|
||||
*
|
||||
* @return true if world is natural
|
||||
* @deprecated replaced by the gameplay/eyeblossom_open and gameplay/creaking_active environment attributes
|
||||
* @deprecated replaced by the gameplay/nether_portal_spawns_piglin, gameplay/eyeblossom_open and gameplay/creaking_active environmental attributes
|
||||
*/
|
||||
@Deprecated(since = "1.21.11")
|
||||
public boolean isNatural();
|
||||
@@ -2784,7 +2786,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
* not always be the case.
|
||||
*
|
||||
* @return true if beds work in this world
|
||||
* @deprecated Due to 1.21.11 beds changes, a boolean no longer
|
||||
* @deprecated due to 1.21.11 beds changes, a boolean no longer
|
||||
* represents if they work. There is no replacement API yet
|
||||
*/
|
||||
@ApiStatus.Obsolete(since = "1.21.11")
|
||||
@@ -2809,6 +2811,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
* transforming to zombified piglins.
|
||||
*
|
||||
* @return true if piglins will not transform to zombified piglins
|
||||
* @apiNote the returned value may be inaccurate in custom biome using environmental attribute override
|
||||
*/
|
||||
public boolean isPiglinSafe();
|
||||
|
||||
@@ -2816,6 +2819,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
* Gets if this world allows players to charge and use respawn anchors.
|
||||
*
|
||||
* @return true if players can charge and use respawn anchors
|
||||
* @apiNote the returned value may be inaccurate in custom biome using environmental attribute override
|
||||
*/
|
||||
public boolean isRespawnAnchorWorks();
|
||||
|
||||
@@ -2824,6 +2828,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
* raid.
|
||||
*
|
||||
* @return true if raids will be triggered
|
||||
* @apiNote the returned value may be inaccurate in custom biome using environmental attribute override
|
||||
*/
|
||||
public boolean hasRaids();
|
||||
|
||||
@@ -2837,7 +2842,7 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
* </ul>
|
||||
*
|
||||
* @return true if this world has the above mechanics
|
||||
* @deprecated as of 1.21.11, ultra warm is replaced by the WATER_EVAPORATES, FAST_LAVA, and DEFAULT_DRIPSTONE_PARTICLE environment attributes.
|
||||
* @deprecated replaced by the gameplay/water_evaporates and gameplay/fast_lava environmental attributes
|
||||
*/
|
||||
@Deprecated(since = "1.21.11")
|
||||
public boolean isUltraWarm();
|
||||
@@ -4295,6 +4300,69 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||
return java.util.Optional.ofNullable(this.locateNearestBiome(origin, radius, step, step, biome)).map(BiomeSearchResult::getLocation).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the nearest point of interest closest to the given location
|
||||
* without any occupancy restriction.
|
||||
*
|
||||
* @param origin where to start looking for a new point of interest at
|
||||
* @param poiType the poi type to find
|
||||
* @param radius the radius
|
||||
* @return a location at the nearest PoiType or {@code null} if no poi was found
|
||||
*/
|
||||
@Nullable
|
||||
default Location locateNearestPoi(@NotNull Location origin, @NotNull PoiType poiType, @Positive int radius) {
|
||||
return this.locateNearestPoi(origin, poiType, radius, PoiType.Occupancy.ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the nearest point of interest closest to the given location.
|
||||
* <p>
|
||||
* {@link PoiType} that return {@code false} for {@link PoiType#hasOccupants()}
|
||||
* may not behave as expected for given occupancies other than
|
||||
* {@link PoiType.Occupancy#ANY}.
|
||||
*
|
||||
* @param origin where to start looking for a new point of interest at
|
||||
* @param poiType the poi type to find
|
||||
* @param radius the radius
|
||||
* @param occupancy the current required occupancy of the point of interest
|
||||
* @return a location at the nearest PoiType or {@code null} if no poi was found
|
||||
*/
|
||||
@Nullable
|
||||
Location locateNearestPoi(@NotNull Location origin, @NotNull PoiType poiType, @Positive int radius, @NotNull PoiType.Occupancy occupancy);
|
||||
|
||||
/**
|
||||
* Finds all valid {@link PoiType} in the provided radius and returns them
|
||||
* in a list format without any occupancy restriction.
|
||||
*
|
||||
* @param origin the center point of the radius
|
||||
* @param poiTypePredicate the predicate to test whether a PoiType
|
||||
* can be collected into the result
|
||||
* @param radius the radius
|
||||
* @return a list of search results containing all found Poi's in the range
|
||||
*/
|
||||
@NotNull
|
||||
default List<PoiSearchResult> locateAllPoiInRange(@NotNull Location origin, @NotNull Predicate<PoiType> poiTypePredicate, @Positive int radius) {
|
||||
return this.locateAllPoiInRange(origin, poiTypePredicate, radius, PoiType.Occupancy.ANY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all valid {@link PoiType} in the provided radius and returns them
|
||||
* in a list format.
|
||||
* <p>
|
||||
* {@link PoiType} that return false for {@link PoiType#hasOccupants()}
|
||||
* may not behave as expected for given occupancies other than
|
||||
* {@link PoiType.Occupancy#ANY}.
|
||||
*
|
||||
* @param origin the center point of the radius
|
||||
* @param poiTypePredicate the predicate to test whether a PoiType
|
||||
* can be collected into the result
|
||||
* @param radius the radius
|
||||
* @param occupancy the current required occupancy of the point of interest
|
||||
* @return a list of search results containing all found Poi's in the range
|
||||
*/
|
||||
@NotNull
|
||||
List<PoiSearchResult> locateAllPoiInRange(@NotNull Location origin, @NotNull Predicate<PoiType> poiTypePredicate, @Positive int radius, @NotNull PoiType.Occupancy occupancy);
|
||||
|
||||
/**
|
||||
* Gets the coordinate scaling of this world.
|
||||
*
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.bukkit;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.Random;
|
||||
import io.papermc.paper.math.Position;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.generator.BiomeProvider;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
@@ -26,6 +27,10 @@ public class WorldCreator {
|
||||
private boolean hardcore = false;
|
||||
private boolean bonusChest = false;
|
||||
|
||||
private @Nullable Position spawnPositionOverride;
|
||||
private @Nullable Float spawnYawOverride;
|
||||
private @Nullable Float spawnPitchOverride;
|
||||
|
||||
/**
|
||||
* Creates an empty WorldCreationOptions for the given world name.
|
||||
*
|
||||
@@ -261,6 +266,80 @@ public class WorldCreator {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the forced spawn position for the world created by this {@link WorldCreator}.
|
||||
* <p>
|
||||
* This overrides vanilla and custom generator behavior without loading any chunks.
|
||||
* When a forced spawn is specified, the bonus chest will not be generated.
|
||||
*
|
||||
* @param position the spawn position
|
||||
* @param yaw the yaw rotation at spawn
|
||||
* @param pitch the pitch rotation at spawn
|
||||
* @return this object, for chaining
|
||||
*/
|
||||
@NotNull
|
||||
public WorldCreator forcedSpawnPosition(@NotNull Position position, float yaw, float pitch) {
|
||||
this.spawnPositionOverride = position; // If you set this to null, it wont do anything!
|
||||
this.spawnYawOverride = yaw;
|
||||
this.spawnPitchOverride = pitch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any previously forced spawn position.
|
||||
* <p>
|
||||
* After calling this, vanilla spawn selection behavior is used.
|
||||
*
|
||||
* @return this object, for chaining
|
||||
*/
|
||||
@NotNull
|
||||
public WorldCreator clearForcedSpawnPosition() {
|
||||
this.spawnPositionOverride = null;
|
||||
this.spawnYawOverride = null;
|
||||
this.spawnPitchOverride = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the forced spawn position that will be applied when this world is created.
|
||||
* <p>
|
||||
* If this returns {@code null}, vanilla or custom generator behavior will be used
|
||||
* to determine the spawn position.
|
||||
*
|
||||
* @return the forced spawn position, or {@code null} for the vanilla behavior
|
||||
*/
|
||||
public @Nullable Position forcedSpawnPosition() {
|
||||
return this.spawnPositionOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the forced spawn yaw that will be applied when this world is created.
|
||||
* <p>
|
||||
* If this returns {@code null}, the spawn yaw will be determined by vanilla behavior
|
||||
* or the world generator.
|
||||
* <p>
|
||||
* This value is only meaningful if a forced spawn position is present.
|
||||
*
|
||||
* @return the forced spawn yaw, or {@code null} for the vanilla behavior
|
||||
*/
|
||||
public @Nullable Float forcedSpawnYaw() {
|
||||
return this.spawnYawOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the forced spawn pitch that will be applied when this world is created.
|
||||
* <p>
|
||||
* If this returns {@code null}, the spawn pitch will be determined by vanilla behavior
|
||||
* or the world generator.
|
||||
* <p>
|
||||
* This value is only meaningful if a forced spawn position is present.
|
||||
*
|
||||
* @return the forced spawn pitch, or {@code null} for the vanilla behavior
|
||||
*/
|
||||
public @Nullable Float forcedSpawnPitch() {
|
||||
return this.spawnPitchOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the generator that will be used to create or load the world.
|
||||
* <p>
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.bukkit.Keyed;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.Translatable;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.util.OldEnum;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -170,6 +171,13 @@ public interface Attribute extends OldEnum<Attribute>, Keyed, Translatable, net.
|
||||
@NotNull
|
||||
Sentiment getSentiment();
|
||||
|
||||
/**
|
||||
* {@return the default value of this attribute}
|
||||
* <p>
|
||||
* Default attribute values may differ between entity types, use {@link EntityType#getDefaultAttributes()} to get default attribute values for a specific entity type.
|
||||
*/
|
||||
double getDefaultValue();
|
||||
|
||||
/**
|
||||
* @param name of the attribute.
|
||||
* @return the attribute with the given name.
|
||||
|
||||
@@ -111,6 +111,11 @@ public interface AttributeInstance {
|
||||
* Gets the default value of the Attribute attached to this instance.
|
||||
*
|
||||
* @return server default value
|
||||
* @deprecated this method is placed misleadingly as it does not return the default value in the current entity's context, but in the server's context.
|
||||
* Use {@link Attribute#getDefaultValue()} as a replacement and see the note there about default values for specific entity types
|
||||
* @see Attribute#getDefaultValue()
|
||||
* @see org.bukkit.entity.EntityType#getDefaultAttributes()
|
||||
*/
|
||||
@Deprecated(since = "26.1")
|
||||
double getDefaultValue();
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public interface AreaEffectCloud extends Entity {
|
||||
float getRadiusPerTick();
|
||||
|
||||
/**
|
||||
* Gets the amount that the radius of this cloud will decrease by each tick.
|
||||
* Sets the amount that the radius of this cloud will decrease by each tick.
|
||||
*
|
||||
* @param radius per tick delta
|
||||
*/
|
||||
@@ -139,7 +139,7 @@ public interface AreaEffectCloud extends Entity {
|
||||
/**
|
||||
* Sets the particle which this cloud will be composed of
|
||||
*
|
||||
* @param <T> type of particle data (see {@link Particle#getDataType()}
|
||||
* @param <T> type of particle data (see {@link Particle#getDataType()})
|
||||
* @param particle the new particle type
|
||||
* @param data the data to use for the particle or null,
|
||||
* the type of this depends on {@link Particle#getDataType()}
|
||||
|
||||
@@ -2,12 +2,15 @@ package org.bukkit.entity;
|
||||
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.bukkit.damage.DamageType;
|
||||
import org.bukkit.event.entity.EntityRegainHealthEvent;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an {@link Entity} that has health and can take damage.
|
||||
*/
|
||||
@NullMarked
|
||||
public interface Damageable extends Entity {
|
||||
/**
|
||||
* Deals the given amount of damage to this entity.
|
||||
@@ -32,7 +35,24 @@ public interface Damageable extends Entity {
|
||||
* @param amount amount of damage to deal
|
||||
* @param damageSource source to which the damage should be attributed
|
||||
*/
|
||||
void damage(double amount, @NotNull DamageSource damageSource);
|
||||
void damage(double amount, DamageSource damageSource);
|
||||
|
||||
/**
|
||||
* Sets the entity's health to 0 and kill the entity with a generic DamageSource.
|
||||
*
|
||||
* @throws IllegalStateException if is used in world generation
|
||||
*/
|
||||
default void kill() {
|
||||
this.kill(DamageSource.builder(DamageType.GENERIC_KILL).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the entity's health to 0 and kill the entity with the specified DamageSource.
|
||||
*
|
||||
* @param damageSource the DamageSource to use for the kill
|
||||
* @throws IllegalStateException if is used in world generation
|
||||
*/
|
||||
void kill(DamageSource damageSource);
|
||||
|
||||
/**
|
||||
* Gets the entity's health from 0 to {@link #getMaxHealth()}, where 0 is dead.
|
||||
@@ -57,7 +77,7 @@ public interface Damageable extends Entity {
|
||||
* @param amount heal amount
|
||||
*/
|
||||
default void heal(final double amount) {
|
||||
this.heal(amount, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.CUSTOM);
|
||||
this.heal(amount, EntityRegainHealthEvent.RegainReason.CUSTOM);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +86,7 @@ public interface Damageable extends Entity {
|
||||
* @param amount heal amount
|
||||
* @param reason heal reason
|
||||
*/
|
||||
void heal(double amount, @NotNull org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason reason);
|
||||
void heal(double amount, EntityRegainHealthEvent.RegainReason reason);
|
||||
|
||||
/**
|
||||
* Gets the entity's absorption amount.
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
package org.bukkit.entity;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.FireworkMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public interface Firework extends Projectile {
|
||||
|
||||
/**
|
||||
* Get a copy of the fireworks meta
|
||||
*
|
||||
* @return A copy of the current Firework meta
|
||||
* @apiNote obsolete in favor of {@link #getItem()} / {@link #setItem(ItemStack)} with the equivalent {@link DataComponentTypes#FIREWORKS} component
|
||||
*/
|
||||
@NotNull
|
||||
@ApiStatus.Obsolete
|
||||
FireworkMeta getFireworkMeta();
|
||||
|
||||
/**
|
||||
@@ -20,8 +26,10 @@ public interface Firework extends Projectile {
|
||||
* Adjusts detonation ticks automatically.
|
||||
*
|
||||
* @param meta The FireworkMeta to apply
|
||||
* @apiNote obsolete in favor of {@link #getItem()} / {@link #setItem(ItemStack)} with the equivalent {@link DataComponentTypes#FIREWORKS} component
|
||||
*/
|
||||
void setFireworkMeta(@NotNull FireworkMeta meta);
|
||||
@ApiStatus.Obsolete
|
||||
void setFireworkMeta(FireworkMeta meta);
|
||||
|
||||
/**
|
||||
* Set the {@link LivingEntity} to which this firework is attached.
|
||||
@@ -48,8 +56,7 @@ public interface Firework extends Projectile {
|
||||
*
|
||||
* @return the attached entity, or null if none
|
||||
*/
|
||||
@Nullable
|
||||
LivingEntity getAttachedTo();
|
||||
@Nullable LivingEntity getAttachedTo();
|
||||
|
||||
/**
|
||||
* Set the ticks that this firework has been alive. If this value exceeds
|
||||
@@ -59,7 +66,7 @@ public interface Firework extends Projectile {
|
||||
* @deprecated use {@link #setTicksFlown(int)}
|
||||
* @return true if the life was set, false if this firework has already detonated
|
||||
*/
|
||||
@Deprecated(forRemoval = true) // Paper
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
boolean setLife(int ticks);
|
||||
|
||||
/**
|
||||
@@ -69,7 +76,7 @@ public interface Firework extends Projectile {
|
||||
* @deprecated use {@link #getTicksFlown()}
|
||||
* @return the life ticks
|
||||
*/
|
||||
@Deprecated(forRemoval = true) // Paper
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
int getLife();
|
||||
|
||||
/**
|
||||
@@ -79,7 +86,7 @@ public interface Firework extends Projectile {
|
||||
* @deprecated use {@link #setTicksToDetonate(int)}
|
||||
* @return true if the time was set, false if this firework has already detonated
|
||||
*/
|
||||
@Deprecated(forRemoval = true) // Paper
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
boolean setMaxLife(int ticks);
|
||||
|
||||
/**
|
||||
@@ -88,7 +95,7 @@ public interface Firework extends Projectile {
|
||||
* @deprecated use {@link #getTicksToDetonate()}
|
||||
* @return the maximum life in ticks
|
||||
*/
|
||||
@Deprecated(forRemoval = true) // Paper
|
||||
@Deprecated(forRemoval = true, since = "1.18.2")
|
||||
int getMaxLife();
|
||||
|
||||
/**
|
||||
@@ -122,30 +129,30 @@ public interface Firework extends Projectile {
|
||||
*/
|
||||
void setShotAtAngle(boolean shotAtAngle);
|
||||
|
||||
// Paper start
|
||||
@org.jetbrains.annotations.Nullable
|
||||
public java.util.UUID getSpawningEntity();
|
||||
/**
|
||||
* Retrieves the UUID of the entity responsible for spawning this firework.
|
||||
*
|
||||
* @return the UUID of the spawning entity, or null if no spawning entity is associated
|
||||
*/
|
||||
@Nullable UUID getSpawningEntity();
|
||||
|
||||
/**
|
||||
* If this firework is boosting an entity, return it
|
||||
* @deprecated use {@link #getAttachedTo()}
|
||||
* @see #setAttachedTo(LivingEntity)
|
||||
* @return The entity being boosted
|
||||
*/
|
||||
@org.jetbrains.annotations.Nullable
|
||||
@Deprecated
|
||||
default LivingEntity getBoostedEntity() {
|
||||
return getAttachedTo();
|
||||
@Deprecated(since = "1.18.2")
|
||||
default @Nullable LivingEntity getBoostedEntity() {
|
||||
return this.getAttachedTo();
|
||||
}
|
||||
// Paper end
|
||||
|
||||
// Paper start - Firework API
|
||||
/**
|
||||
* Gets the item used in the firework.
|
||||
*
|
||||
* @return firework item
|
||||
*/
|
||||
@NotNull
|
||||
public org.bukkit.inventory.ItemStack getItem();
|
||||
ItemStack getItem();
|
||||
|
||||
/**
|
||||
* Sets the item used in the firework.
|
||||
@@ -154,7 +161,7 @@ public interface Firework extends Projectile {
|
||||
*
|
||||
* @param itemStack item to set
|
||||
*/
|
||||
void setItem(@org.jetbrains.annotations.Nullable org.bukkit.inventory.ItemStack itemStack);
|
||||
void setItem(@Nullable ItemStack itemStack);
|
||||
|
||||
/**
|
||||
* Gets the number of ticks the firework has flown.
|
||||
@@ -184,5 +191,4 @@ public interface Firework extends Projectile {
|
||||
* @param ticks ticks to detonate on
|
||||
*/
|
||||
void setTicksToDetonate(int ticks);
|
||||
// Paper end
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.bukkit.entity;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.item.Fireworks;
|
||||
import io.papermc.paper.datacomponent.item.UseCooldown;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import io.papermc.paper.datacomponent.item.UseCooldown;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
@@ -20,7 +22,6 @@ import org.bukkit.inventory.MainHand;
|
||||
import org.bukkit.inventory.MenuType;
|
||||
import org.bukkit.inventory.Merchant;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.meta.FireworkMeta;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -1009,16 +1010,35 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
||||
* Perform a firework boost.
|
||||
* <p>
|
||||
* This method will only work such that {@link #isGliding()} is true and
|
||||
* the entity is actively gliding with an elytra. Additionally, the supplied
|
||||
* {@code fireworkItemStack} must be a firework rocket. The power of the boost
|
||||
* will directly correlate to {@link FireworkMeta#getPower()}.
|
||||
* the entity is actively gliding with an item with {@link DataComponentTypes#GLIDER} component.
|
||||
* <p>
|
||||
* The power of the boost will directly correlate to {@link Fireworks#flightDuration()} from {@link DataComponentTypes#FIREWORKS} component.
|
||||
* <p>
|
||||
* This method does not fire {@link com.destroystokyo.paper.event.player.PlayerElytraBoostEvent}.
|
||||
*
|
||||
* @param fireworkItemStack the firework item stack to use to glide
|
||||
* @param boosterItem the item to use to boost
|
||||
* @return the attached {@link Firework}, or null if the entity could not
|
||||
* be boosted
|
||||
* @throws IllegalArgumentException if the fireworkItemStack is not a firework
|
||||
*/
|
||||
@Nullable
|
||||
public Firework fireworkBoost(ItemStack fireworkItemStack);
|
||||
Firework fireworkBoost(ItemStack boosterItem);
|
||||
|
||||
/**
|
||||
* Perform a firework boost.
|
||||
* <p>
|
||||
* This method will only work such that {@link #isGliding()} is true and
|
||||
* the entity is actively gliding with an item with {@link DataComponentTypes#GLIDER} component.
|
||||
* <p>
|
||||
* The power of the boost will directly correlate to {@link Fireworks#flightDuration()} from {@link DataComponentTypes#FIREWORKS} component.
|
||||
* <p>
|
||||
* This method does not fire {@link com.destroystokyo.paper.event.player.PlayerElytraBoostEvent}.
|
||||
*
|
||||
* @return the attached {@link Firework}, or null if the entity could not
|
||||
* be boosted
|
||||
*/
|
||||
@Nullable
|
||||
default Firework fireworkBoost() {
|
||||
return this.fireworkBoost(ItemStack.empty());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.bukkit.entity;
|
||||
|
||||
import com.destroystokyo.paper.ClientOption;
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.connection.PlayerGameConnection;
|
||||
import io.papermc.paper.entity.LookAnchor;
|
||||
import io.papermc.paper.entity.PlayerGiveResult;
|
||||
@@ -3349,8 +3350,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
|
||||
*/
|
||||
@@ -3617,24 +3617,22 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
|
||||
<T> T getClientOption(ClientOption<T> option);
|
||||
// Paper end - client option API
|
||||
|
||||
// Paper start - elytra boost API
|
||||
/**
|
||||
* Boost a Player that's {@link #isGliding()} using a {@link Firework}.
|
||||
* If the creation of the entity is cancelled, no boosting is done.
|
||||
* This method does not fire {@link com.destroystokyo.paper.event.player.PlayerElytraBoostEvent}.
|
||||
*
|
||||
* @param firework The {@link Material#FIREWORK_ROCKET} to boost the player with
|
||||
* @param boosterItem The itemstack to boost the player with
|
||||
* @return The {@link Firework} boosting the Player or null if the spawning of the entity was cancelled
|
||||
* @throws IllegalArgumentException if {@link #isGliding()} is false
|
||||
* or if the {@code firework} isn't a {@link Material#FIREWORK_ROCKET}
|
||||
* @throws IllegalStateException if {@link #isGliding()} is false
|
||||
* @deprecated use {@link HumanEntity#fireworkBoost(ItemStack)} instead. Note that this method <b>does not</b>
|
||||
* check if the player is gliding or not.
|
||||
*/
|
||||
default @Nullable Firework boostElytra(final ItemStack firework) {
|
||||
com.google.common.base.Preconditions.checkState(this.isGliding(), "Player must be gliding");
|
||||
return this.fireworkBoost(firework);
|
||||
@Deprecated(since = "1.20.5")
|
||||
default @Nullable Firework boostElytra(final ItemStack boosterItem) {
|
||||
Preconditions.checkState(this.isGliding(), "Player must be gliding");
|
||||
return this.fireworkBoost(boosterItem);
|
||||
}
|
||||
// Paper end - elytra boost API
|
||||
|
||||
// Paper start - sendOpLevel API
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package org.bukkit.entity;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public interface ThrowableProjectile extends Projectile {
|
||||
|
||||
/**
|
||||
@@ -10,7 +11,6 @@ public interface ThrowableProjectile extends Projectile {
|
||||
*
|
||||
* @return The thrown item display ItemStack
|
||||
*/
|
||||
@NotNull
|
||||
ItemStack getItem();
|
||||
|
||||
/**
|
||||
@@ -18,5 +18,5 @@ public interface ThrowableProjectile extends Projectile {
|
||||
*
|
||||
* @param item ItemStack set to be displayed
|
||||
*/
|
||||
void setItem(@NotNull ItemStack item);
|
||||
void setItem(ItemStack item);
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
package org.bukkit.entity;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import java.util.Collection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Represents a thrown potion bottle
|
||||
*/
|
||||
@NullMarked
|
||||
public interface ThrownPotion extends ThrowableProjectile {
|
||||
|
||||
/**
|
||||
@@ -15,8 +19,7 @@ public interface ThrownPotion extends ThrowableProjectile {
|
||||
*
|
||||
* @return The potion effects
|
||||
*/
|
||||
@NotNull
|
||||
public Collection<PotionEffect> getEffects();
|
||||
Collection<PotionEffect> getEffects();
|
||||
|
||||
/**
|
||||
* Returns a copy of the ItemStack for this thrown potion.
|
||||
@@ -27,25 +30,24 @@ public interface ThrownPotion extends ThrowableProjectile {
|
||||
*
|
||||
* @return A copy of the ItemStack for this thrown potion.
|
||||
*/
|
||||
@NotNull
|
||||
public ItemStack getItem();
|
||||
ItemStack getItem();
|
||||
|
||||
/**
|
||||
* Set the ItemStack for this thrown potion.
|
||||
*
|
||||
* @param item New ItemStack
|
||||
*/
|
||||
public void setItem(@NotNull ItemStack item);
|
||||
void setItem(ItemStack item);
|
||||
|
||||
// Paper start - Projectile API
|
||||
/**
|
||||
* Gets a copy of the PotionMeta for this thrown potion.
|
||||
* This includes what effects will be applied by this potion.
|
||||
*
|
||||
* @return potion meta
|
||||
* @apiNote obsolete in favor of {@link #getItem()} / {@link #setItem(ItemStack)} with the equivalent {@link DataComponentTypes#POTION_CONTENTS} component
|
||||
*/
|
||||
@NotNull
|
||||
org.bukkit.inventory.meta.PotionMeta getPotionMeta();
|
||||
@ApiStatus.Obsolete
|
||||
PotionMeta getPotionMeta();
|
||||
|
||||
/**
|
||||
* Sets the PotionMeta of this thrown potion.
|
||||
@@ -54,12 +56,13 @@ public interface ThrownPotion extends ThrowableProjectile {
|
||||
* Note that the type of {@link #getItem()} is irrelevant
|
||||
*
|
||||
* @param meta potion meta
|
||||
* @apiNote obsolete in favor of {@link #getItem()} / {@link #setItem(ItemStack)} with the equivalent {@link DataComponentTypes#POTION_CONTENTS} component
|
||||
*/
|
||||
void setPotionMeta(@NotNull org.bukkit.inventory.meta.PotionMeta meta);
|
||||
@ApiStatus.Obsolete
|
||||
void setPotionMeta(PotionMeta meta);
|
||||
|
||||
/**
|
||||
* Splashes the potion at its current location.
|
||||
*/
|
||||
void splash();
|
||||
// Paper end
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,30 @@
|
||||
package org.bukkit.event.hanging;
|
||||
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Hanging;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Triggered when a hanging entity is removed by an entity
|
||||
*/
|
||||
@NullMarked
|
||||
public class HangingBreakByEntityEvent extends HangingBreakEvent {
|
||||
|
||||
private final Entity remover;
|
||||
private final DamageSource damageSource;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public HangingBreakByEntityEvent(@NotNull final Hanging hanging, @NotNull final Entity remover) {
|
||||
this(hanging, remover, HangingBreakEvent.RemoveCause.ENTITY);
|
||||
public HangingBreakByEntityEvent(final Hanging hanging, final Entity remover, final DamageSource damageSource) {
|
||||
this(hanging, remover, damageSource, HangingBreakEvent.RemoveCause.ENTITY);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public HangingBreakByEntityEvent(@NotNull final Hanging hanging, @NotNull final Entity remover, @NotNull final HangingBreakEvent.RemoveCause cause) {
|
||||
public HangingBreakByEntityEvent(final Hanging hanging, final Entity remover, final DamageSource damageSource, final HangingBreakEvent.RemoveCause cause) {
|
||||
super(hanging, cause);
|
||||
this.remover = remover;
|
||||
this.damageSource = damageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,8 +32,16 @@ public class HangingBreakByEntityEvent extends HangingBreakEvent {
|
||||
*
|
||||
* @return the entity that removed the hanging entity
|
||||
*/
|
||||
@NotNull
|
||||
public Entity getRemover() {
|
||||
return this.remover;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link DamageSource} that caused the hanging entity to be removed.
|
||||
*
|
||||
* @return the damage source
|
||||
*/
|
||||
public DamageSource getDamageSource() {
|
||||
return this.damageSource;
|
||||
}
|
||||
}
|
||||
@@ -6,24 +6,26 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Called when a player gets kicked from the server
|
||||
*/
|
||||
@NullMarked
|
||||
public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
|
||||
private Component kickReason;
|
||||
private Component leaveMessage;
|
||||
private @Nullable Component leaveMessage;
|
||||
private final Cause cause;
|
||||
|
||||
private boolean cancelled;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Deprecated(forRemoval = true)
|
||||
public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final String kickReason, @NotNull final String leaveMessage) {
|
||||
public PlayerKickEvent(final Player playerKicked, final String kickReason, final String leaveMessage) {
|
||||
super(playerKicked);
|
||||
this.kickReason = LegacyComponentSerializer.legacySection().deserialize(kickReason);
|
||||
this.leaveMessage = LegacyComponentSerializer.legacySection().deserialize(leaveMessage);
|
||||
@@ -32,7 +34,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Deprecated(forRemoval = true)
|
||||
public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final Component kickReason, @NotNull final Component leaveMessage) {
|
||||
public PlayerKickEvent(final Player playerKicked, final Component kickReason, final Component leaveMessage) {
|
||||
super(playerKicked);
|
||||
this.kickReason = kickReason;
|
||||
this.leaveMessage = leaveMessage;
|
||||
@@ -40,7 +42,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final Component kickReason, @NotNull final Component leaveMessage, @NotNull final Cause cause) {
|
||||
public PlayerKickEvent(final Player playerKicked, final Component kickReason, final Component leaveMessage, final Cause cause) {
|
||||
super(playerKicked);
|
||||
this.kickReason = kickReason;
|
||||
this.leaveMessage = leaveMessage;
|
||||
@@ -52,7 +54,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
*
|
||||
* @return string kick reason
|
||||
*/
|
||||
public @NotNull Component reason() {
|
||||
public Component reason() {
|
||||
return this.kickReason;
|
||||
}
|
||||
|
||||
@@ -61,7 +63,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
*
|
||||
* @param kickReason kick reason
|
||||
*/
|
||||
public void reason(@NotNull Component kickReason) {
|
||||
public void reason(Component kickReason) {
|
||||
this.kickReason = kickReason;
|
||||
}
|
||||
|
||||
@@ -71,7 +73,6 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
* @return string kick reason
|
||||
* @deprecated in favour of {@link #reason()}
|
||||
*/
|
||||
@NotNull
|
||||
@Deprecated
|
||||
public String getReason() {
|
||||
return LegacyComponentSerializer.legacySection().serialize(this.kickReason);
|
||||
@@ -81,10 +82,10 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
* Sets the reason why the player is getting kicked
|
||||
*
|
||||
* @param kickReason kick reason
|
||||
* @deprecated in favour of {@link #reason(net.kyori.adventure.text.Component)}
|
||||
* @deprecated in favour of {@link #reason(Component)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setReason(@NotNull String kickReason) {
|
||||
public void setReason(String kickReason) {
|
||||
this.kickReason = LegacyComponentSerializer.legacySection().deserialize(kickReason);
|
||||
}
|
||||
|
||||
@@ -93,16 +94,16 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
*
|
||||
* @return string kick reason
|
||||
*/
|
||||
public @NotNull Component leaveMessage() {
|
||||
public @Nullable Component leaveMessage() {
|
||||
return this.leaveMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the leave message send to all online players
|
||||
*
|
||||
* @param leaveMessage leave message
|
||||
* @param leaveMessage leave message. If {@code null}, no message will be sent
|
||||
*/
|
||||
public void leaveMessage(@NotNull Component leaveMessage) {
|
||||
public void leaveMessage(@Nullable Component leaveMessage) {
|
||||
this.leaveMessage = leaveMessage;
|
||||
}
|
||||
|
||||
@@ -112,28 +113,26 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
* @return string kick reason
|
||||
* @deprecated in favour of {@link #leaveMessage()}
|
||||
*/
|
||||
@NotNull
|
||||
@Deprecated
|
||||
public String getLeaveMessage() {
|
||||
return LegacyComponentSerializer.legacySection().serialize(this.leaveMessage);
|
||||
public @Nullable String getLeaveMessage() {
|
||||
return LegacyComponentSerializer.legacySection().serializeOrNull(this.leaveMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the leave message send to all online players
|
||||
*
|
||||
* @param leaveMessage leave message
|
||||
* @deprecated in favour of {@link #leaveMessage(net.kyori.adventure.text.Component)}
|
||||
* @param leaveMessage leave message. If {@code null}, no message will be sent
|
||||
* @deprecated in favour of {@link #leaveMessage(Component)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setLeaveMessage(@NotNull String leaveMessage) {
|
||||
this.leaveMessage = LegacyComponentSerializer.legacySection().deserialize(leaveMessage);
|
||||
public void setLeaveMessage(@Nullable String leaveMessage) {
|
||||
this.leaveMessage = LegacyComponentSerializer.legacySection().deserializeOrNull(leaveMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cause of this kick
|
||||
*/
|
||||
@NotNull
|
||||
public org.bukkit.event.player.PlayerKickEvent.Cause getCause() {
|
||||
public PlayerKickEvent.Cause getCause() {
|
||||
return this.cause;
|
||||
}
|
||||
|
||||
@@ -147,13 +146,11 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.bukkit.event.vehicle;
|
||||
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.Cancellable;
|
||||
@@ -15,18 +16,30 @@ public class VehicleDamageEvent extends VehicleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
|
||||
private final DamageSource damageSource;
|
||||
private final Entity attacker;
|
||||
private double damage;
|
||||
|
||||
private boolean cancelled;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public VehicleDamageEvent(@NotNull final Vehicle vehicle, @Nullable final Entity attacker, final double damage) {
|
||||
public VehicleDamageEvent(final @NotNull Vehicle vehicle, final @NotNull DamageSource damageSource, final @Nullable Entity attacker, final double damage) {
|
||||
super(vehicle);
|
||||
this.damageSource = damageSource;
|
||||
this.attacker = attacker;
|
||||
this.damage = damage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DamageSource that caused the damage.
|
||||
*
|
||||
* @return the DamageSource that caused the damage
|
||||
*/
|
||||
@NotNull
|
||||
public DamageSource getDamageSource() {
|
||||
return this.damageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Entity that is attacking the vehicle
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.bukkit.event.vehicle;
|
||||
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.Cancellable;
|
||||
@@ -17,15 +18,27 @@ public class VehicleDestroyEvent extends VehicleEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
|
||||
private final DamageSource damageSource;
|
||||
private final Entity attacker;
|
||||
private boolean cancelled;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public VehicleDestroyEvent(@NotNull final Vehicle vehicle, @Nullable final Entity attacker) {
|
||||
public VehicleDestroyEvent(final @NotNull Vehicle vehicle, final @NotNull DamageSource damageSource, final @Nullable Entity attacker) {
|
||||
super(vehicle);
|
||||
this.damageSource = damageSource;
|
||||
this.attacker = attacker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DamageSource that has destroyed the vehicle.
|
||||
*
|
||||
* @return the DamageSource that has destroyed the vehicle
|
||||
*/
|
||||
@NotNull
|
||||
public DamageSource getDamageSource() {
|
||||
return this.damageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Entity that has destroyed the vehicle, potentially null
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -133,26 +133,74 @@ public class PotionEffect implements ConfigurationSerializable {
|
||||
}
|
||||
|
||||
// Paper start
|
||||
/**
|
||||
* Returns a new potion effect with the provided type and this effect's
|
||||
* duration, amplifier, ambient, particles, and icon.
|
||||
*
|
||||
* @param type effect type
|
||||
* @return a new potion effect with the provided type
|
||||
*/
|
||||
@NotNull
|
||||
public PotionEffect withType(@NotNull PotionEffectType type) {
|
||||
return new PotionEffect(type, duration, amplifier, ambient, particles, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new potion effect with the provided duration and this effect's
|
||||
* type, amplifier, ambient, particles, and icon.
|
||||
*
|
||||
* @param duration measured in ticks, see {@link
|
||||
* PotionEffect#getDuration()}
|
||||
* @return a new potion effect with the provided duration
|
||||
*/
|
||||
@NotNull
|
||||
public PotionEffect withDuration(int duration) {
|
||||
return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new potion effect with the provided amplifier and this effect's
|
||||
* type, duration, ambient, particles, and icon.
|
||||
*
|
||||
* @param amplifier the amplifier, see {@link PotionEffect#getAmplifier()}
|
||||
* @return a new potion effect with the provided amplifier
|
||||
*/
|
||||
@NotNull
|
||||
public PotionEffect withAmplifier(int amplifier) {
|
||||
return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new potion effect with the provided ambient and this effect's
|
||||
* type, duration, amplifier, particles, and icon.
|
||||
*
|
||||
* @param ambient the ambient status, see {@link PotionEffect#isAmbient()}
|
||||
* @return a new potion effect with the provided ambient
|
||||
*/
|
||||
@NotNull
|
||||
public PotionEffect withAmbient(boolean ambient) {
|
||||
return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new potion effect with the provided particles and this effect's
|
||||
* type, duration, amplifier, ambient, and icon.
|
||||
*
|
||||
* @param particles the particle status, see {@link PotionEffect#hasParticles()}
|
||||
* @return a new potion effect with the provided particles
|
||||
*/
|
||||
@NotNull
|
||||
public PotionEffect withParticles(boolean particles) {
|
||||
return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new potion effect with the provided icon and this effect's
|
||||
* type, duration, amplifier, ambient, and particles.
|
||||
*
|
||||
* @param icon the icon status, see {@link PotionEffect#hasIcon()}
|
||||
* @return a new potion effect with the provided icon
|
||||
*/
|
||||
@NotNull
|
||||
public PotionEffect withIcon(boolean icon) {
|
||||
return new PotionEffect(this.type, duration, amplifier, ambient, particles, icon);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import io.papermc.paper.datacomponent.item.SwingAnimation;
|
||||
import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.item.MapPostProcessing;
|
||||
import io.papermc.paper.entity.poi.PoiTypes;
|
||||
import io.papermc.paper.world.WeatheringCopperState;
|
||||
import io.papermc.typewriter.preset.EnumCloneRewriter;
|
||||
import io.papermc.typewriter.preset.model.EnumValue;
|
||||
@@ -231,6 +232,7 @@ public final class Rewriters {
|
||||
.register("PigSoundVariant", Pig.SoundVariant.class, new RegistryFieldRewriter<>(Registries.PIG_SOUND_VARIANT, "getSoundVariant"))
|
||||
.register("ZombieNautilusVariant", ZombieNautilus.Variant.class, new RegistryFieldRewriter<>(Registries.ZOMBIE_NAUTILUS_VARIANT, "getVariant"))
|
||||
.register("Dialog", Dialog.class, new RegistryFieldRewriter<>(Registries.DIALOG, "getDialog"))
|
||||
.register("PoiTypes", PoiTypes.class, new RegistryFieldRewriter<>(Registries.POINT_OF_INTEREST_TYPE, "get"))
|
||||
.register("MemoryKey", MemoryKey.class, new MemoryKeyRewriter())
|
||||
// .register("ItemType", org.bukkit.inventory.ItemType.class, new io.papermc.generator.rewriter.types.simple.ItemTypeRewriter()) - disable for now, lynx want the generic type
|
||||
.register("BlockType", BlockType.class, new BlockTypeRewriter())
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.papermc.generator.utils.ClassHelper;
|
||||
import io.papermc.paper.datacomponent.DataComponentType;
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.entity.poi.PoiTypes;
|
||||
import io.papermc.paper.registry.data.BannerPatternRegistryEntry;
|
||||
import io.papermc.paper.registry.data.CatTypeRegistryEntry;
|
||||
import io.papermc.paper.registry.data.ChickenVariantRegistryEntry;
|
||||
@@ -175,7 +176,8 @@ public final class RegistryEntries {
|
||||
entry(Registries.FLUID, Fluids.class, Fluid.class),
|
||||
entry(Registries.SOUND_EVENT, SoundEvents.class, Sound.class).allowDirect().apiRegistryField("SOUNDS").apiRegistryBuilder(SoundEventRegistryEntry.Builder.class, "PaperSoundEventRegistryEntry.PaperBuilder", RegistryEntry.RegistryModificationApiSupport.NONE),
|
||||
entry(Registries.DATA_COMPONENT_TYPE, DataComponents.class, DataComponentType.class, "Paper").preload(DataComponentTypes.class).apiAccessName("of"),
|
||||
entry(Registries.GAME_RULE, GameRules.class, GameRule.class).genericArgCount(1)/*.preload(org.bukkit.GameRules.class)*/ // only preload once the old names are removed
|
||||
entry(Registries.GAME_RULE, GameRules.class, GameRule.class).genericArgCount(1)/*.preload(org.bukkit.GameRules.class)*/, // only preload once the old names are removed
|
||||
entry(Registries.POINT_OF_INTEREST_TYPE, PoiTypes.class, io.papermc.paper.entity.poi.PoiType.class, "Paper").preload(io.papermc.paper.entity.poi.PoiTypes.class)
|
||||
);
|
||||
|
||||
public static final List<RegistryEntry<?>> DATA_DRIVEN = List.of(
|
||||
|
||||
@@ -14,8 +14,8 @@ plugins {
|
||||
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")
|
||||
mache("io.papermc:mache:26.1.2+build.3")
|
||||
paperclip("io.papermc:paperclip:3.0.4")
|
||||
}
|
||||
|
||||
paperweight {
|
||||
@@ -23,7 +23,7 @@ paperweight {
|
||||
gitFilePatches = false
|
||||
|
||||
updatingMinecraft {
|
||||
// oldPaperCommit = "7e80cef5198561d0db53406127e5b8bc7af51577"
|
||||
// oldPaperCommit = "711c5de2b05df39b72c44ff54e9f9381f8d153cb"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -33491,7 +33491,7 @@ index 109d7b563ee799d998a5773c5a36e61ca3607d46..747755082639436731989d3ee4b3c30a
|
||||
return structureTemplate.save(new CompoundTag());
|
||||
}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 1b064f00c33712c3d2d85ed8520f1eda02abfbf9..65a971379f35c4b1b519b93787f690d891e29523 100644
|
||||
index c809ea1f2620c543d9bc80afdd64489f2fb98744..49be7709026cd75cfcb31715550387f0ba954a16 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -299,6 +299,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -33503,18 +33503,18 @@ index 1b064f00c33712c3d2d85ed8520f1eda02abfbf9..65a971379f35c4b1b519b93787f690d8
|
||||
Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> serverReference.get().runServer(), "Server thread");
|
||||
thread.setUncaughtExceptionHandler((t, e) -> LOGGER.error("Uncaught exception in server thread", e));
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
|
||||
index c206c74acc80c281d06a669eb668239dc61018eb..884fa9545a93008fa92863c845aef8f18d88e25a 100644
|
||||
index 4346f3bace176e09d9ffb02e9af29a1281071e2a..df4f03f3a346e0ab0074757b3a077b2407135ac3 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
|
||||
@@ -99,7 +99,7 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun
|
||||
}
|
||||
// Spigot end
|
||||
injectDatafixingContext(chunkTag, dataFixContextTag);
|
||||
- chunkTag = this.dataFixType.update(this.fixerUpper, chunkTag, version, targetVersion);
|
||||
+ chunkTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(this.getDataConverterType(), chunkTag, version, targetVersion); // Paper - rewrite dataconverter system
|
||||
// Spigot start
|
||||
if (stopBelowZero) {
|
||||
chunkTag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString());
|
||||
@@ -100,7 +100,7 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun
|
||||
}
|
||||
// Spigot end
|
||||
injectDatafixingContext(chunkTag, dataFixContextTag);
|
||||
- chunkTag = this.dataFixType.update(this.fixerUpper, chunkTag, version, targetVersion);
|
||||
+ chunkTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(this.getDataConverterType(), chunkTag, version, targetVersion); // Paper - rewrite dataconverter system
|
||||
// Spigot start
|
||||
if (stopBelowZero) {
|
||||
chunkTag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString());
|
||||
@@ -118,6 +118,20 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun
|
||||
}
|
||||
}
|
||||
@@ -33537,23 +33537,23 @@ index c206c74acc80c281d06a669eb668239dc61018eb..884fa9545a93008fa92863c845aef8f1
|
||||
return this.upgradeChunkTag(chunkTag, defaultVersion, null, SharedConstants.getCurrentVersion().dataVersion().version());
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/net/minecraft/world/level/levelgen/structure/StructureCheck.java
|
||||
index 2ab055d5cdfb1e2e7cfb6f8a769c3d571acb2861..a45da98735045d55d3da14271c9bbb7a37f3151c 100644
|
||||
index cba5c9ea5fd424e7aaeefaa8cc5ffe37f307b370..ce7856fa3b0f48099d09057bb44ce95a42367301 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/StructureCheck.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/StructureCheck.java
|
||||
@@ -161,7 +161,7 @@ public class StructureCheck {
|
||||
@@ -163,7 +163,7 @@ public class StructureCheck {
|
||||
|
||||
CompoundTag fixedChunkTag;
|
||||
try {
|
||||
- fixedChunkTag = DataFixTypes.CHUNK.updateToCurrentVersion(this.fixerUpper, chunkTag, version);
|
||||
+ fixedChunkTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, chunkTag, version, ca.spottedleaf.dataconverter.minecraft.util.Version.getCurrentVersion()); // Paper - replace chunk converter
|
||||
} catch (Exception var12) {
|
||||
LOGGER.warn("Failed to partially datafix chunk {}", pos, var12);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Failed to partially datafix chunk {}", pos, e);
|
||||
return StructureCheckResult.CHUNK_LOAD_NEEDED;
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java b/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java
|
||||
index 780a3eb08b7fb2c385c8e75e2e5f02a9d67297f4..2c7e4a6288f0c7101755de4be8f14449cdc4e01e 100644
|
||||
index e61076a9ff3d9bce5c44e548158716db105db3ee..fe1500ebbfb09bef18989c891a19608ec9d4661c 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java
|
||||
@@ -79,7 +79,7 @@ public abstract class TemplateSource {
|
||||
@@ -71,7 +71,7 @@ public abstract class TemplateSource {
|
||||
public StructureTemplate readStructure(final CompoundTag tag) {
|
||||
StructureTemplate structureTemplate = new StructureTemplate();
|
||||
int version = NbtUtils.getDataVersion(tag, 500);
|
||||
@@ -33563,7 +33563,7 @@ index 780a3eb08b7fb2c385c8e75e2e5f02a9d67297f4..2c7e4a6288f0c7101755de4be8f14449
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/storage/PlayerDataStorage.java b/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||
index 41cbb27861f33ad8d7523f3b2fef9a30a69693a9..c5898bfb8b4f075b08090cba2e9f980174e0a326 100644
|
||||
index 8eda63e1f07f7998875713447c5f39eea3f85ca4..eddb6ebe3fa50a818e54079b73ba117be0abd195 100644
|
||||
--- a/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||
+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java
|
||||
@@ -98,7 +98,7 @@ public class PlayerDataStorage {
|
||||
|
||||
+15
-14
@@ -28,10 +28,10 @@ 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 13faa13a9d3120cdeaca63d6eb3a0feb8019fb3a..d14aea970ce98edfe3dc3692e707334e7e150804 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -65,7 +65,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
@@ -64,7 +64,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
private static final ProtocolInfo<ServerHandshakePacketListener> INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND;
|
||||
private final PacketFlow receiving;
|
||||
private volatile boolean sendLoginDisconnect = true;
|
||||
@@ -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<?>> {
|
||||
@@ -392,11 +396,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<?>> {
|
||||
@@ -405,7 +436,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<?>> {
|
||||
@@ -419,21 +450,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<?>> {
|
||||
@@ -445,16 +497,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<?>> {
|
||||
@@ -524,6 +617,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<?>> {
|
||||
@@ -705,7 +799,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<?>> {
|
||||
@@ -716,7 +810,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<?>> {
|
||||
@@ -751,4 +845,96 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public void setBandwidthLogger(final LocalSampleLogger bandwidthLogger) {
|
||||
this.bandwidthDebugMonitor = new BandwidthDebugMonitor(bandwidthLogger);
|
||||
}
|
||||
@@ -371,10 +372,10 @@ 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 77e1c02b74c1f6597fbb5a457bf463fe52de019e..6d506004583b2415ab356e34e2f8d6ac0e39cca2 100644
|
||||
--- a/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -52,11 +52,13 @@ public class ServerConnectionListener {
|
||||
@@ -51,11 +51,13 @@ public class ServerConnectionListener {
|
||||
|
||||
// Paper start - prevent blocking on adding a new connection while the server is ticking
|
||||
private final java.util.Queue<Connection> pending = new java.util.concurrent.ConcurrentLinkedQueue<>();
|
||||
@@ -388,7 +389,7 @@ index b0445b4ad9adb6d2dec08537559d2ed243ca69bb..b266e4f7b437578356568d86910e3b42
|
||||
}
|
||||
}
|
||||
// Paper end - prevent blocking on adding a new connection while the server is ticking
|
||||
@@ -92,6 +94,7 @@ public class ServerConnectionListener {
|
||||
@@ -87,6 +89,7 @@ public class ServerConnectionListener {
|
||||
} catch (ChannelException var5) {
|
||||
}
|
||||
|
||||
|
||||
@@ -31,18 +31,18 @@ this fix, as the data will remain in the oversized file. Once the server returns
|
||||
to a jar with this fix, the data will be restored.
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 5149635679ec03d881e63effbd79fc193d7e52c8..d628e06a8dbf11b491b323c10a512fde22e72a12 100644
|
||||
index 026b1f31d5041786e90ba372a228732aee094c16..d39f8ae8f5736a7f4590ca41ac95792a61975baf 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -69,6 +69,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
@@ -68,6 +68,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
this.info = info;
|
||||
this.path = path;
|
||||
this.version = version;
|
||||
+ this.initOversizedState(); // Paper
|
||||
if (!Files.isDirectory(externalFileDir)) {
|
||||
throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath());
|
||||
} else {
|
||||
@@ -465,4 +466,75 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
@@ -463,4 +464,75 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
private interface CommitOp {
|
||||
void run() throws IOException;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ index 5149635679ec03d881e63effbd79fc193d7e52c8..d628e06a8dbf11b491b323c10a512fde
|
||||
+ private synchronized void initOversizedState() throws IOException {
|
||||
+ Path metaFile = getOversizedMetaFile();
|
||||
+ if (Files.exists(metaFile)) {
|
||||
+ final byte[] read = java.nio.file.Files.readAllBytes(metaFile);
|
||||
+ final byte[] read = Files.readAllBytes(metaFile);
|
||||
+ System.arraycopy(read, 0, oversized, 0, oversized.length);
|
||||
+ for (byte temp : oversized) {
|
||||
+ oversizedCount += temp;
|
||||
@@ -98,7 +98,7 @@ index 5149635679ec03d881e63effbd79fc193d7e52c8..d628e06a8dbf11b491b323c10a512fde
|
||||
+ }
|
||||
+
|
||||
+ private void writeOversizedMeta() throws IOException {
|
||||
+ java.nio.file.Files.write(getOversizedMetaFile(), oversized);
|
||||
+ Files.write(this.getOversizedMetaFile(), this.oversized);
|
||||
+ }
|
||||
+
|
||||
+ private Path getOversizedMetaFile() {
|
||||
@@ -119,16 +119,24 @@ index 5149635679ec03d881e63effbd79fc193d7e52c8..d628e06a8dbf11b491b323c10a512fde
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index e9316cc08fe4cb4af28583a8cb1ec658243bffd0..aa36e241d49725eb13f00e57d020d4da24add53d 100644
|
||||
index 36f8c19e3e90740e6d58eb8dbf573b2fdf4fed3d..3d0a09662e5ed1f7bc0c02dbe6de529791f2f66f 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -241,6 +241,43 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -16,6 +16,7 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage { // Paper - rewrite chunk system
|
||||
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
|
||||
public static final String ANVIL_EXTENSION = ".mca";
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
@@ -241,6 +242,43 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static void printOversizedLog(String msg, Path file, int x, int z) {
|
||||
+ org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed.");
|
||||
+ LOGGER.error("{} ({} - {},{}) Go clean it up to remove this message. /minecraft:tp {} 128 {} - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed.", msg, file.toString().replaceAll(".+[\\\\/]", ""), x, z, x << 4, z << 4);
|
||||
+ }
|
||||
+
|
||||
+ private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {
|
||||
@@ -145,9 +153,9 @@ index e9316cc08fe4cb4af28583a8cb1ec658243bffd0..aa36e241d49725eb13f00e57d020d4da
|
||||
+ mergeChunkList(chunk.getCompoundOrEmpty("Level"), oversizedLevel, "TileEntities", "TileEntities");
|
||||
+
|
||||
+ return chunk;
|
||||
+ } catch (Throwable throwable) {
|
||||
+ throwable.printStackTrace();
|
||||
+ throw throwable;
|
||||
+ } catch (Throwable t) {
|
||||
+ t.printStackTrace();
|
||||
+ throw t;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
@@ -166,7 +174,7 @@ index e9316cc08fe4cb4af28583a8cb1ec658243bffd0..aa36e241d49725eb13f00e57d020d4da
|
||||
public @Nullable CompoundTag read(final ChunkPos pos) throws IOException {
|
||||
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
|
||||
RegionFile region = this.getRegionFile(pos, true);
|
||||
@@ -248,6 +285,12 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -248,6 +286,12 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
return null;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -177,9 +185,9 @@ index e9316cc08fe4cb4af28583a8cb1ec658243bffd0..aa36e241d49725eb13f00e57d020d4da
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
CompoundTag var4;
|
||||
try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) {
|
||||
@@ -290,6 +333,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
return regionChunkInputStream == null ? null : NbtIo.read(regionChunkInputStream);
|
||||
@@ -283,6 +327,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
} else {
|
||||
try (DataOutputStream output = region.getChunkDataOutputStream(pos)) {
|
||||
NbtIo.write(value, output);
|
||||
|
||||
@@ -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 89da20b0682708ba8bfc0d10381eb9784d80c395..b5d63d7b848c11ed322d512adeee102886cbb6fd 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");
|
||||
@@ -462,7 +462,7 @@ index 0df8332933203a904bd9ef9efb3c9bce21e65441..1a502cbd8acea9420fa6dd8d716018b5
|
||||
public void tick() {
|
||||
super.tick();
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index f7b4da570ee28b7128b4d2cd1c67b89e3980bced..93d3fb313d538cc1067b1db010458169a1320122 100644
|
||||
index 593265d78564b60bacbb4899f18a6e74bf56601d..84c664711658eb83b5ff9d4c8470fd8ec54a5473 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -382,6 +382,15 @@ public abstract class Entity
|
||||
@@ -521,10 +521,10 @@ index f7b4da570ee28b7128b4d2cd1c67b89e3980bced..93d3fb313d538cc1067b1db010458169
|
||||
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 f62e535b62d249dd3be19d7c1b02fae8dad31c10..6eb95b979ffe37d78fd68eb57ebe71891beb0d28 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
|
||||
@@ -3380,6 +3380,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
protected void playAttackSound() {
|
||||
}
|
||||
|
||||
@@ -540,10 +540,10 @@ index c4da41f3b5ba6d8492d3776654b1ce62a5015895..6a0ebbdfcc0bc07915574c1cf87463e8
|
||||
public void tick() {
|
||||
super.tick();
|
||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||
index c7c53ef16e104ebc48aeb8719783fb4c45d39fc2..90eaa775dc134041647618c3b965334a9bb9fd3b 100644
|
||||
index e63ac861b785cf3dccac25404454289c44b7ec9d..8b036640be655c65852e0862e30962e443d3024d 100644
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -211,6 +211,19 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs
|
||||
@@ -211,6 +211,20 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs
|
||||
return this.lookControl;
|
||||
}
|
||||
|
||||
@@ -551,6 +551,7 @@ index c7c53ef16e104ebc48aeb8719783fb4c45d39fc2..90eaa775dc134041647618c3b965334a
|
||||
+ @Override
|
||||
+ public void inactiveTick() {
|
||||
+ super.inactiveTick();
|
||||
+ if (!this.aware) return; // Paper - Do not tick AI for inactive unaware mobs
|
||||
+ if (this.goalSelector.inactiveTick()) {
|
||||
+ this.goalSelector.tick();
|
||||
+ }
|
||||
@@ -564,7 +565,7 @@ index c7c53ef16e104ebc48aeb8719783fb4c45d39fc2..90eaa775dc134041647618c3b965334a
|
||||
return this.getControlledVehicle() instanceof Mob riding ? riding.getMoveControl() : this.moveControl;
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/PathfinderMob.java b/net/minecraft/world/entity/PathfinderMob.java
|
||||
index c4b4a135f61955c2b87801772a2b31eeeb77bf45..9d12cc2d169f243ba23485e2782bca7064282a36 100644
|
||||
index a19d8d4c0075340e8d187d5f8b6ce989567d3163..c661311dfdc1e21e3d6ec65e1e8b953637149675 100644
|
||||
--- a/net/minecraft/world/entity/PathfinderMob.java
|
||||
+++ b/net/minecraft/world/entity/PathfinderMob.java
|
||||
@@ -17,6 +17,8 @@ public abstract class PathfinderMob extends Mob {
|
||||
@@ -577,7 +578,7 @@ index c4b4a135f61955c2b87801772a2b31eeeb77bf45..9d12cc2d169f243ba23485e2782bca70
|
||||
return this.getWalkTargetValue(pos, this.level());
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index 6bc2d38fb990628784deb5ee615e34a0fc320a47..844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae 100644
|
||||
index c918154444a05917a3622947d0ddbc29bdb9bead..b13bdc2852504903fa054c42f89299a5d33dfbd3 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -24,6 +24,7 @@ public class GoalSelector {
|
||||
@@ -639,7 +640,7 @@ index d46e0e3a4a7fc3bb3f1dd695d4cc563778b99db0..c6e9b155c2341c13d569f28f54f0c1d2
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index c482c3348267ca2b88109e34291aa860e0cde916..b11b59d80e37d272770ab51a63028fdddfe800d6 100644
|
||||
index ca0b7ce4ab535d7112b315a7de1dc5130797ea2d..974d1d7b283aace71f0ea8ef07ba68a17b75af8a 100644
|
||||
--- a/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -124,6 +124,29 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
@@ -673,7 +674,7 @@ index c482c3348267ca2b88109e34291aa860e0cde916..b11b59d80e37d272770ab51a63028fdd
|
||||
public void tick() {
|
||||
if (this.getItem().isEmpty()) {
|
||||
diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java
|
||||
index a80e6a23cf29cb44943339101f15565dbc19af1f..f481fd661440f77c98940cbde4a8b95818e4a22c 100644
|
||||
index 084a4a945d4fc6a76878da00e5015c79fc88b47f..e4ba6e200e85f4e226d6a3e68db734f277b89226 100644
|
||||
--- a/net/minecraft/world/entity/npc/villager/Villager.java
|
||||
+++ b/net/minecraft/world/entity/npc/villager/Villager.java
|
||||
@@ -244,11 +244,35 @@ public class Villager extends AbstractVillager implements VillagerDataHolder, Re
|
||||
@@ -687,7 +688,7 @@ index a80e6a23cf29cb44943339101f15565dbc19af1f..f481fd661440f77c98940cbde4a8b958
|
||||
+ if (this.getUnhappyCounter() > 0) {
|
||||
+ this.setUnhappyCounter(this.getUnhappyCounter() - 1);
|
||||
+ }
|
||||
+ if (this.isEffectiveAi()) {
|
||||
+ if (this.aware && this.isEffectiveAi()) { // Paper - Do not tick AI for inactive unaware mobs
|
||||
+ if (this.level().spigotConfig.tickInactiveVillagers) {
|
||||
+ this.customServerAiStep(this.level().getMinecraftWorld());
|
||||
+ } else {
|
||||
@@ -778,7 +779,7 @@ index f3861c936855a0d9c9170585f4da4ce1cd77b854..3b4cbbc4c8ca1cd3110d1d6ba9e35312
|
||||
public void tick() {
|
||||
super.tick();
|
||||
diff --git a/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java b/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java
|
||||
index 3a590d4dc980a2912e9cc043d8c8db4cf9d60803..06ab7c48b18c03af494ab10fc2b584cefc776749 100644
|
||||
index f46cca0467bb4da5511bc953ce5b43fa606bf978..445c5cafad71028171c1f261939661775dd7f2bd 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java
|
||||
@@ -50,6 +50,7 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
@@ -789,20 +790,21 @@ index 3a590d4dc980a2912e9cc043d8c8db4cf9d60803..06ab7c48b18c03af494ab10fc2b584ce
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
@@ -103,11 +104,13 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
@@ -103,12 +104,14 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
|
||||
public boolean suckInItems() {
|
||||
if (HopperBlockEntity.suckInItems(this.level(), this)) {
|
||||
+ this.immunize(); // Paper
|
||||
return true;
|
||||
} else {
|
||||
for (ItemEntity entity : this.level()
|
||||
.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) {
|
||||
if (HopperBlockEntity.addItem(this, entity)) {
|
||||
+ this.immunize(); // Paper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (ItemEntity entity : this.level()
|
||||
.getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) {
|
||||
if (HopperBlockEntity.addItem(this, entity)) {
|
||||
+ this.immunize(); // Paper
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -142,4 +145,11 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper
|
||||
public AbstractContainerMenu createMenu(final int containerId, final Inventory inventory) {
|
||||
return new HopperMenu(containerId, inventory, this);
|
||||
@@ -816,7 +818,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 cc492445307ddc08446484d272866f01646cf7b3..a5d46832d4f8a13b0bf67b523c21d5c3b44209a9 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
|
||||
@@ -833,7 +835,7 @@ index 0958fe0438c3e934b885acf78a0f8003ef8bb694..31c7223d2d01573c24d4ad83737fa2c2
|
||||
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
|
||||
// Paper start - add paper world config
|
||||
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
index ec01093094f1d4de2708791ae6a5545268a021ae..f904c587fafe7395473450f766354d874e36ebac 100644
|
||||
index ef78f286ca14512c3dfccdb8fb06ebe9affa1589..c5c0b01c41055a82e49c1546d4525da0acce13a4 100644
|
||||
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
||||
@@ -159,6 +159,10 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
||||
|
||||
@@ -30,7 +30,7 @@ Additionally, this lets us avoid even allocating new objects for this too, furth
|
||||
reducing memory usage.
|
||||
|
||||
diff --git a/net/minecraft/world/phys/shapes/IndirectMerger.java b/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
index 7e525297aaca8c18cf1669ab80040475029ff652..b342e4c0260fc5a64e5943e6342de0703233a99b 100644
|
||||
index 6c637af546a411d5790ceba9936aa9128d05d97e..e18f24a3941e1102648bac841851a8749f2d9438 100644
|
||||
--- a/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
+++ b/net/minecraft/world/phys/shapes/IndirectMerger.java
|
||||
@@ -10,12 +10,32 @@ public class IndirectMerger implements IndexMerger {
|
||||
@@ -67,7 +67,7 @@ index 7e525297aaca8c18cf1669ab80040475029ff652..b342e4c0260fc5a64e5943e6342de070
|
||||
this.firstIndices = new int[capacity];
|
||||
this.secondIndices = new int[capacity];
|
||||
diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java
|
||||
index de10ce3faa86d6ed6d528575a083722a8feedf8d..7574443bc098c1a0958b64f1f54e76322e48a2e7 100644
|
||||
index ccdaf6043f667b6983e4492cf570947ed5179df1..5c552f618d09fa9456195bbfa643ce4a1a03bd84 100644
|
||||
--- a/net/minecraft/world/phys/shapes/Shapes.java
|
||||
+++ b/net/minecraft/world/phys/shapes/Shapes.java
|
||||
@@ -343,11 +343,26 @@ public final class Shapes {
|
||||
@@ -117,9 +117,9 @@ index de10ce3faa86d6ed6d528575a083722a8feedf8d..7574443bc098c1a0958b64f1f54e7632
|
||||
} else if (second.getDouble(secondSize) < first.getDouble(0) - 1.0E-7) {
|
||||
return new NonOverlappingMerger(second, first, true);
|
||||
} else {
|
||||
- return (IndexMerger)(firstSize == secondSize && Objects.equals(first, second)
|
||||
- return firstSize == secondSize && Objects.equals(first, second)
|
||||
- ? new IdenticalMerger(first)
|
||||
- : new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters));
|
||||
- : new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters);
|
||||
+ return new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters); // Paper - Identical happens more often than Disjoint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] optimize dirt and snow spreading
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/SpreadingSnowyBlock.java b/net/minecraft/world/level/block/SpreadingSnowyBlock.java
|
||||
index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8507c3510 100644
|
||||
index 85666946f8cb23255360bca8efde2ce13abcbc0a..839bfdda7f54e6aabe401db6da1856544b032bf8 100644
|
||||
--- a/net/minecraft/world/level/block/SpreadingSnowyBlock.java
|
||||
+++ b/net/minecraft/world/level/block/SpreadingSnowyBlock.java
|
||||
@@ -27,8 +27,13 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock {
|
||||
@@ -22,8 +22,8 @@ index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8
|
||||
+ BlockState aboveState = chunk.getBlockState(above); // Paper - Perf: optimize dirt and snow spreading
|
||||
if (aboveState.is(Blocks.SNOW) && aboveState.getValue(SnowLayerBlock.LAYERS) == 1) {
|
||||
return true;
|
||||
} else if (aboveState.getFluidState().isFull()) {
|
||||
@@ -40,8 +45,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock {
|
||||
}
|
||||
@@ -42,8 +47,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock {
|
||||
}
|
||||
|
||||
private static boolean canPropagate(final BlockState state, final LevelReader level, final BlockPos pos) {
|
||||
@@ -39,7 +39,7 @@ index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,7 +61,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock {
|
||||
@@ -52,7 +63,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock {
|
||||
Registry<Block> blocks = level.registryAccess().lookupOrThrow(Registries.BLOCK);
|
||||
Optional<Block> baseBlock = blocks.getOptional(this.baseBlock);
|
||||
if (!baseBlock.isEmpty()) {
|
||||
@@ -55,7 +55,7 @@ index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, baseBlock.get().defaultBlockState()).isCancelled()) {
|
||||
return;
|
||||
@@ -63,8 +81,20 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock {
|
||||
@@ -65,8 +83,20 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock {
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BlockPos testPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1);
|
||||
|
||||
+36
-35
@@ -86,7 +86,7 @@ index 0003a548fe4a48ecfe3534f3de309a920568b773..fae764ffd6858c920cafd2fba4444793
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
diff --git a/net/minecraft/network/CompressionDecoder.java b/net/minecraft/network/CompressionDecoder.java
|
||||
index 2f660186f00414b37fa5c01d00c048173feaef13..fe3f0b59561e7b7236aba9cca2a13cee8955a933 100644
|
||||
index 8497561d90bf6165d1e56a044b3b409c234e1ef8..ddd5daf92d03dd343e6164d55fff638509175e6d 100644
|
||||
--- a/net/minecraft/network/CompressionDecoder.java
|
||||
+++ b/net/minecraft/network/CompressionDecoder.java
|
||||
@@ -12,14 +12,22 @@ import java.util.zip.Inflater;
|
||||
@@ -169,7 +169,7 @@ index 2f660186f00414b37fa5c01d00c048173feaef13..fe3f0b59561e7b7236aba9cca2a13cee
|
||||
this.validateDecompressed = validateDecompressed;
|
||||
}
|
||||
diff --git a/net/minecraft/network/CompressionEncoder.java b/net/minecraft/network/CompressionEncoder.java
|
||||
index 319325e741cc314b84844bb49ea569aaf014f319..20b5cfe1ce36d74cd6b2f95566a1bc34fc0aaa7f 100644
|
||||
index 595db570b0ade9cad7de77d2ab7b10d9e68699df..ac095f59d9f17d8239d6493d1c1e3942139b039f 100644
|
||||
--- a/net/minecraft/network/CompressionEncoder.java
|
||||
+++ b/net/minecraft/network/CompressionEncoder.java
|
||||
@@ -6,17 +6,30 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||
@@ -207,33 +207,34 @@ index 319325e741cc314b84844bb49ea569aaf014f319..20b5cfe1ce36d74cd6b2f95566a1bc34
|
||||
int uncompressedLength = uncompressed.readableBytes();
|
||||
if (uncompressedLength > 8388608) {
|
||||
throw new IllegalArgumentException("Packet too big (is " + uncompressedLength + ", should be less than 8388608)");
|
||||
@@ -25,6 +38,7 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
VarInt.write(out, 0);
|
||||
out.writeBytes(uncompressed);
|
||||
} else {
|
||||
+ if (this.deflater != null) { // Paper - Use Velocity cipher
|
||||
byte[] input = new byte[uncompressedLength];
|
||||
uncompressed.readBytes(input);
|
||||
VarInt.write(out, input.length);
|
||||
@@ -37,6 +51,17 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
}
|
||||
|
||||
this.deflater.reset();
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ VarInt.write(out, uncompressedLength);
|
||||
+ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, uncompressed);
|
||||
+ try {
|
||||
+ this.compressor.deflate(compatibleIn, out);
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
@@ -26,6 +39,7 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
VarInt.write(out, 0);
|
||||
out.writeBytes(uncompressed);
|
||||
} else {
|
||||
+ if (this.deflater != null) { // Paper - Use Velocity cipher
|
||||
byte[] input = new byte[uncompressedLength];
|
||||
uncompressed.readBytes(input);
|
||||
VarInt.write(out, input.length);
|
||||
@@ -38,6 +52,18 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
}
|
||||
|
||||
this.deflater.reset();
|
||||
+ // Paper start - Use Velocity cipher
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ VarInt.write(out, uncompressedLength);
|
||||
+ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, uncompressed);
|
||||
+ try {
|
||||
+ this.compressor.deflate(compatibleIn, out);
|
||||
+ } finally {
|
||||
+ compatibleIn.release();
|
||||
+ }
|
||||
+ // Paper end - Use Velocity cipher
|
||||
}
|
||||
}
|
||||
@@ -48,4 +73,31 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
|
||||
@@ -48,4 +74,31 @@ public class CompressionEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
public void setThreshold(final int threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
@@ -266,10 +267,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 d14aea970ce98edfe3dc3692e707334e7e150804..0f06d509125e72ec11d263d0d5c2179d65f6d8dd 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -738,11 +738,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
@@ -730,11 +730,22 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@@ -296,7 +297,7 @@ index 9cd6ec17981da310be1d35054af080d6b33beff8..d7ed1621709c491525daaf7adc8e9f0d
|
||||
|
||||
public boolean isEncrypted() {
|
||||
return this.encrypted;
|
||||
@@ -780,16 +791,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
@@ -772,16 +783,17 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
public void setupCompression(final int threshold, final boolean validateDecompressed) {
|
||||
if (threshold >= 0) {
|
||||
@@ -318,10 +319,10 @@ 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 6d506004583b2415ab356e34e2f8d6ac0e39cca2..474b7f06223514d95bad3d91356dfaa5435b77f5 100644
|
||||
--- a/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -77,6 +77,10 @@ public class ServerConnectionListener {
|
||||
@@ -76,6 +76,10 @@ public class ServerConnectionListener {
|
||||
LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled.");
|
||||
}
|
||||
// Paper end - Warn people with console access that HAProxy is in use.
|
||||
@@ -333,10 +334,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 50e4f4037702875fe7755b169947abd800b06e7b..722c832ce18fd930d9fdb4f718dc13bfc962e5dd 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);
|
||||
@@ -346,6 +347,6 @@ index 8203765d5570644b4c8f6790f361bca2c7066b25..718f00ad9c587a4b0c12f351c10d4621
|
||||
this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING;
|
||||
- this.connection.setEncryptionKey(decryptCipher, encryptCipher);
|
||||
+ this.connection.setEncryptionKey(secretKey); // Paper - Use Velocity cipher
|
||||
} catch (CryptException var7) {
|
||||
throw new IllegalStateException("Protocol error", var7);
|
||||
} catch (CryptException e) {
|
||||
throw new IllegalStateException("Protocol error", e);
|
||||
}
|
||||
+11
-14
@@ -7,7 +7,7 @@ Optimise the stream.anyMatch statement to move to a bitset
|
||||
where we can replace the call with a single bitwise operation.
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/Goal.java b/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
index 5746eefd9e8fa851e74ccf6b5d889a9f8e6fc1e0..81fa892212f586e8cd7938556eeaa9f9dc2654aa 100644
|
||||
index aa5f0e00daf26650b943a24676638581e494a112..60e0d618c603caef5e3516c9fdfc63ff45a7cdff 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/Goal.java
|
||||
@@ -7,7 +7,15 @@ import net.minecraft.world.entity.Entity;
|
||||
@@ -69,7 +69,7 @@ index 5746eefd9e8fa851e74ccf6b5d889a9f8e6fc1e0..81fa892212f586e8cd7938556eeaa9f9
|
||||
// Paper end - Mob Goal API
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index 844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae..75d8953845b2e9acb62b19a859d0e39fd63533eb 100644
|
||||
index b13bdc2852504903fa054c42f89299a5d33dfbd3..1ddf8796d14d472bec48546f25ac4583d483c8e9 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -23,7 +23,8 @@ public class GoalSelector {
|
||||
@@ -119,27 +119,24 @@ index 844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae..75d8953845b2e9acb62b19a859d0e39f
|
||||
goal.stop();
|
||||
}
|
||||
}
|
||||
@@ -95,11 +96,14 @@ public class GoalSelector {
|
||||
@@ -95,8 +96,14 @@ public class GoalSelector {
|
||||
profiler.push("goalUpdate");
|
||||
|
||||
for (WrappedGoal goalx : this.availableGoals) {
|
||||
- if (!goalx.isRunning()
|
||||
- && !goalContainsAnyFlags(goalx, this.disabledFlags)
|
||||
- && goalCanBeReplacedForAllFlags(goalx, this.lockedFlags)
|
||||
- && goalx.canUse()) {
|
||||
- for (Goal.Flag flag : goalx.getFlags()) {
|
||||
for (WrappedGoal goal : this.availableGoals) {
|
||||
- if (!goal.isRunning() && !goalContainsAnyFlags(goal, this.disabledFlags) && goalCanBeReplacedForAllFlags(goal, this.lockedFlags) && goal.canUse()) {
|
||||
- for (Goal.Flag flag : goal.getFlags()) {
|
||||
+ // Paper start
|
||||
+ if (!goalx.isRunning() && !goalContainsAnyFlags(goalx, this.goalTypes) && goalCanBeReplacedForAllFlags(goalx, this.lockedFlags) && goalx.canUse()) {
|
||||
+ long flagIterator = goalx.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = goalx.getFlags().size();
|
||||
+ if (!goal.isRunning() && !goalContainsAnyFlags(goal, this.goalTypes) && goalCanBeReplacedForAllFlags(goal, this.lockedFlags) && goal.canUse()) {
|
||||
+ long flagIterator = goal.getFlags().getBackingSet();
|
||||
+ int wrappedGoalSize = goal.getFlags().size();
|
||||
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
||||
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
|
||||
+ flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
|
||||
+ // Paper end
|
||||
WrappedGoal currentGoal = this.lockedFlags.getOrDefault(flag, NO_GOAL);
|
||||
currentGoal.stop();
|
||||
this.lockedFlags.put(flag, goalx);
|
||||
@@ -131,11 +135,11 @@ public class GoalSelector {
|
||||
this.lockedFlags.put(flag, goal);
|
||||
@@ -128,11 +135,11 @@ public class GoalSelector {
|
||||
}
|
||||
|
||||
public void disableControlFlag(final Goal.Flag flag) {
|
||||
|
||||
@@ -9,7 +9,7 @@ creating too large of a packet to sed.
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 2bfc4cb47fc51345fc733b6ab3b19ace4f8bc171..dad2b89355b05900251955d015451fe195bfdb49 100644
|
||||
index 6ecda939755534ce0f35680be16a04c0a0e0a312..488d5654f5414c9950f19e86a791507366366e01 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -32,6 +32,14 @@ public class ClientboundLevelChunkPacketData {
|
||||
|
||||
@@ -7,7 +7,7 @@ Co-authored-by: Bjarne Koll <git@lynxplay.dev>
|
||||
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
index 135d932a31a557ff06643fb563262423d48cd540..9fb025b05cacc901d72d93c16cf2b7e48d4dd9a6 100644
|
||||
index c16463febcf74e20e8e984bc19e3179a0f5f4ed1..3adfb334068d3722329f91011c41d5e59b1956c9 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
|
||||
@@ -69,7 +69,7 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
@@ -57,7 +57,7 @@ index 135d932a31a557ff06643fb563262423d48cd540..9fb025b05cacc901d72d93c16cf2b7e4
|
||||
@Override
|
||||
@@ -118,24 +132,36 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
|
||||
|
||||
public static enum RunningPolicy {
|
||||
public enum RunningPolicy {
|
||||
RUN_ONE {
|
||||
+ // Paper start - Perf: Remove streams from hot code
|
||||
@Override
|
||||
@@ -98,7 +98,7 @@ index 135d932a31a557ff06643fb563262423d48cd540..9fb025b05cacc901d72d93c16cf2b7e4
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
index 75233df622242db6c23f7a1a5812bf25942bca41..133aab614b102419ec731e901858c0347076bae9 100644
|
||||
index 600633670eb269ab1f4f50865942c46ed4c66fc6..9008b12745628fdcc225415e20e740192185bdd8 100644
|
||||
--- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
+++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
|
||||
@@ -28,7 +28,7 @@ import net.minecraft.util.VisibleForDebug;
|
||||
@@ -133,7 +133,7 @@ index 75233df622242db6c23f7a1a5812bf25942bca41..133aab614b102419ec731e901858c034
|
||||
+ List<GossipContainer.GossipEntry> entries = this.decompress(); // Paper - Perf: Remove streams from hot code
|
||||
if (entries.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
}
|
||||
@@ -176,7 +190,23 @@ public class GossipContainer {
|
||||
private final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
|
||||
|
||||
|
||||
+32
-31
@@ -16,25 +16,24 @@ This lets us get faster foreach iteration, as well as avoids map lookups on
|
||||
the values when needed.
|
||||
|
||||
diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e7308620653774 100644
|
||||
index 53aa6995d18cae5663d392e606c049e2e9138a99..253074a0a14115cd3d18aaae6fa5822cf32346c9 100644
|
||||
--- a/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
+++ b/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
@@ -54,8 +54,12 @@ public class PathFinder {
|
||||
if (from == null) {
|
||||
@@ -55,20 +55,24 @@ public class PathFinder {
|
||||
return null;
|
||||
} else {
|
||||
- Map<Target, BlockPos> tos = targets.stream()
|
||||
- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity()));
|
||||
+ // Paper start - Perf: remove streams and optimize collection
|
||||
+ List<Map.Entry<Target, BlockPos>> tos = Lists.newArrayList();
|
||||
+ for (BlockPos pos : targets) {
|
||||
+ tos.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos));
|
||||
+ }
|
||||
+ // Paper end - Perf: remove streams and optimize collection
|
||||
Path path = this.findPath(from, tos, maxPathLength, reachRange, maxVisitedNodesMultiplier);
|
||||
this.nodeEvaluator.done();
|
||||
return path;
|
||||
@@ -63,12 +67,12 @@ public class PathFinder {
|
||||
}
|
||||
|
||||
- Map<Target, BlockPos> tos = targets.stream()
|
||||
- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity()));
|
||||
+ // Paper start - Perf: remove streams and optimize collection
|
||||
+ List<Map.Entry<Target, BlockPos>> tos = Lists.newArrayList();
|
||||
+ for (BlockPos pos : targets) {
|
||||
+ tos.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos));
|
||||
+ }
|
||||
+ // Paper end - Perf: remove streams and optimize collection
|
||||
Path path = this.findPath(from, tos, maxPathLength, reachRange, maxVisitedNodesMultiplier);
|
||||
this.nodeEvaluator.done();
|
||||
return path;
|
||||
}
|
||||
|
||||
private @Nullable Path findPath(
|
||||
@@ -63,7 +62,7 @@ index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e73086
|
||||
current.closed = true;
|
||||
|
||||
- for (Target target : targets) {
|
||||
+ // Paper start - optimize collection
|
||||
+ // Paper start - Perf: remove streams and optimize collection
|
||||
+ for (int positionIndex = 0, size = targets.size(); positionIndex < size; positionIndex++) {
|
||||
+ final Map.Entry<Target, BlockPos> entry = targets.get(positionIndex);
|
||||
+ Target target = entry.getKey();
|
||||
@@ -75,17 +74,21 @@ index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e73086
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,34 +134,40 @@ public class PathFinder {
|
||||
@@ -126,34 +134,41 @@ public class PathFinder {
|
||||
}
|
||||
}
|
||||
|
||||
- Optional<Path> optPath = !reachedTargets.isEmpty()
|
||||
- ? reachedTargets.stream()
|
||||
- .map(targetx -> this.reconstructPath(targetx.getBestNode(), targetMap.get(targetx), true))
|
||||
- .map(target -> this.reconstructPath(target.getBestNode(), targetMap.get(target), true))
|
||||
- .min(Comparator.comparingInt(Path::getNodeCount))
|
||||
- : targets.stream()
|
||||
- .map(targetx -> this.reconstructPath(targetx.getBestNode(), targetMap.get(targetx), false))
|
||||
- .map(target -> this.reconstructPath(target.getBestNode(), targetMap.get(target), false))
|
||||
- .min(Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount));
|
||||
- profiler.pop();
|
||||
- if (optPath.isEmpty()) {
|
||||
- return null;
|
||||
+ // Paper start - Perf: remove streams and optimize collection
|
||||
+ Path best = null;
|
||||
+ boolean entryListIsEmpty = reachedTargets.isEmpty();
|
||||
+ Comparator<Path> comparator = entryListIsEmpty
|
||||
@@ -96,23 +99,21 @@ index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e73086
|
||||
+ if (best == null || comparator.compare(path, best) < 0) {
|
||||
+ best = path;
|
||||
+ }
|
||||
+ }
|
||||
profiler.pop();
|
||||
- if (optPath.isEmpty()) {
|
||||
- return null;
|
||||
- } else {
|
||||
- Path path = optPath.get();
|
||||
- if (captureDebug) {
|
||||
- path.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), targets);
|
||||
}
|
||||
-
|
||||
- Path path = optPath.get();
|
||||
- if (captureDebug) {
|
||||
- path.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), targets);
|
||||
+ profiler.pop();
|
||||
+ if (captureDebug && best != null) {
|
||||
+ Set<Target> set = Sets.newHashSet();
|
||||
+ for(Map.Entry<Target, BlockPos> entry : targets) {
|
||||
+ set.add(entry.getKey());
|
||||
}
|
||||
-
|
||||
- return path;
|
||||
+ }
|
||||
+ best.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), set);
|
||||
}
|
||||
-
|
||||
- return path;
|
||||
+ return best;
|
||||
+ // Paper end - Perf: remove streams and optimize collection
|
||||
}
|
||||
|
||||
+3
-3
@@ -48,10 +48,10 @@ index cff05f64af7f425b77cbbd7680c5cc592faa798c..0ab4080c8e30d5ee14ce5fcbac64b031
|
||||
serverEntity.getLastSentYRot(),
|
||||
entity.getType(),
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index 23ae1694c3d5fffdb2277316f66c5fd59157f5ca..be28a41084d656c44b611cf3a01ba89de610d5b2 100644
|
||||
index 7f879bc44354c9fac0238208db12b55a948982fb..55cfe38c0daa3ca71a71bf8c7d88fd613fabd82d 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1361,6 +1361,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||
@@ -1357,6 +1357,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||
ChunkMap.this.level.debugSynchronizers().startTrackingEntity(player, this.entity);
|
||||
}
|
||||
// Paper end - entity tracking events
|
||||
@@ -60,7 +60,7 @@ index 23ae1694c3d5fffdb2277316f66c5fd59157f5ca..be28a41084d656c44b611cf3a01ba89d
|
||||
} else {
|
||||
this.removePlayer(player);
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 6774d12d04fa848624fb8bf7a3c2b8bcb88f6e8f..19bb751d3e9c347fe2446412f85c9f28ec8212e6 100644
|
||||
index a62ec41b1319857f0d6cd223d013a92b1e2c2b0d..5fad52157fc22755196ce9eaddaa2bc23c5bb86b 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -89,6 +89,13 @@ public class ServerEntity {
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-21
@@ -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 6d847ff3646b27fe9bc75e792d813a7f611ab3e5..cfc30654917703a9278143a2c36d37eb719ee061 100644
|
||||
index 9fc39230f52f4cf6b44edd34aa9542b9d500538e..965d9f515d0410df3395d07c6cf5e6349c75c923 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) {
|
||||
@@ -2766,6 +2767,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 6d847ff3646b27fe9bc75e792d813a7f611ab3e5..cfc30654917703a9278143a2c36d37eb
|
||||
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 8d1d7582730e05bf605db31e13ee24242592074e..3d20ef3bc4e891e3e6e5f9f6f5efc6c0367369ea 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
|
||||
@@ -2156,6 +2156,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
return this.palettedContainerFactory;
|
||||
}
|
||||
|
||||
@@ -2370,11 +2365,11 @@ index 31c7223d2d01573c24d4ad83737fa2c2752db028..8df070a7135411806d42ea692b566c4d
|
||||
+ }
|
||||
+ // Paper end - optimize redstone (Alternate Current)
|
||||
+
|
||||
public static enum ExplosionInteraction implements StringRepresentable {
|
||||
public enum ExplosionInteraction implements StringRepresentable {
|
||||
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 5bdeaa9ae20de9f42e760d2207219d5f22d95e9b..0e285f38d282b29f625c5578ee1871a6c2b8585d 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()) {
|
||||
|
||||
+8
-16
@@ -8,10 +8,10 @@ This ensures at least a valid version of the chunk exists
|
||||
on disk, even if outdated
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index d628e06a8dbf11b491b323c10a512fde22e72a12..fc712f9dbc893a6dee8ccecc54d0af07659dee62 100644
|
||||
index d39f8ae8f5736a7f4590ca41ac95792a61975baf..4d83986bccc2003b291dd93534da2d2260f6c428 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -25,6 +25,7 @@ import org.slf4j.Logger;
|
||||
@@ -24,6 +24,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -19,7 +19,7 @@ index d628e06a8dbf11b491b323c10a512fde22e72a12..fc712f9dbc893a6dee8ccecc54d0af07
|
||||
private static final int SECTOR_BYTES = 4096;
|
||||
@VisibleForTesting
|
||||
protected static final int SECTOR_INTS = 1024;
|
||||
@@ -453,6 +454,24 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
@@ -451,6 +452,24 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
@@ -45,18 +45,10 @@ index d628e06a8dbf11b491b323c10a512fde22e72a12..fc712f9dbc893a6dee8ccecc54d0af07
|
||||
public void close() throws IOException {
|
||||
ByteBuffer result = ByteBuffer.wrap(this.buf, 0, this.count);
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index aa36e241d49725eb13f00e57d020d4da24add53d..5fa64ff30b8252f139ca7f77c14352c384c8c0e5 100644
|
||||
index 3d0a09662e5ed1f7bc0c02dbe6de529791f2f66f..fedec4d680934730d38d8c5d609fe216938b668a 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -16,6 +16,7 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.io.ChunkSystemRegionFileStorage { // Paper - rewrite chunk system
|
||||
+ private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
|
||||
public static final String ANVIL_EXTENSION = ".mca";
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
@@ -122,11 +123,24 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -123,11 +123,24 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// (and, the regionfile parameter is unused for writing until the write call)
|
||||
final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile)regionFile).moonrise$startWrite(compound, pos);
|
||||
|
||||
@@ -81,7 +73,7 @@ index aa36e241d49725eb13f00e57d020d4da24add53d..5fa64ff30b8252f139ca7f77c14352c3
|
||||
|
||||
return writeData;
|
||||
}
|
||||
@@ -331,9 +345,18 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -325,9 +338,18 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
if (value == null) {
|
||||
region.clear(pos);
|
||||
} else {
|
||||
@@ -96,12 +88,12 @@ index aa36e241d49725eb13f00e57d020d4da24add53d..5fa64ff30b8252f139ca7f77c14352c3
|
||||
+ } catch (final RegionFileSizeException ex) {
|
||||
+ region.clear(pos);
|
||||
+ final int maxSize = RegionFile.MAX_CHUNK_SIZE / (1024 * 1024);
|
||||
+ LOGGER.error("Chunk at (" + pos.x() + "," + pos.z() + ") in regionfile '" + region.getPath().toString() + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk.");
|
||||
+ LOGGER.error("Chunk at ({},{}) in regionfile '{}' exceeds max size of {}MiB, it has been deleted from disk.", pos.x(), pos.z(), region.getPath().toString(), maxSize);
|
||||
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,4 +399,13 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -370,4 +392,13 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
public RegionStorageInfo info() {
|
||||
return this.info;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ index 0cfdbdee091f43ca011bc68f7479eb7b84801b09..8d9ce3d301d5f7e4106587ae00adb8dd
|
||||
scopedCollector.forChild(entity.problemPath()), entity.registryAccess()
|
||||
);
|
||||
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
|
||||
index 2cdbb5f9bace96a8c4ad7fc4de17678ec0db8a6c..6b19f8cd8655cc52a0d8deadb9ca9f24473637a4 100644
|
||||
index a1ee86c18c17e14ebf98f0e72680543addc4c7fa..1ee78f52205cbb0b254a28999f3707ccccbe998e 100644
|
||||
--- a/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/net/minecraft/world/entity/EntityType.java
|
||||
@@ -1647,7 +1647,18 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
|
||||
@@ -1641,7 +1641,18 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T>,
|
||||
}
|
||||
|
||||
public static Stream<Entity> loadEntitiesRecursive(final ValueInput.ValueInputList entities, final Level level, final EntitySpawnReason reason) {
|
||||
@@ -56,10 +56,10 @@ index 2cdbb5f9bace96a8c4ad7fc4de17678ec0db8a6c..6b19f8cd8655cc52a0d8deadb9ca9f24
|
||||
return entity;
|
||||
}));
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/EntityStorage.java b/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
index 04045397dff89870316d0d374b9e472540c3298d..b1cd822c114b99a25fad2e649ca44596109aa0e5 100644
|
||||
index 0326b79fea3f563c3cdfa8f7cf1a3af0e4f08d38..4bd083ecdea207ee5689760fccc9ce8a5a958d57 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java
|
||||
@@ -95,7 +95,18 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
||||
@@ -92,7 +92,18 @@ public class EntityStorage implements EntityPersistentStorage<Entity> {
|
||||
} else {
|
||||
try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(ChunkAccess.problemPath(pos), LOGGER)) {
|
||||
ListTag entities = new ListTag();
|
||||
|
||||
+184
-175
@@ -55,10 +55,10 @@ index a6f9435a8e2a6c8cc05bd3873cb6fc0ec98973b8..d44fd9eea0ccb09c894d6431ede8a4c2
|
||||
this.used.set(position, position + size);
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48ebd220a5f 100644
|
||||
index 4d83986bccc2003b291dd93534da2d2260f6c428..42d07aef0b2f646ec52ed6f4e7c003dbf82bd92d 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -47,6 +47,363 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
@@ -46,6 +46,363 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
@VisibleForTesting
|
||||
protected final RegionBitmap usedSectors = new RegionBitmap();
|
||||
|
||||
@@ -127,11 +127,11 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ private void backupRegionFile(Path to) {
|
||||
+ try {
|
||||
+ this.file.force(true);
|
||||
+ LOGGER.warn("Backing up regionfile \"" + this.path.toAbsolutePath() + "\" to " + to.toAbsolutePath());
|
||||
+ java.nio.file.Files.copy(this.path, to, java.nio.file.StandardCopyOption.COPY_ATTRIBUTES);
|
||||
+ LOGGER.warn("Backed up the regionfile to " + to.toAbsolutePath());
|
||||
+ LOGGER.warn("Backing up regionfile \"{}\" to {}", this.path.toAbsolutePath(), to.toAbsolutePath());
|
||||
+ Files.copy(this.path, to, java.nio.file.StandardCopyOption.COPY_ATTRIBUTES);
|
||||
+ LOGGER.warn("Backed up the regionfile to {}", to.toAbsolutePath());
|
||||
+ } catch (IOException ex) {
|
||||
+ LOGGER.error("Failed to backup to " + to.toAbsolutePath(), ex);
|
||||
+ LOGGER.error("Failed to backup to {}", to.toAbsolutePath(), ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
@@ -152,13 +152,13 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ }
|
||||
+ ChunkPos ourLowerLeftPosition = RegionFileStorage.getRegionFileCoordinates(this.path);
|
||||
+ if (ourLowerLeftPosition == null) {
|
||||
+ LOGGER.error("Unable to get chunk location of regionfile " + this.path.toAbsolutePath() + ", cannot recover header");
|
||||
+ LOGGER.error("Unable to get chunk location of regionfile {}, cannot recover header", this.path.toAbsolutePath());
|
||||
+ return false;
|
||||
+ }
|
||||
+ synchronized (this) {
|
||||
+ this.recalculateCount.getAndIncrement();
|
||||
+
|
||||
+ LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile " + this.path.toAbsolutePath(), new Throwable());
|
||||
+ LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile {}", this.path.toAbsolutePath(), new Throwable());
|
||||
+
|
||||
+ // try to backup file so maybe it could be sent to us for further investigation
|
||||
+
|
||||
@@ -182,7 +182,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+
|
||||
+ ChunkPos chunkPos = SerializableChunkData.getChunkCoordinate(compound);
|
||||
+ if (!inSameRegionfile(ourLowerLeftPosition, chunkPos)) {
|
||||
+ LOGGER.error("Ignoring absolute chunk " + chunkPos + " in regionfile as it is not contained in the bounds of the regionfile '" + this.path.toAbsolutePath() + "'. It should be in regionfile (" + (chunkPos.x() >> 5) + "," + (chunkPos.z() >> 5) + ")");
|
||||
+ LOGGER.error("Ignoring absolute chunk {} in regionfile as it is not contained in the bounds of the regionfile '{}'. It should be in regionfile ({},{})", chunkPos, this.path.toAbsolutePath(), chunkPos.x() >> 5, chunkPos.z() >> 5);
|
||||
+ continue;
|
||||
+ }
|
||||
+ int location = (chunkPos.x() & 31) | ((chunkPos.z() & 31) << 5);
|
||||
@@ -204,7 +204,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ isAikarOversized = true;
|
||||
+ }
|
||||
+ } catch (Exception ex) {
|
||||
+ LOGGER.error("Failed to read aikar oversized data for absolute chunk (" + chunkPos.x() + "," + chunkPos.z() + ") in regionfile " + this.path.toAbsolutePath() + ", oversized data for this chunk will be lost", ex);
|
||||
+ LOGGER.error("Failed to read aikar oversized data for absolute chunk ({},{}) in regionfile {}, oversized data for this chunk will be lost", chunkPos.x(), chunkPos.z(), this.path.toAbsolutePath(), ex);
|
||||
+ // fall through, if we can't read aikar oversized we can't risk corrupting chunk data
|
||||
+ }
|
||||
+ }
|
||||
@@ -253,7 +253,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ try {
|
||||
+ chunkData = Files.readAllBytes(regionFile);
|
||||
+ } catch (Exception ex) {
|
||||
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", data will be lost", ex);
|
||||
+ LOGGER.error("Failed to read oversized chunk data in file {}, data will be lost", regionFile.toAbsolutePath(), ex);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
@@ -273,12 +273,12 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ }
|
||||
+
|
||||
+ if (compound == null) {
|
||||
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", it's corrupt. Its data will be lost");
|
||||
+ LOGGER.error("Failed to read oversized chunk data in file {}, it's corrupt. Its data will be lost", regionFile.toAbsolutePath());
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (!SerializableChunkData.getChunkCoordinate(compound).equals(oversizedCoords)) {
|
||||
+ LOGGER.error("Can't use oversized chunk stored in " + regionFile.toAbsolutePath() + ", got absolute chunkpos: " + SerializableChunkData.getChunkCoordinate(compound) + ", expected " + oversizedCoords);
|
||||
+ LOGGER.error("Can't use oversized chunk stored in {}, got absolute chunkpos: {}, expected {}", regionFile.toAbsolutePath(), net.minecraft.world.level.chunk.storage.SerializableChunkData.getChunkCoordinate(compound), oversizedCoords);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
@@ -312,7 +312,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ if (newSectorAllocations.tryAllocate(sectorOffset, sectorLength)) {
|
||||
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
|
||||
+ } else {
|
||||
+ LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at (" + chunkX + "," + chunkZ + ") in regionfile " + this.path.toAbsolutePath() + ", chunk will be regenerated");
|
||||
+ LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at ({},{}) in regionfile {}, chunk will be regenerated", chunkX, chunkZ, this.path.toAbsolutePath());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
@@ -336,7 +336,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
|
||||
+ } catch (IOException ex) {
|
||||
+ newSectorAllocations.free(sectorOffset, sectorLength);
|
||||
+ LOGGER.error("Failed to write new oversized chunk data holder, local chunk at (" + chunkX + "," + chunkZ + ") in regionfile " + this.path.toAbsolutePath() + " will be regenerated");
|
||||
+ LOGGER.error("Failed to write new oversized chunk data holder, local chunk at ({},{}) in regionfile {} will be regenerated", chunkX, chunkZ, this.path.toAbsolutePath());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
@@ -358,7 +358,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ try {
|
||||
+ this.writeOversizedMeta();
|
||||
+ } catch (Exception ex) {
|
||||
+ LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile " + this.path.toAbsolutePath(), ex);
|
||||
+ LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile {}", this.path.toAbsolutePath(), ex);
|
||||
+ Files.deleteIfExists(this.getOversizedMetaFile());
|
||||
+ }
|
||||
+ } else {
|
||||
@@ -369,7 +369,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+
|
||||
+ // before we overwrite the old sectors, print a summary of the chunks that got changed.
|
||||
+
|
||||
+ LOGGER.info("Starting summary of changes for regionfile " + this.path.toAbsolutePath());
|
||||
+ LOGGER.info("Starting summary of changes for regionfile {}", this.path.toAbsolutePath());
|
||||
+
|
||||
+ for (int chunkX = 0; chunkX < 32; ++chunkX) {
|
||||
+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) {
|
||||
@@ -386,16 +386,16 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+
|
||||
+ if (oldOffset == 0) {
|
||||
+ // found lost data
|
||||
+ LOGGER.info("Found missing data for local chunk (" + chunkX + "," + chunkZ + ") in regionfile " + this.path.toAbsolutePath());
|
||||
+ LOGGER.info("Found missing data for local chunk ({},{}) in regionfile {}", chunkX, chunkZ, this.path.toAbsolutePath());
|
||||
+ } else if (newOffset == 0) {
|
||||
+ LOGGER.warn("Data for local chunk (" + chunkX + "," + chunkZ + ") could not be recovered in regionfile " + this.path.toAbsolutePath() + ", it will be regenerated");
|
||||
+ LOGGER.warn("Data for local chunk ({},{}) could not be recovered in regionfile {}, it will be regenerated", chunkX, chunkZ, this.path.toAbsolutePath());
|
||||
+ } else {
|
||||
+ LOGGER.info("Local chunk (" + chunkX + "," + chunkZ + ") changed to point to newer data or correct chunk in regionfile " + this.path.toAbsolutePath());
|
||||
+ LOGGER.info("Local chunk ({},{}) changed to point to newer data or correct chunk in regionfile {}", chunkX, chunkZ, this.path.toAbsolutePath());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ LOGGER.info("End of change summary for regionfile " + this.path.toAbsolutePath());
|
||||
+ LOGGER.info("End of change summary for regionfile {}", this.path.toAbsolutePath());
|
||||
+
|
||||
+ // simply destroy the timestamp header, it's not used
|
||||
+
|
||||
@@ -407,9 +407,9 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ try {
|
||||
+ this.flush();
|
||||
+ this.file.force(true); // try to ensure it goes through...
|
||||
+ LOGGER.info("Successfully wrote new header to disk for regionfile " + this.path.toAbsolutePath());
|
||||
+ LOGGER.info("Successfully wrote new header to disk for regionfile {}", this.path.toAbsolutePath());
|
||||
+ } catch (IOException ex) {
|
||||
+ LOGGER.error("Failed to write new header to disk for regionfile " + this.path.toAbsolutePath(), ex);
|
||||
+ LOGGER.error("Failed to write new header to disk for regionfile {}", this.path.toAbsolutePath(), ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
@@ -423,75 +423,58 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
@Override
|
||||
public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(final net.minecraft.nbt.CompoundTag data, final ChunkPos pos) throws IOException {
|
||||
@@ -75,6 +432,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath());
|
||||
} else {
|
||||
this.externalFileDir = externalFileDir;
|
||||
+ this.canRecalcHeader = info.dfuType()[0] == net.minecraft.util.datafix.DataFixTypes.CHUNK; // Paper - add can recalc flag
|
||||
this.offsets = this.header.asIntBuffer();
|
||||
this.offsets.limit(1024);
|
||||
this.header.position(4096);
|
||||
}
|
||||
|
||||
this.externalFileDir = externalFileDir;
|
||||
+ this.canRecalcHeader = info.dfuType()[0] == net.minecraft.util.datafix.DataFixTypes.CHUNK; // Paper - add can recalc flag
|
||||
this.offsets = this.header.asIntBuffer();
|
||||
this.offsets.limit(1024);
|
||||
this.header.position(4096);
|
||||
@@ -95,11 +453,13 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
|
||||
long size = Files.size(path);
|
||||
long size = Files.size(path);
|
||||
|
||||
- for (int i = 0; i < 1024; i++) {
|
||||
+ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption
|
||||
+ boolean hasBackedUp = false; // Paper - recalculate header on header corruption
|
||||
+ for (int i = 0; i < 1024; i++) { final int headerLocation = i; // Paper - we expect this to be the header location
|
||||
int offset = this.offsets.get(i);
|
||||
if (offset != 0) {
|
||||
- int sectorNumber = getSectorNumber(offset);
|
||||
- int numSectors = getNumSectors(offset);
|
||||
+ int sectorNumber = getSectorNumber(offset); // Paper - we expect this to be offset in file in sectors
|
||||
+ int numSectors = getNumSectors(offset); // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments
|
||||
// Spigot start
|
||||
if (numSectors == 255) {
|
||||
// We're maxed out, so we need to read the proper length from the section
|
||||
- for (int i = 0; i < 1024; i++) {
|
||||
+ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption
|
||||
+ boolean hasBackedUp = false; // Paper - recalculate header on header corruption
|
||||
+ for (int i = 0; i < 1024; i++) { final int headerLocation = i; // Paper - diff on change, we expect this to be the header location
|
||||
int offset = this.offsets.get(i);
|
||||
if (offset != 0) {
|
||||
- int sectorNumber = getSectorNumber(offset);
|
||||
- int numSectors = getNumSectors(offset);
|
||||
+ int sectorNumber = getSectorNumber(offset); // Paper - diff on change, we expect this to be offset in file in sectors
|
||||
+ int numSectors = getNumSectors(offset); // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments
|
||||
// Spigot start
|
||||
if (numSectors == 255) {
|
||||
// We're maxed out, so we need to read the proper length from the section
|
||||
@@ -110,18 +470,62 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
// Spigot end
|
||||
if (sectorNumber < 2) {
|
||||
LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i, sectorNumber);
|
||||
- this.offsets.put(i, 0);
|
||||
+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (numSectors == 0) {
|
||||
LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, i);
|
||||
- this.offsets.put(i, 0);
|
||||
+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (sectorNumber * 4096L > size) {
|
||||
LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", path, i, sectorNumber);
|
||||
- this.offsets.put(i, 0);
|
||||
+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else {
|
||||
- this.usedSectors.force(sectorNumber, numSectors);
|
||||
+ //this.usedSectors.force(sectorNumber, numSectors); // Paper - move this down so we can check if it fails to allocate
|
||||
+ }
|
||||
+ // Paper start - recalculate header on header corruption
|
||||
+ if (sectorNumber < 2 || numSectors <= 0 || ((long)sectorNumber * 4096L) > size) {
|
||||
+ if (this.canRecalcHeader) {
|
||||
+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + "! Recalculating header...");
|
||||
+ needsHeaderRecalc = true;
|
||||
+ break;
|
||||
+ } else {
|
||||
+ // location = chunkX | (chunkZ << 5);
|
||||
+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() +
|
||||
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
|
||||
+ if (!hasBackedUp) {
|
||||
+ hasBackedUp = true;
|
||||
+ this.backupRegionFile();
|
||||
+ }
|
||||
+ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too
|
||||
+ this.offsets.put(headerLocation, 0); // delete the entry from header
|
||||
+ continue;
|
||||
+ }
|
||||
}
|
||||
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(sectorNumber, numSectors);
|
||||
+ if (failedToAllocate) {
|
||||
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.path.toAbsolutePath());
|
||||
+ }
|
||||
+ if (failedToAllocate & !this.canRecalcHeader) {
|
||||
// Spigot end
|
||||
if (sectorNumber < 2) {
|
||||
LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i, sectorNumber);
|
||||
- this.offsets.put(i, 0);
|
||||
+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (numSectors == 0) {
|
||||
LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, i);
|
||||
- this.offsets.put(i, 0);
|
||||
+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (sectorNumber * 4096L > size) {
|
||||
LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", path, i, sectorNumber);
|
||||
- this.offsets.put(i, 0);
|
||||
+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else {
|
||||
- this.usedSectors.force(sectorNumber, numSectors);
|
||||
+ //this.usedSectors.force(sectorNumber, numSectors); // Paper - move this down so we can check if it fails to allocate
|
||||
+ }
|
||||
+ // Paper start - recalculate header on header corruption
|
||||
+ if (sectorNumber < 2 || numSectors <= 0 || ((long)sectorNumber * 4096L) > size) {
|
||||
+ if (this.canRecalcHeader) {
|
||||
+ LOGGER.error("Detected invalid header for regionfile {}! Recalculating header...", this.path.toAbsolutePath());
|
||||
+ needsHeaderRecalc = true;
|
||||
+ break;
|
||||
+ } else {
|
||||
+ // location = chunkX | (chunkZ << 5);
|
||||
+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() +
|
||||
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
|
||||
+ LOGGER.error("Detected invalid header for regionfile {}! Cannot recalculate, removing local chunk ({},{}) from header",
|
||||
+ this.path.toAbsolutePath(), headerLocation & 31, headerLocation >>> 5);
|
||||
+ if (!hasBackedUp) {
|
||||
+ hasBackedUp = true;
|
||||
+ this.backupRegionFile();
|
||||
@@ -500,21 +483,38 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
+ this.offsets.put(headerLocation, 0); // delete the entry from header
|
||||
+ continue;
|
||||
+ }
|
||||
+ needsHeaderRecalc |= failedToAllocate;
|
||||
+ // Paper end - recalculate header on header corruption
|
||||
+ }
|
||||
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(sectorNumber, numSectors);
|
||||
+ if (failedToAllocate) {
|
||||
+ LOGGER.error("Overlapping allocation by local chunk ({},{}) in regionfile {}", headerLocation & 31, headerLocation >>> 5, this.path.toAbsolutePath());
|
||||
}
|
||||
+ if (failedToAllocate & !this.canRecalcHeader) {
|
||||
+ // location = chunkX | (chunkZ << 5);
|
||||
+ LOGGER.error("Detected invalid header for regionfile {}! Cannot recalculate, removing local chunk ({},{}) from header",
|
||||
+ this.path.toAbsolutePath(), headerLocation & 31, headerLocation >>> 5);
|
||||
+ if (!hasBackedUp) {
|
||||
+ hasBackedUp = true;
|
||||
+ this.backupRegionFile();
|
||||
+ }
|
||||
+ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too
|
||||
+ this.offsets.put(headerLocation, 0); // delete the entry from header
|
||||
+ continue;
|
||||
+ }
|
||||
+ needsHeaderRecalc |= failedToAllocate;
|
||||
+ // Paper end - recalculate header on header corruption
|
||||
}
|
||||
+ // Paper start - recalculate header on header corruption
|
||||
+ // we move the recalc here so comparison to old header is correct when logging to console
|
||||
+ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues
|
||||
+ LOGGER.error("Recalculating regionfile " + this.path.toAbsolutePath() + ", header gave erroneous offsets & locations");
|
||||
+ this.recalculateHeader();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
+ // Paper start - recalculate header on header corruption
|
||||
+ // we move the recalc here so comparison to old header is correct when logging to console
|
||||
+ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues
|
||||
+ LOGGER.error("Recalculating regionfile {}, header gave erroneous offsets & locations", this.path.toAbsolutePath());
|
||||
+ this.recalculateHeader();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
@@ -131,10 +535,34 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
|
||||
@@ -130,10 +534,34 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
|
||||
private Path getExternalChunkPath(final ChunkPos pos) {
|
||||
@@ -550,77 +550,79 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
public synchronized @Nullable DataInputStream getChunkDataInputStream(final ChunkPos pos) throws IOException {
|
||||
int offset = this.getOffset(pos);
|
||||
if (offset == 0) {
|
||||
@@ -155,30 +583,67 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
buffer.flip();
|
||||
if (buffer.remaining() < 5) {
|
||||
LOGGER.error("Chunk {} header is truncated: expected {} but read {}", pos, sectorsLength, buffer.remaining());
|
||||
@@ -155,6 +583,11 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
buffer.flip();
|
||||
if (buffer.remaining() < 5) {
|
||||
LOGGER.error("Chunk {} header is truncated: expected {} but read {}", pos, sectorsLength, buffer.remaining());
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -162,6 +595,11 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
byte versionId = buffer.get();
|
||||
if (length == 0) {
|
||||
LOGGER.warn("Chunk {} is allocated, but stream is missing", pos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -169,18 +607,45 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
if (isExternalStreamChunk(versionId)) {
|
||||
if (streamLength != 0) {
|
||||
LOGGER.warn("Chunk has both internal and external streams");
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
int length = buffer.getInt();
|
||||
byte versionId = buffer.get();
|
||||
if (length == 0) {
|
||||
LOGGER.warn("Chunk {} is allocated, but stream is missing", pos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
int streamLength = length - 1;
|
||||
if (isExternalStreamChunk(versionId)) {
|
||||
if (streamLength != 0) {
|
||||
LOGGER.warn("Chunk has both internal and external streams");
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
}
|
||||
|
||||
- return this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
} else if (streamLength > buffer.remaining()) {
|
||||
LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", pos, streamLength, buffer.remaining());
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else if (streamLength < 0) {
|
||||
LOGGER.error("Declared size {} of chunk {} is negative", length, pos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
JvmProfiler.INSTANCE.onRegionFileRead(this.info, pos, this.version, streamLength);
|
||||
- return this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,9 +823,14 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
|
||||
- return this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
} else if (streamLength > buffer.remaining()) {
|
||||
LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", pos, streamLength, buffer.remaining());
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else if (streamLength < 0) {
|
||||
LOGGER.error("Declared size {} of chunk {} is negative", length, pos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
JvmProfiler.INSTANCE.onRegionFileRead(this.info, pos, this.version, streamLength);
|
||||
- return this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,9 +822,14 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
|
||||
private ByteBuffer createExternalStub() {
|
||||
@@ -637,7 +639,7 @@ index fc712f9dbc893a6dee8ccecc54d0af07659dee62..b4a59b855b45018853e8122a5829a48e
|
||||
return stub;
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 5fa64ff30b8252f139ca7f77c14352c384c8c0e5..eae4963b6d18c5f92871477b93f81c2c79331cd9 100644
|
||||
index fedec4d680934730d38d8c5d609fe216938b668a..e47a91b1869801258d0db20c126722fb06522c80 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -24,6 +24,32 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -739,28 +741,35 @@ index 5fa64ff30b8252f139ca7f77c14352c384c8c0e5..eae4963b6d18c5f92871477b93f81c2c
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.Contract("_, false -> !null") private @Nullable RegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit
|
||||
@@ -313,6 +365,19 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
@@ -307,7 +359,25 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// Paper end
|
||||
|
||||
var4 = NbtIo.read(regionChunkInputStream);
|
||||
try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) {
|
||||
- return regionChunkInputStream == null ? null : NbtIo.read(regionChunkInputStream);
|
||||
+ // Paper start - recover from corrupt regionfile header
|
||||
+ if (regionChunkInputStream == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final CompoundTag serialisedChunkData = NbtIo.read(regionChunkInputStream);
|
||||
+ if (this.isChunkData) {
|
||||
+ ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(var4);
|
||||
+ ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(serialisedChunkData);
|
||||
+ if (!headerChunkPos.equals(pos)) {
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + headerChunkPos + " instead! Attempting regionfile recalculation for regionfile " + region.getPath().toAbsolutePath());
|
||||
+ LOGGER.error("Attempting to read chunk data at {} but got chunk data for {} instead! Attempting regionfile recalculation for regionfile {}", pos, headerChunkPos, region.getPath().toAbsolutePath());
|
||||
+ if (region.recalculateHeader()) {
|
||||
+ return this.read(pos);
|
||||
+ }
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + region.getPath().toAbsolutePath());
|
||||
+ LOGGER.error("Can't recalculate regionfile header, regenerating chunk {} for {}", pos, region.getPath().toAbsolutePath());
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ return serialisedChunkData;
|
||||
+ // Paper end - recover from corrupt regionfile header
|
||||
}
|
||||
}
|
||||
|
||||
return var4;
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
index 97d3da90c270a06d85e70d261658f71d97ae4e3c..11b65c688144e7ef5b7cba603949843a11ccd084 100644
|
||||
index ea229f63f81c5638ded74c28e1e13d8948f2e5e0..d991fccfc3d2cc51611f802a6d40429024e21d9a 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
@@ -21,7 +21,7 @@ import org.slf4j.Logger;
|
||||
@@ -771,7 +780,7 @@ index 97d3da90c270a06d85e70d261658f71d97ae4e3c..11b65c688144e7ef5b7cba603949843a
|
||||
+ public static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>(); // Paper - private -> public
|
||||
private static final Object2ObjectMap<String, RegionFileVersion> VERSIONS_BY_NAME = new Object2ObjectOpenHashMap<>();
|
||||
public static final RegionFileVersion VERSION_GZIP = register(
|
||||
new RegionFileVersion(1, null, in -> new FastBufferedInputStream(new GZIPInputStream(in)), out -> new BufferedOutputStream(new GZIPOutputStream(out)))
|
||||
new RegionFileVersion(1, "gzip", in -> new FastBufferedInputStream(new GZIPInputStream(in)), out -> new BufferedOutputStream(new GZIPOutputStream(out))) // Paper - Enable for Configurable region compression format
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionStorageInfo.java b/net/minecraft/world/level/chunk/storage/RegionStorageInfo.java
|
||||
index 590bd1ca60956e5c5be58481f97401e55f9e1aeb..4e0c9fa1eecfa9f21285b7911e25830bbcbc8d86 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionStorageInfo.java
|
||||
@@ -791,7 +800,7 @@ index 590bd1ca60956e5c5be58481f97401e55f9e1aeb..4e0c9fa1eecfa9f21285b7911e25830b
|
||||
return new RegionStorageInfo(this.level, this.dimension, this.type + suffix);
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
index 22a83f312d357176a5489e5b6b71c3ef3e737df7..74158a5d7ea8058c99ab215265987746aa043fc7 100644
|
||||
index 2d326c3090a5d7621350347e131ee31d4715d3a7..98fb7a282a33f4391de124ed9be9bcf069178516 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
@@ -120,6 +120,18 @@ public record SerializableChunkData(
|
||||
@@ -813,7 +822,7 @@ index 22a83f312d357176a5489e5b6b71c3ef3e737df7..74158a5d7ea8058c99ab215265987746
|
||||
|
||||
// Paper start - Do not let the server load chunks from newer versions
|
||||
private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().dataVersion().version();
|
||||
@@ -544,7 +556,7 @@ public record SerializableChunkData(
|
||||
@@ -542,7 +554,7 @@ public record SerializableChunkData(
|
||||
tag.putInt("xPos", this.chunkPos.x());
|
||||
tag.putInt("yPos", this.minSectionY);
|
||||
tag.putInt("zPos", this.chunkPos.z());
|
||||
@@ -823,7 +832,7 @@ index 22a83f312d357176a5489e5b6b71c3ef3e737df7..74158a5d7ea8058c99ab215265987746
|
||||
tag.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString());
|
||||
tag.storeNullable("blending_data", BlendingData.Packed.CODEC, this.blendingData);
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
|
||||
index 884fa9545a93008fa92863c845aef8f18d88e25a..15da3686bb1b5fddd388a88a7b300aa221c83f58 100644
|
||||
index df4f03f3a346e0ab0074757b3a077b2407135ac3..0b0265c8d4cb70aef758c1b443d007ef8d6c282b 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java
|
||||
@@ -34,6 +34,7 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun
|
||||
|
||||
@@ -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 def29f67aa4d901fd61cb546f65b763b3da09131..a3edf217dd2ffce19dc1111402975ba12bb86bad 100644
|
||||
index 49be7709026cd75cfcb31715550387f0ba954a16..f9da26656b18327e3bcc1537a5f51e84b32cc43a 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -958,7 +958,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -961,7 +961,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 def29f67aa4d901fd61cb546f65b763b3da09131..a3edf217dd2ffce19dc1111402975ba1
|
||||
boolean result = false;
|
||||
|
||||
for (ServerLevel level : this.getAllLevels()) {
|
||||
@@ -970,13 +970,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -973,13 +973,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
result = true;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ index def29f67aa4d901fd61cb546f65b763b3da09131..a3edf217dd2ffce19dc1111402975ba1
|
||||
|
||||
if (flush) {
|
||||
for (ServerLevel level : this.getAllLevels()) {
|
||||
@@ -990,11 +984,25 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -993,10 +987,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -51,14 +51,13 @@ index def29f67aa4d901fd61cb546f65b763b3da09131..a3edf217dd2ffce19dc1111402975ba1
|
||||
+ // Paper end - split out global level data
|
||||
+
|
||||
public boolean saveEverything(final boolean silent, final boolean flush, final boolean force) {
|
||||
boolean var5;
|
||||
try {
|
||||
this.isSaving = true;
|
||||
- this.getPlayerList().saveAll();
|
||||
+ this.getPlayerList().saveAll(); // Paper - Incremental chunk and player saving; diff on change
|
||||
boolean result = this.saveAllChunks(silent, flush, force);
|
||||
this.warnOnLowDiskSpace();
|
||||
var5 = result;
|
||||
return result;
|
||||
@@ -1641,9 +1649,31 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
@@ -94,10 +93,10 @@ index def29f67aa4d901fd61cb546f65b763b3da09131..a3edf217dd2ffce19dc1111402975ba1
|
||||
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 cfc30654917703a9278143a2c36d37eb719ee061..78021db10860396fef4eb2e01926fbad123916fa 100644
|
||||
index 965d9f515d0410df3395d07c6cf5e6349c75c923..49f688e3536fe4fdb052bbfeeec36b5b8666b9b1 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)));
|
||||
}
|
||||
@@ -114,10 +113,10 @@ index cfc30654917703a9278143a2c36d37eb719ee061..78021db10860396fef4eb2e01926fbad
|
||||
public void save(final @Nullable ProgressListener progressListener, final boolean flush, final boolean noSave) {
|
||||
// Paper start - add close param
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 41816ca8d4ef3d959d2b88cd4b2eedaaa541e612..82e87270d1ad89ad7aa56e028ced6b998ea0eca5 100644
|
||||
index f35f88da81abb14b393d6fce04054ee40e8d8397..ec4ad547c2d09f7313390ac6b8a91809baab5f2e 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -205,6 +205,7 @@ import org.slf4j.Logger;
|
||||
@@ -204,6 +204,7 @@ import org.slf4j.Logger;
|
||||
|
||||
public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -126,10 +125,10 @@ 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 eb41400b8948d3eecc6fd89e2fefbe638ccbaad1..3c38b8cadcab6575fca0b7c3cf61287c3793f00f 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -418,6 +418,7 @@ public abstract class PlayerList {
|
||||
@@ -413,6 +413,7 @@ public abstract class PlayerList {
|
||||
|
||||
protected void save(final ServerPlayer player) {
|
||||
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
|
||||
@@ -137,7 +136,7 @@ index 0613b053f4a75c0884280011ee092d9d108b3857..b69bcaa1e27a4fbe9a9568f3c9e18431
|
||||
this.playerIo.save(player);
|
||||
ServerStatsCounter stats = player.getStats(); // CraftBukkit
|
||||
if (stats != null) {
|
||||
@@ -951,10 +952,24 @@ public abstract class PlayerList {
|
||||
@@ -947,10 +948,24 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
|
||||
+9
-9
@@ -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 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54cd6255ff 100644
|
||||
index 2e9b47e87a1dc9f0713420414eda71eb6c03d898..3527559c9520e07646c7fb63fe27ad1b14f28da4 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 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54
|
||||
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 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54
|
||||
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 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1542,7 +1576,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1541,7 +1575,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ index 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54
|
||||
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 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54
|
||||
// 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 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54
|
||||
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
|
||||
@@ -1753,7 +1798,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
private boolean updateAwaitingTeleport() {
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
@@ -117,7 +117,7 @@ index 05a700ffc844b41f4fa129226f78dc6c52520f32..1d93a864c5fc040b5ec7c48b4db0bd54
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(
|
||||
this.awaitingPositionFromClient.x,
|
||||
@@ -1771,6 +1816,34 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1772,6 +1817,34 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ average over the last 5 seconds of keepalive transactions.
|
||||
|
||||
diff --git a/io/papermc/paper/util/KeepAlive.java b/io/papermc/paper/util/KeepAlive.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..4a2520f554c2ee74faf86d7c93baccf0f391a6b3
|
||||
index 0000000000000000000000000000000000000000..66d6af2833d76af28fbeb2ce70c194a559572460
|
||||
--- /dev/null
|
||||
+++ b/io/papermc/paper/util/KeepAlive.java
|
||||
@@ -0,0 +1,67 @@
|
||||
@@ -0,0 +1,84 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+public class KeepAlive {
|
||||
@@ -34,6 +34,14 @@ index 0000000000000000000000000000000000000000..4a2520f554c2ee74faf86d7c93baccf0
|
||||
+ public final PingCalculator pingCalculator1m = new PingCalculator(java.util.concurrent.TimeUnit.MINUTES.toNanos(1L));
|
||||
+ public final PingCalculator pingCalculator5s = new PingCalculator(java.util.concurrent.TimeUnit.SECONDS.toNanos(5L));
|
||||
+
|
||||
+ public KeepAlive copyForListenerHandoff() {
|
||||
+ KeepAlive copy = new KeepAlive();
|
||||
+ copy.lastKeepAliveTx = this.lastKeepAliveTx;
|
||||
+ copy.pingCalculator1m.copyFrom(this.pingCalculator1m);
|
||||
+ copy.pingCalculator5s.copyFrom(this.pingCalculator5s);
|
||||
+ return copy;
|
||||
+ }
|
||||
+
|
||||
+ public static final class PingCalculator {
|
||||
+
|
||||
+ private final long intervalNS;
|
||||
@@ -47,6 +55,15 @@ index 0000000000000000000000000000000000000000..4a2520f554c2ee74faf86d7c93baccf0
|
||||
+ this.intervalNS = intervalNS;
|
||||
+ }
|
||||
+
|
||||
+ private void copyFrom(PingCalculator other) {
|
||||
+ for (KeepAliveResponse response : other.responses) {
|
||||
+ this.responses.add(response);
|
||||
+ }
|
||||
+ this.timeSumNS = other.timeSumNS;
|
||||
+ this.timeSumCount = other.timeSumCount;
|
||||
+ this.lastAverageNS = other.lastAverageNS;
|
||||
+ }
|
||||
+
|
||||
+ public void update(KeepAliveResponse response) {
|
||||
+ long currTime = response.txTimeNS;
|
||||
+
|
||||
@@ -100,7 +117,7 @@ index d87a00ee3cd04ce25dbe46ae6b386b7f0799102c..ace440c2b82a6368aa27a85ff433ba2c
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index f54d99c59bbca7fb5e0615f8fee9c3f6fbffa18a..d9b6f3826e2126d339e926afed782f6d0e890508 100644
|
||||
index f9be3e8cbc05fe74ac7816f8b2d81d52f6f23e40..8b194a59f79eea32c9e7a46227034942f6a6e816 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
|
||||
@@ -121,7 +138,7 @@ index f54d99c59bbca7fb5e0615f8fee9c3f6fbffa18a..d9b6f3826e2126d339e926afed782f6d
|
||||
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;
|
||||
@@ -137,7 +154,7 @@ index f54d99c59bbca7fb5e0615f8fee9c3f6fbffa18a..d9b6f3826e2126d339e926afed782f6d
|
||||
// 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) {
|
||||
@@ -167,25 +184,19 @@ index f54d99c59bbca7fb5e0615f8fee9c3f6fbffa18a..d9b6f3826e2126d339e926afed782f6d
|
||||
+ 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();
|
||||
@@ -194,7 +205,7 @@ index f54d99c59bbca7fb5e0615f8fee9c3f6fbffa18a..d9b6f3826e2126d339e926afed782f6d
|
||||
- final long elapsedTime = now - this.keepAliveTime;
|
||||
- if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // use vanilla's 15000L between keep alive packets
|
||||
- if (this.keepAlivePending) {
|
||||
- if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
|
||||
- if (elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
|
||||
- this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); // Paper - kick event cause
|
||||
- }
|
||||
- // Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
||||
@@ -204,7 +215,7 @@ index f54d99c59bbca7fb5e0615f8fee9c3f6fbffa18a..d9b6f3826e2126d339e926afed782f6d
|
||||
- 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)) {
|
||||
@@ -223,11 +234,21 @@ index f54d99c59bbca7fb5e0615f8fee9c3f6fbffa18a..d9b6f3826e2126d339e926afed782f6d
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,6 +457,6 @@ 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
|
||||
+ return new CommonListenerCookie(this.playerProfile(), this.latency, clientInformation, this.transferred, this.playerBrand, this.pluginMessagerChannels, this.keepAlive); // Paper // Paper
|
||||
+ // Paper start - listener handoff should reset pending keepalive expectations
|
||||
+ return new CommonListenerCookie(
|
||||
+ this.playerProfile(),
|
||||
+ this.latency,
|
||||
+ clientInformation,
|
||||
+ this.transferred,
|
||||
+ this.playerBrand,
|
||||
+ this.pluginMessagerChannels,
|
||||
+ this.keepAlive.copyForListenerHandoff()
|
||||
+ );
|
||||
+ // Paper end - listener handoff should reset pending keepalive expectations
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,11 @@ index 2bc436cdf5180a7943c45fabb9fbbedae6f7db56..f312a7f5b1b2a777ab36b94ce7cbf387
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index a3edf217dd2ffce19dc1111402975ba12bb86bad..2b6717833b56c3e33f3ac656a376dd5c841dc1bc 100644
|
||||
index f9da26656b18327e3bcc1537a5f51e84b32cc43a..e69b540be1e0f0c699a57e07057cee74d4f8a771 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1784,32 +1784,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
return new ServerStatus.Players(maxPlayers, players.size(), sample);
|
||||
}
|
||||
|
||||
+ public final io.papermc.paper.threadedregions.EntityScheduler.EntitySchedulerTickList entitySchedulerTickList = new io.papermc.paper.threadedregions.EntityScheduler.EntitySchedulerTickList(); // Paper - optimise Folia entity scheduler
|
||||
@@ -66,10 +66,10 @@ index a3edf217dd2ffce19dc1111402975ba12bb86bad..2b6717833b56c3e33f3ac656a376dd5c
|
||||
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.ADVENTURE_CLICK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 93d3fb313d538cc1067b1db010458169a1320122..9cd46a8619e575a865f4d00ce71d249c9b028b2f 100644
|
||||
index 5e030ff471248f501d8bca6cfa6cc4161a580d4d..5d4ae462c60723291b1c72dc5b933cd04d31133b 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -5147,6 +5147,11 @@ public abstract class Entity
|
||||
@@ -5148,6 +5148,11 @@ public abstract class Entity
|
||||
this.getBukkitEntity().taskScheduler.retire();
|
||||
}
|
||||
// Paper end - Folia schedulers
|
||||
|
||||
@@ -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 3527559c9520e07646c7fb63fe27ad1b14f28da4..810b352503cdf56091ec6340ad72edde238fe359 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1820,9 +1820,14 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1821,9 +1821,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,7 +62,7 @@ index ae140a514e1e3200f52c5933f886cc9e820b818a..4a1146cc54bd9272466ffc9bb64f600c
|
||||
);
|
||||
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 8df070a7135411806d42ea692b566c4d8389a47b..06451a21c4bfbcd95063f96246013d63f65af8a3 100644
|
||||
index 3d20ef3bc4e891e3e6e5f9f6f5efc6c0367369ea..62c8650462a866dcdb3f06f781c7a8c716b0d912 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
|
||||
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] Optional per player mob spawns
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index be28a41084d656c44b611cf3a01ba89de610d5b2..15d9c2d601a48d2288d5110f9991280129f43087 100644
|
||||
index 55cfe38c0daa3ca71a71bf8c7d88fd613fabd82d..2afc89ab4404cf04ba1da813f1c4a05baa4f44e3 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -238,11 +238,29 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||
@@ -42,10 +42,10 @@ index be28a41084d656c44b611cf3a01ba89de610d5b2..15d9c2d601a48d2288d5110f99912801
|
||||
protected ChunkGenerator generator() {
|
||||
return this.worldGenContext.generator();
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index fcb23814c2539f4e31ed5191e03cc28f4e7f9c2d..0edfb9866ee2d0ff71394bc74f139fe3b4550c42 100644
|
||||
index a5685e0b50610cc8213f34c5db62b475bd54789b..a5023f6f7d912560f3488b1823ee22a1dc639203 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -537,9 +537,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -535,9 +535,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
private void tickChunks(final ProfilerFiller profiler, final long timeDiff) {
|
||||
profiler.push("naturalSpawnCount");
|
||||
int chunkCount = this.distanceManager.getNaturalSpawnChunkCount();
|
||||
@@ -67,7 +67,7 @@ index fcb23814c2539f4e31ed5191e03cc28f4e7f9c2d..0edfb9866ee2d0ff71394bc74f139fe3
|
||||
this.lastSpawnState = spawnCookie;
|
||||
boolean doMobSpawning = this.level.getGameRules().get(GameRules.SPAWN_MOBS) && !this.level.players().isEmpty(); // CraftBukkit
|
||||
int tickSpeed = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED);
|
||||
@@ -567,7 +576,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -565,7 +574,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
profiler.popPush("shuffleSpawningChunks");
|
||||
// Paper start - chunk tick iteration optimisation
|
||||
this.shuffleRandom.setSeed(this.level.getRandom().nextLong());
|
||||
@@ -77,10 +77,10 @@ index fcb23814c2539f4e31ed5191e03cc28f4e7f9c2d..0edfb9866ee2d0ff71394bc74f139fe3
|
||||
profiler.popPush("tickSpawningChunks");
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 82e87270d1ad89ad7aa56e028ced6b998ea0eca5..558abe7248725a58b5aa1a36c7e372824c0fbe2e 100644
|
||||
index c8dd908ea52305d7ae1235ea430a26c88306f183..85d22ea2e0fb7c59c387df056ace9ef556f489a2 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -430,6 +430,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -411,6 +411,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public net.minecraft.network.protocol.game.@Nullable ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
// Paper end - cancellable death event
|
||||
@@ -92,7 +92,7 @@ index 82e87270d1ad89ad7aa56e028ced6b998ea0eca5..558abe7248725a58b5aa1a36c7e37282
|
||||
public @Nullable String lastKnownName; // Better rename detection
|
||||
public String displayName;
|
||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
||||
index 8ab7bdd487de7dbc5ea19d1f361ec52e367f8251..d9c1a04e53bec4a268ab58bfc8025c00bd3fa8ce 100644
|
||||
index c0a986932c25d056877e3147d09dd50d1264b13d..b1ecbc50ea908c6c11e9e1ae2f73d1eed669db08 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -70,6 +70,18 @@ public final class NaturalSpawner {
|
||||
|
||||
+6
-6
@@ -6,7 +6,7 @@ Subject: [PATCH] Improve cancelling PreCreatureSpawnEvent with per player mob
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index 15d9c2d601a48d2288d5110f9991280129f43087..01cbebd70223389c6d952be23e5d739579b96ead 100644
|
||||
index 2afc89ab4404cf04ba1da813f1c4a05baa4f44e3..42ec67c53c35189838ce4767c2be620e05108159 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -257,8 +257,25 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
||||
@@ -37,10 +37,10 @@ index 15d9c2d601a48d2288d5110f9991280129f43087..01cbebd70223389c6d952be23e5d7395
|
||||
// Paper end - Optional per player mob spawns
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0edfb9866ee2d0ff71394bc74f139fe3b4550c42..5a309dcf3c357f6b3a12d74aca2e9592f952318c 100644
|
||||
index a5023f6f7d912560f3488b1823ee22a1dc639203..0609c4e7ac7d027ed01684ab4fec2a7838f1f30f 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -542,7 +542,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -540,7 +540,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
|
||||
// re-set mob counts
|
||||
for (ServerPlayer player : this.level.players()) {
|
||||
@@ -60,10 +60,10 @@ index 0edfb9866ee2d0ff71394bc74f139fe3b4550c42..5a309dcf3c357f6b3a12d74aca2e9592
|
||||
spawnCookie = NaturalSpawner.createState(chunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
} else {
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 558abe7248725a58b5aa1a36c7e372824c0fbe2e..06b938013f9dbee4fb3b86979d5a42f28a0ea33e 100644
|
||||
index 85d22ea2e0fb7c59c387df056ace9ef556f489a2..d354517cbfdcee0648daa8f3eb035b2024d5ce72 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -434,6 +434,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -415,6 +415,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
|
||||
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
|
||||
// Paper end - Optional per player mob spawns
|
||||
@@ -72,7 +72,7 @@ index 558abe7248725a58b5aa1a36c7e372824c0fbe2e..06b938013f9dbee4fb3b86979d5a42f2
|
||||
public @Nullable String lastKnownName; // Better rename detection
|
||||
public String displayName;
|
||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
||||
index d9c1a04e53bec4a268ab58bfc8025c00bd3fa8ce..427573fc142c107d3fcc2be9000316221039ba4c 100644
|
||||
index b1ecbc50ea908c6c11e9e1ae2f73d1eed669db08..9764163a32b0389afa50ba093d0647de04d5119e 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -307,6 +307,11 @@ public final class NaturalSpawner {
|
||||
|
||||
@@ -48,10 +48,10 @@ index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdf
|
||||
+ }
|
||||
+}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 2b6717833b56c3e33f3ac656a376dd5c841dc1bc..2142757965b7345a011a92de08038473fa8ae320 100644
|
||||
index e69b540be1e0f0c699a57e07057cee74d4f8a771..cc35c6271c98615a486422d0490145227626bd85 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1836,6 +1836,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1840,6 +1840,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
|
||||
@@ -60,10 +60,10 @@ index 2b6717833b56c3e33f3ac656a376dd5c841dc1bc..2142757965b7345a011a92de08038473
|
||||
profiler.push("tick");
|
||||
|
||||
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||
index ee0fde839f06b6b900053b792617f3738b8000e8..54d67c847c1de9ee216cedb0527136f50223ea2d 100644
|
||||
index 95e0fb32457f2113de8d3e78fc18398bec83eccf..1d08ac66271a441811a157ed6619b14bf58c403f 100644
|
||||
--- a/net/minecraft/world/item/ItemStack.java
|
||||
+++ b/net/minecraft/world/item/ItemStack.java
|
||||
@@ -807,10 +807,16 @@ public final class ItemStack implements DataComponentHolder, ItemInstance {
|
||||
@@ -807,11 +807,17 @@ public final class ItemStack implements DataComponentHolder, ItemInstance {
|
||||
}
|
||||
|
||||
public ItemStack copy() {
|
||||
@@ -76,17 +76,18 @@ index ee0fde839f06b6b900053b792617f3738b8000e8..54d67c847c1de9ee216cedb0527136f5
|
||||
+ if (!originalItem && this.isEmpty()) {
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
return EMPTY;
|
||||
} else {
|
||||
- ItemStack copy = new ItemStack(this.typeHolder(), this.count, this.components.copy());
|
||||
+ ItemStack copy = new ItemStack(originalItem ? this.item : this.typeHolder(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers
|
||||
copy.setPopTime(this.getPopTime());
|
||||
return copy;
|
||||
}
|
||||
|
||||
- ItemStack copy = new ItemStack(this.typeHolder(), this.count, this.components.copy());
|
||||
+ ItemStack copy = new ItemStack(originalItem ? this.item : this.typeHolder(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers
|
||||
copy.setPopTime(this.getPopTime());
|
||||
return copy;
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 04cfd03f29b319225011b86d459626a6872a5e87..865f08c92946010a36947b7766b957f4c0517285 100644
|
||||
index 0e2b537ff5230e6bdb55e9e99d6b2202479b8fd2..2c9fb60cae8065b1cd70d6ec53122cec9cf7f2a7 100644
|
||||
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -40,6 +40,7 @@ import org.jspecify.annotations.Nullable;
|
||||
@@ -39,6 +39,7 @@ import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public abstract class BlockEntity implements DebugValueSource, TypedInstance<BlockEntityType<?>> {
|
||||
@@ -94,7 +95,7 @@ index 04cfd03f29b319225011b86d459626a6872a5e87..865f08c92946010a36947b7766b957f4
|
||||
// CraftBukkit start - data containers
|
||||
private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||
public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer;
|
||||
@@ -229,6 +230,7 @@ public abstract class BlockEntity implements DebugValueSource, TypedInstance<Blo
|
||||
@@ -214,6 +215,7 @@ public abstract class BlockEntity implements DebugValueSource, TypedInstance<Blo
|
||||
|
||||
public void setChanged() {
|
||||
if (this.level != null) {
|
||||
@@ -103,7 +104,7 @@ index 04cfd03f29b319225011b86d459626a6872a5e87..865f08c92946010a36947b7766b957f4
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b8522610a941 100644
|
||||
index 920eb74888c1692b93eb060f408004f145489d7c..ce6b64e00a0a13ebdceda56d975d79f60c26b86d 100644
|
||||
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -142,6 +142,43 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
@@ -150,27 +151,29 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
private static boolean tryMoveItems(
|
||||
final Level level, final BlockPos pos, final BlockState state, final HopperBlockEntity entity, final BooleanSupplier action
|
||||
) {
|
||||
@@ -150,12 +187,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
} else {
|
||||
if (!entity.isOnCooldown() && state.getValue(HopperBlock.ENABLED)) {
|
||||
boolean changed = false;
|
||||
- if (!entity.isEmpty()) {
|
||||
+ final int fullState = getFullState(entity); // Paper - Perf: Optimize Hoppers
|
||||
+ if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
|
||||
changed = ejectItems(level, pos, entity);
|
||||
}
|
||||
@@ -151,11 +188,12 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
- if (!entity.inventoryFull()) {
|
||||
- changed |= action.getAsBoolean();
|
||||
+ if (changed || fullState != HOPPER_IS_FULL) { // Paper - Perf: Optimize Hoppers
|
||||
+ changed |= action.getAsBoolean(); // Paper - note: this is not a validator, it's what adds/sucks in items
|
||||
}
|
||||
if (!entity.isOnCooldown() && state.getValue(HopperBlock.ENABLED)) {
|
||||
boolean changed = false;
|
||||
- if (!entity.isEmpty()) {
|
||||
+ final int fullState = getFullState(entity); // Paper - Perf: Optimize Hoppers
|
||||
+ if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
|
||||
changed = ejectItems(level, pos, entity);
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
@@ -179,6 +217,206 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
- if (!entity.inventoryFull()) {
|
||||
+ if (changed || fullState != HOPPER_IS_FULL) { // Paper - Perf: Optimize Hoppers
|
||||
changed |= action.getAsBoolean();
|
||||
}
|
||||
|
||||
@@ -179,67 +217,218 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
return true;
|
||||
}
|
||||
|
||||
- private static boolean ejectItems(final Level level, final BlockPos blockPos, final HopperBlockEntity self) {
|
||||
- Container container = getAttachedContainer(level, blockPos, self);
|
||||
- if (container == null) {
|
||||
- return false;
|
||||
+ // Paper start - Perf: Optimize Hoppers
|
||||
+ public static boolean skipHopperEvents;
|
||||
+ private static boolean skipPullModeEventFire;
|
||||
@@ -214,13 +217,16 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
+ }
|
||||
+ origItemStack.setCount(originalItemCount);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
|
||||
+ hopper.setCooldown(level.spigotConfig.hopperTransfer);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
|
||||
- Direction direction = self.facing.getOpposite();
|
||||
- if (isFullContainer(container, direction)) {
|
||||
- return false;
|
||||
+ private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) {
|
||||
+ ItemStack movedItem = origItemStack;
|
||||
+ final int originalItemCount = origItemStack.getCount();
|
||||
@@ -237,8 +243,27 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
+ // site for IMIE did not exhibit the same behavior
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
}
|
||||
|
||||
- for (int slot = 0; slot < self.getContainerSize(); slot++) {
|
||||
- ItemStack itemStack = self.getItem(slot);
|
||||
- if (!itemStack.isEmpty()) {
|
||||
- int originalCount = itemStack.getCount();
|
||||
- // CraftBukkit start - Call event when pushing items into other inventories
|
||||
- ItemStack original = itemStack.copy();
|
||||
- org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
|
||||
- self.removeItem(slot, level.spigotConfig.hopperAmount)
|
||||
- ); // Spigot
|
||||
-
|
||||
- org.bukkit.inventory.Inventory destinationInventory;
|
||||
- // Have to special case large chests as they work oddly
|
||||
- if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
|
||||
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
- } else if (container.getOwner() != null) {
|
||||
- destinationInventory = container.getOwner().getInventory();
|
||||
- } else {
|
||||
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
|
||||
- }
|
||||
+ final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
|
||||
+ final int remainingItemCount = remainingItem.getCount();
|
||||
+ if (remainingItemCount != movedItemCount) {
|
||||
@@ -331,28 +356,49 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
+ blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
|
||||
- org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
|
||||
- self.getOwner().getInventory(),
|
||||
- oitemstack,
|
||||
- destinationInventory,
|
||||
- true
|
||||
- );
|
||||
- if (!event.callEvent()) {
|
||||
- self.setItem(slot, original);
|
||||
- self.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
|
||||
+ private static boolean allMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (container instanceof WorldlyContainer) {
|
||||
+ for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
|
||||
+ if (container instanceof WorldlyContainer worldlyContainer) {
|
||||
+ for (int slot : worldlyContainer.getSlotsForFace(direction)) {
|
||||
+ if (!test.test(container.getItem(slot), slot)) {
|
||||
+ return false;
|
||||
+ }
|
||||
return false;
|
||||
}
|
||||
- int origCount = event.getItem().getAmount(); // Spigot
|
||||
- ItemStack result = HopperBlockEntity.addItem(self, container, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction);
|
||||
- // CraftBukkit end
|
||||
- if (result.isEmpty()) {
|
||||
- container.setChanged();
|
||||
- return true;
|
||||
+ }
|
||||
+ } else {
|
||||
+ int size = container.getContainerSize();
|
||||
+ for (int slot = 0; slot < size; slot++) {
|
||||
+ if (!test.test(container.getItem(slot), slot)) {
|
||||
+ return false;
|
||||
+ }
|
||||
}
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
|
||||
- itemStack.setCount(originalCount);
|
||||
- // Spigot start
|
||||
- itemStack.shrink(origCount - result.getCount());
|
||||
- if (originalCount <= level.spigotConfig.hopperAmount) {
|
||||
- // Spigot end
|
||||
- self.setItem(slot, itemStack);
|
||||
+ private static boolean anyMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
||||
+ if (container instanceof WorldlyContainer) {
|
||||
+ for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
|
||||
+ if (container instanceof WorldlyContainer worldlyContainer) {
|
||||
+ for (int slot : worldlyContainer.getSlotsForFace(direction)) {
|
||||
+ if (test.test(container.getItem(slot), slot)) {
|
||||
+ return true;
|
||||
+ }
|
||||
@@ -362,78 +408,32 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
+ for (int slot = 0; slot < size; slot++) {
|
||||
+ if (test.test(container.getItem(slot), slot)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return true;
|
||||
+ }
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemStack, i) -> itemStack.getCount() >= itemStack.getMaxStackSize();
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemStack, i) -> itemStack.isEmpty();
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
+
|
||||
private static boolean ejectItems(final Level level, final BlockPos blockPos, final HopperBlockEntity self) {
|
||||
Container container = getAttachedContainer(level, blockPos, self);
|
||||
if (container == null) {
|
||||
@@ -188,57 +426,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
if (isFullContainer(container, direction)) {
|
||||
return false;
|
||||
} else {
|
||||
- for (int slot = 0; slot < self.getContainerSize(); slot++) {
|
||||
- ItemStack itemStack = self.getItem(slot);
|
||||
- if (!itemStack.isEmpty()) {
|
||||
- int originalCount = itemStack.getCount();
|
||||
- // CraftBukkit start - Call event when pushing items into other inventories
|
||||
- ItemStack original = itemStack.copy();
|
||||
- org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
|
||||
- self.removeItem(slot, level.spigotConfig.hopperAmount)
|
||||
- ); // Spigot
|
||||
-
|
||||
- org.bukkit.inventory.Inventory destinationInventory;
|
||||
- // Have to special case large chests as they work oddly
|
||||
- if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
|
||||
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
|
||||
- } else if (container.getOwner() != null) {
|
||||
- destinationInventory = container.getOwner().getInventory();
|
||||
- } else {
|
||||
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
|
||||
- }
|
||||
-
|
||||
- org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
|
||||
- self.getOwner().getInventory(),
|
||||
- oitemstack,
|
||||
- destinationInventory,
|
||||
- true
|
||||
- );
|
||||
- if (!event.callEvent()) {
|
||||
- self.setItem(slot, original);
|
||||
- self.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
|
||||
- return false;
|
||||
- }
|
||||
- int origCount = event.getItem().getAmount(); // Spigot
|
||||
- ItemStack result = HopperBlockEntity.addItem(self, container, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction);
|
||||
- // CraftBukkit end
|
||||
-
|
||||
- if (result.isEmpty()) {
|
||||
- container.setChanged();
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
- itemStack.setCount(originalCount);
|
||||
- // Spigot start
|
||||
- itemStack.shrink(origCount - result.getCount());
|
||||
- if (originalCount <= level.spigotConfig.hopperAmount) {
|
||||
- // Spigot end
|
||||
- self.setItem(slot, itemStack);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return false;
|
||||
+ return hopperPush(level, container, direction, self); // Paper - Perf: Optimize Hoppers
|
||||
}
|
||||
}
|
||||
}
|
||||
+ return true;
|
||||
+ }
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemStack, _) -> itemStack.getCount() >= itemStack.getMaxStackSize();
|
||||
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemStack, _) -> itemStack.isEmpty();
|
||||
+ // Paper end - Perf: Optimize Hoppers
|
||||
|
||||
- return false;
|
||||
+ private static boolean ejectItems(final Level level, final BlockPos blockPos, final HopperBlockEntity self) {
|
||||
+ Container container = getAttachedContainer(level, blockPos, self);
|
||||
+ if (container == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ Direction direction = self.facing.getOpposite();
|
||||
+ if (isFullContainer(container, direction)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return hopperPush(level, container, direction, self); // Paper - Perf: Optimize Hoppers
|
||||
}
|
||||
@@ -293,6 +481,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
|
||||
private static int[] getSlots(final Container container, final Direction direction) {
|
||||
@@ -292,6 +481,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
Container container = getSourceContainer(level, hopper, blockPos, blockState);
|
||||
if (container != null) {
|
||||
Direction direction = Direction.DOWN;
|
||||
@@ -441,7 +441,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
|
||||
for (int slot : getSlots(container, direction)) {
|
||||
if (tryTakeInItemFromSlot(hopper, container, slot, direction, level)) { // Spigot
|
||||
@@ -320,54 +509,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
@@ -319,54 +509,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
private static boolean tryTakeInItemFromSlot(final Hopper hopper, final Container container, final int slot, final Direction direction, final Level level) { // Spigot
|
||||
ItemStack itemStack = container.getItem(slot);
|
||||
if (!itemStack.isEmpty() && canTakeItemFromContainer(hopper, container, itemStack, slot, direction)) {
|
||||
@@ -497,7 +497,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -376,13 +518,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
@@ -375,13 +518,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
public static boolean addItem(final Container container, final ItemEntity entity) {
|
||||
boolean changed = false;
|
||||
// CraftBukkit start
|
||||
@@ -514,7 +514,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
ItemStack copy = entity.getItem().copy();
|
||||
ItemStack result = addItem(null, container, copy, null);
|
||||
if (result.isEmpty()) {
|
||||
@@ -441,7 +585,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
@@ -440,7 +585,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
itemStack = itemStack.split(container.getMaxStackSize());
|
||||
}
|
||||
// Spigot end
|
||||
@@ -524,7 +524,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
itemStack = leftover; // Paper - Make hoppers respect inventory max stack size
|
||||
success = true;
|
||||
} else if (canMergeItems(current, itemStack)) {
|
||||
@@ -527,14 +673,22 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
@@ -526,14 +673,22 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
|
||||
public static @Nullable Container getContainerAt(final Level level, final BlockPos pos) {
|
||||
@@ -549,7 +549,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
result = getEntityContainer(level, x, y, z);
|
||||
}
|
||||
|
||||
@@ -558,14 +712,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
@@ -559,14 +714,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||
}
|
||||
|
||||
private static @Nullable Container getEntityContainer(final Level level, final double x, final double y, final double z) {
|
||||
@@ -568,7 +568,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
index 557ef92009f51b54e710f105254eb3e352c6057c..2270b5e5696ef65366c372b9606c5f03b6a11565 100644
|
||||
index 9ded208a6e3b86e24a36791f8bb74cec08cd6e9c..5019356f5f29be895d1b2ea8ee9a0e0f6f237a6a 100644
|
||||
--- a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
|
||||
@@ -52,7 +52,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
|
||||
|
||||
@@ -55,7 +55,7 @@ index cde895c776c3077292c1a8381461075b1fbc45c7..b817e30a23a0030f948ff6c12175767f
|
||||
|
||||
if (buffer.writerIndex() != buffer.capacity()) {
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 488d5654f5414c9950f19e86a791507366366e01..42bfd4b3b626ef66b0f2ef8438add5342b367800 100644
|
||||
index d7a1dde0452632d46fe594afa158cace71698de8..a52f93d0563f713b1d2b707cdb6ab74e4793a54d 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -41,13 +41,23 @@ public class ClientboundLevelChunkPacketData {
|
||||
@@ -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 ac3c00ccb3025cd45beb3c6b96f11dad38f78366..a9a00f9be49344b17b27f64834102df3a323f03b 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;
|
||||
@@ -168,10 +168,10 @@ index 78021db10860396fef4eb2e01926fbad123916fa..3f02da2014ed8e4169f4bb819b4d9e61
|
||||
this.weatherData.setLevel(this);
|
||||
this.typeKey = typeKey;
|
||||
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index f1faa0439bf5bce583e70ce37ade4b7e66daaaa4..f7390b91fe1866c6a11beb93711d0fcde4293164 100644
|
||||
index 837f8de90fddb5f458d44ee42ea11557463454c3..515dfa9c71333f68d6a42535f98977b5681eb407 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -321,6 +321,7 @@ public class ServerPlayerGameMode {
|
||||
@@ -320,6 +320,7 @@ public class ServerPlayerGameMode {
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageAbortEvent(this.player, pos, this.player.getInventory().getSelectedItem()); // CraftBukkit
|
||||
}
|
||||
}
|
||||
@@ -196,10 +196,10 @@ 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 bab8c73be9537a1d531871b1b72bed87d2e0956e..02d19fc610e738f5ed12c23ab92bbdcbabaeced3 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -331,7 +331,7 @@ public abstract class PlayerList {
|
||||
@@ -330,7 +330,7 @@ public abstract class PlayerList {
|
||||
.getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
|
||||
player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
|
||||
new net.minecraft.world.level.chunk.EmptyLevelChunk(level, player.chunkPosition(), plains),
|
||||
@@ -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 5a5f7cbc0217ab7aa034698802f634d149662da1..f4302e835fa9684d0fc7d6b65075ec3ec40f8f9f 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,14 +238,14 @@ index 06451a21c4bfbcd95063f96246013d63f65af8a3..e34e901dce06c6bc6060418593010dcf
|
||||
}
|
||||
|
||||
// Paper start - Cancel hit for vanished players
|
||||
@@ -1084,6 +1087,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
}
|
||||
// CraftBukkit end - capture blockstates
|
||||
BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags);
|
||||
+ this.chunkPacketBlockController.onBlockChange(this, pos, blockState, oldState, updateFlags, updateLimit); // Paper - Anti-Xray
|
||||
if (oldState == null) {
|
||||
// CraftBukkit start - remove blockstate if failed (or the same)
|
||||
if (this.captureBlockStates && captured) {
|
||||
@@ -1088,6 +1091,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
}
|
||||
// CraftBukkit end - capture blockstates
|
||||
BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags);
|
||||
+ this.chunkPacketBlockController.onBlockChange(this, pos, blockState, oldState, updateFlags, updateLimit); // Paper - Anti-Xray
|
||||
if (oldState == null) {
|
||||
// CraftBukkit start - remove blockstate if failed (or the same)
|
||||
if (this.captureBlockStates && captured) {
|
||||
diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
index c974b1c276d29610cb59566afaad19f5bcf0c602..c73b9871faa87493e081cb54e1bf1dce487359c6 100644
|
||||
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
@@ -273,10 +273,10 @@ index c974b1c276d29610cb59566afaad19f5bcf0c602..c73b9871faa87493e081cb54e1bf1dce
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index b5b514b292f9fdbe410aba5facec1638682c9075..595e97d2772b504eb6a08e84e4f4a138eb7c5f37 100644
|
||||
index 536c24ec46bdf571637376728aee06755a6256ef..b381c4d5a8b981f34852d029bbe46374d24f7879 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -152,7 +152,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
@@ -151,7 +151,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
|
||||
final LevelChunk.@Nullable PostLoadProcessor postLoad,
|
||||
final @Nullable BlendingData blendingData
|
||||
) {
|
||||
@@ -286,10 +286,10 @@ index b5b514b292f9fdbe410aba5facec1638682c9075..595e97d2772b504eb6a08e84e4f4a138
|
||||
this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index 398018ad7037669a756f804403fd76cf333a06de..d274149a977ed828b6bd02d88d2850521ede6c60 100644
|
||||
index 0e7bb7db9e46b2cade771fa5e94469023d8b47b0..0f807317cc7fa113ee57ab31f91bb6b8df7c4ae0 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -61,8 +61,14 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
||||
@@ -60,8 +60,14 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
||||
this.recalcBlockCounts();
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ index 398018ad7037669a756f804403fd76cf333a06de..d274149a977ed828b6bd02d88d285052
|
||||
this.biomes = containerFactory.createForBiomes();
|
||||
}
|
||||
|
||||
@@ -284,11 +290,17 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
||||
@@ -283,11 +289,17 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
||||
this.biomes = biomes;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ index 398018ad7037669a756f804403fd76cf333a06de..d274149a977ed828b6bd02d88d285052
|
||||
|
||||
public int getSerializedSize() {
|
||||
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6953bf0b2 100644
|
||||
index 4eeb920e4e71ab91cdb5a41f1eabdd47182c80fb..66a05adab494f8674f0636f8b34533f8ef640028 100644
|
||||
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
@@ -26,6 +26,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
@@ -421,7 +421,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6
|
||||
this.data = this.createOrReuseData(null, 0);
|
||||
this.data.palette.idFor(initialValue, this);
|
||||
@@ -123,15 +169,39 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
}
|
||||
return new PalettedContainer.Data<>(dataConfiguration, storage, palette);
|
||||
}
|
||||
|
||||
+ // Paper start - Anti-Xray
|
||||
@@ -462,7 +462,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6
|
||||
|
||||
public synchronized T getAndSet(final int x, final int y, final int z, final T value) { // Paper - synchronize
|
||||
this.acquire();
|
||||
@@ -203,6 +273,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
@@ -200,6 +270,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
newData.palette.read(buffer, this.strategy.globalMap());
|
||||
buffer.readFixedSizeLongArray(newData.storage.getRaw());
|
||||
this.data = newData;
|
||||
@@ -470,7 +470,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6
|
||||
this.updateData(this.data); // Paper - optimise palette reads
|
||||
} finally {
|
||||
this.release();
|
||||
@@ -210,18 +281,31 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
@@ -207,18 +278,31 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -504,16 +504,16 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6
|
||||
List<T> paletteEntries = discData.paletteEntries();
|
||||
int entryCount = strategy.entryCount();
|
||||
Configuration storedConfiguration = strategy.getConfigurationForPaletteSize(paletteEntries.size());
|
||||
@@ -259,7 +343,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
}
|
||||
@@ -257,7 +341,7 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
}
|
||||
|
||||
- return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette));
|
||||
+ return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette, paletteEntries, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values
|
||||
}
|
||||
|
||||
- return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette));
|
||||
+ return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette, paletteEntries, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values
|
||||
}
|
||||
|
||||
@@ -329,12 +413,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
@Override
|
||||
@@ -323,12 +407,12 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
|
||||
@Override
|
||||
public PalettedContainer<T> copy() {
|
||||
@@ -528,7 +528,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -404,9 +488,16 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
@@ -398,9 +482,16 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
return 1 + this.palette.getSerializedSize(globalMap) + this.storage.getRaw().length * 8;
|
||||
}
|
||||
|
||||
@@ -587,7 +587,7 @@ index 9977331d182cbc592f00006aabce23f0f69d2393..cd20a791b101548367ed53080f78e78b
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/PalettedContainerRO.java b/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
||||
index d2a2d435d0eda14a04f2c8582abffb8f98092a59..1498e9a760878f444debac9d4257d096731bb3ba 100644
|
||||
index 4607d2d7591a35d09d748d1ecf7582947bb86f39..f5f40aa2fd1b478045cb9a28b5ae11bc19f337f0 100644
|
||||
--- a/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
||||
+++ b/net/minecraft/world/level/chunk/PalettedContainerRO.java
|
||||
@@ -14,7 +14,11 @@ public interface PalettedContainerRO<T> {
|
||||
@@ -603,7 +603,7 @@ index d2a2d435d0eda14a04f2c8582abffb8f98092a59..1498e9a760878f444debac9d4257d096
|
||||
int getSerializedSize();
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/Strategy.java b/net/minecraft/world/level/chunk/Strategy.java
|
||||
index 45ff1447312f239154930f748637f413e2ea8f87..a0f8b23612f8315eef2aaf4c036c2ec759aafa66 100644
|
||||
index 5c518b6ec7da546460884c37e9af682b6ab9fc22..958be147cd940ac430576ca5b4ada70fa5d051e3 100644
|
||||
--- a/net/minecraft/world/level/chunk/Strategy.java
|
||||
+++ b/net/minecraft/world/level/chunk/Strategy.java
|
||||
@@ -4,7 +4,7 @@ import net.minecraft.core.IdMap;
|
||||
@@ -616,7 +616,7 @@ index 45ff1447312f239154930f748637f413e2ea8f87..a0f8b23612f8315eef2aaf4c036c2ec7
|
||||
private static final Palette.Factory HASHMAP_PALETTE_FACTORY = HashMapPalette::create;
|
||||
private static final Configuration ZERO_BITS = new Configuration.Simple(SINGLE_VALUE_PALETTE_FACTORY, 0);
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
index df0bb06176ad5cce3ed8785d22d68b2dcbf5a8ca..9823f20186679d75444eff2b7a7b9cf8bb2ef575 100644
|
||||
index 98fb7a282a33f4391de124ed9be9bcf069178516..7d29fdc6548324d97ec34d476b5b48ec0bdba0d2 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
@@ -141,6 +141,7 @@ public record SerializableChunkData(
|
||||
@@ -626,17 +626,17 @@ index df0bb06176ad5cce3ed8785d22d68b2dcbf5a8ca..9823f20186679d75444eff2b7a7b9cf8
|
||||
+ net.minecraft.server.level.ServerLevel serverLevel = (net.minecraft.server.level.ServerLevel) levelHeight; // Paper - Anti-Xray This is is seemingly only called from ChunkMap, where, we have a server level. We'll fight this later if needed.
|
||||
if (chunkData.getString("Status").isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
@@ -201,9 +202,11 @@ public record SerializableChunkData(
|
||||
int y = sectionTag.getByteOr("Y", (byte)0);
|
||||
LevelChunkSection section;
|
||||
if (y >= levelHeight.getMinSectionY() && y <= levelHeight.getMaxSectionY()) {
|
||||
+ final BlockState[] presetBlockStates = serverLevel.chunkPacketBlockController.getPresetBlockStates(serverLevel, chunkPos, y); // Paper - Anti-Xray - Add preset block states
|
||||
+ final Codec<PalettedContainer<BlockState>> antiXrayBlockStateCodec = presetBlockStates == null ? blockStatesCodec : PalettedContainer.codecRW(BlockState.CODEC, containerFactory.blockStatesStrategy(), net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray
|
||||
PalettedContainer<BlockState> blocks = sectionTag.getCompound("block_states")
|
||||
.map(
|
||||
- container -> blockStatesCodec.parse(NbtOps.INSTANCE, container)
|
||||
+ container -> antiXrayBlockStateCodec.parse(NbtOps.INSTANCE, container) // Paper - Anti-Xray
|
||||
.promotePartial(msg -> logErrors(chunkPos, y, msg))
|
||||
.getOrThrow(SerializableChunkData.ChunkReadException::new)
|
||||
)
|
||||
}
|
||||
@@ -202,9 +203,11 @@ public record SerializableChunkData(
|
||||
int y = sectionTag.getByteOr("Y", (byte)0);
|
||||
LevelChunkSection section;
|
||||
if (y >= levelHeight.getMinSectionY() && y <= levelHeight.getMaxSectionY()) {
|
||||
+ final BlockState[] presetBlockStates = serverLevel.chunkPacketBlockController.getPresetBlockStates(serverLevel, chunkPos, y); // Paper - Anti-Xray - Add preset block states
|
||||
+ final Codec<PalettedContainer<BlockState>> antiXrayBlockStateCodec = presetBlockStates == null ? blockStatesCodec : PalettedContainer.codecRW(BlockState.CODEC, containerFactory.blockStatesStrategy(), net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray
|
||||
PalettedContainer<BlockState> blocks = sectionTag.getCompound("block_states")
|
||||
.map(
|
||||
- container -> blockStatesCodec.parse(NbtOps.INSTANCE, container)
|
||||
+ container -> antiXrayBlockStateCodec.parse(NbtOps.INSTANCE, container) // Paper - Anti-Xray
|
||||
.promotePartial(msg -> logErrors(chunkPos, y, msg))
|
||||
.getOrThrow(SerializableChunkData.ChunkReadException::new)
|
||||
)
|
||||
@@ -0,0 +1,119 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 20 Apr 2026 02:56:22 -0700
|
||||
Subject: [PATCH] Delay open/close callbacks for chests
|
||||
|
||||
The logic for chests may invoke block updates, which may not
|
||||
be safe to perform. For example, inventory closing due to
|
||||
player logout (which restricts chunk loading due to being
|
||||
inside an entity status callback) or during shutdown (which has
|
||||
chunk loading restrictions due to the chunk system being halted).
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
|
||||
index b39b8176d6b1a1d3f7058387518bcbb71a3631bb..5ba46020b47edfc886ecd5c33483ebb0fa57e5dc 100644
|
||||
--- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java
|
||||
@@ -61,6 +61,13 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity {
|
||||
private static final Component DEFAULT_NAME = Component.translatable("container.barrel");
|
||||
private NonNullList<ItemStack> items = NonNullList.withSize(27, ItemStack.EMPTY);
|
||||
public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() {
|
||||
+ // Paper start - delay open/close callbacks
|
||||
+ @Override
|
||||
+ public boolean delayCallbacks() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - delay open/close callbacks
|
||||
+
|
||||
@Override
|
||||
protected void onOpen(final Level level, final BlockPos pos, final BlockState state) {
|
||||
BarrelBlockEntity.this.playSound(state, SoundEvents.BARREL_OPEN);
|
||||
diff --git a/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/net/minecraft/world/level/block/entity/ChestBlockEntity.java
|
||||
index 3635bd9e9b6292ff4389984eae1ae89ebca4be51..324f19786c4e298e706184045aea3e8ab98aaf46 100644
|
||||
--- a/net/minecraft/world/level/block/entity/ChestBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/ChestBlockEntity.java
|
||||
@@ -30,6 +30,13 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement
|
||||
public static final Component DEFAULT_NAME = Component.translatable("container.chest");
|
||||
private NonNullList<ItemStack> items = NonNullList.withSize(27, ItemStack.EMPTY);
|
||||
public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() {
|
||||
+ // Paper start - delay open/close callbacks
|
||||
+ @Override
|
||||
+ public boolean delayCallbacks() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - delay open/close callbacks
|
||||
+
|
||||
@Override
|
||||
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 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 {
|
||||
|
||||
protected abstract void openerCountChanged(final Level level, final BlockPos pos, final BlockState blockState, int previous, int current);
|
||||
|
||||
+ // Paper start - delay open/close callbacks
|
||||
+ public boolean delayCallbacks() {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - delay open/close callbacks
|
||||
+
|
||||
public abstract boolean isOwnContainer(final Player player);
|
||||
|
||||
public void incrementOpeners(
|
||||
final LivingEntity entity, final Level level, final BlockPos pos, final BlockState blockState, final double maxInteractionRange
|
||||
) {
|
||||
+ // Paper start - delay open/close callbacks
|
||||
+ if (this.delayCallbacks()) {
|
||||
+ scheduleRecheck(level, pos, blockState, 1);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - delay open/close callbacks
|
||||
int previous = this.openCount++;
|
||||
|
||||
// Paper start - Call BlockRedstoneEvent
|
||||
@@ -66,6 +78,12 @@ public abstract class ContainerOpenersCounter {
|
||||
}
|
||||
|
||||
public void decrementOpeners(final LivingEntity entity, final Level level, final BlockPos pos, final BlockState blockState) {
|
||||
+ // Paper start - delay open/close callbacks
|
||||
+ if (this.delayCallbacks()) {
|
||||
+ scheduleRecheck(level, pos, blockState, 1);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - delay open/close callbacks
|
||||
if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative
|
||||
int previous = this.openCount--;
|
||||
|
||||
@@ -151,6 +169,11 @@ public abstract class ContainerOpenersCounter {
|
||||
}
|
||||
|
||||
private static void scheduleRecheck(final Level level, final BlockPos blockPos, final BlockState blockState) {
|
||||
- level.scheduleTick(blockPos, blockState.getBlock(), 5);
|
||||
+ // Paper start - delay open/close callbacks
|
||||
+ scheduleRecheck(level, blockPos, blockState, 5);
|
||||
+ }
|
||||
+ private static void scheduleRecheck(final Level level, final BlockPos blockPos, final BlockState blockState, final int delay) {
|
||||
+ level.scheduleTick(blockPos, blockState.getBlock(), delay);
|
||||
+ // Paper end - delay open/close callbacks
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java b/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java
|
||||
index 592d253921d8adb168840edcc1b24b64969e80f2..551149b8888d78fc17b153a59532ed08e7f5724b 100644
|
||||
--- a/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java
|
||||
@@ -13,6 +13,13 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
public class EnderChestBlockEntity extends BlockEntity implements LidBlockEntity {
|
||||
private final ChestLidController chestLidController = new ChestLidController();
|
||||
public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() {
|
||||
+ // Paper start - delay open/close callbacks
|
||||
+ @Override
|
||||
+ public boolean delayCallbacks() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end - delay open/close callbacks
|
||||
+
|
||||
@Override
|
||||
protected void onOpen(final Level level, final BlockPos pos, final BlockState blockState) {
|
||||
level.playSound(
|
||||
+139
-134
@@ -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,81 +151,81 @@ index 0000000000000000000000000000000000000000..f47c12e9dd6cfa857ca07a764edc22de
|
||||
+ }
|
||||
+}
|
||||
diff --git a/net/minecraft/recipebook/ServerPlaceRecipe.java b/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
index 6d3e3ec045d5b15a435f7217369968b33e082724..b7a3758af337270737041f84d10eb43784e42279 100644
|
||||
index da0380782a846dbb2657c58668e398f36f191c6e..d5ce83d5abd4de6f014a2827780170d3341eb927 100644
|
||||
--- a/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
+++ b/net/minecraft/recipebook/ServerPlaceRecipe.java
|
||||
@@ -40,6 +40,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<?>> {
|
||||
@@ -42,6 +42,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;
|
||||
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<?>> {
|
||||
}
|
||||
|
||||
while (i2 > 0) {
|
||||
@@ -129,9 +130,11 @@ public class ServerPlaceRecipe<R extends Recipe<?>> {
|
||||
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 (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;
|
||||
@@ -167,7 +170,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 5c083f2ec110c388be951014d8e5a6eb64ded371..cd7714dffcd7e7b6d96d18a97e65fd0914a739d1 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 2a8527a2712de71f4c0d6a2e5af8dd3c01b8ff0a..5982b79f6b391ac9c01c452747fc235faf78369e 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;
|
||||
@@ -234,35 +235,35 @@ index bc4f7d16365dffc87b1eef8aa5791a5cb595ee78..cbb37480c19b210cf83999247c1d670c
|
||||
- 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;
|
||||
@@ -53,7 +53,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> {
|
||||
@@ -75,13 +75,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 653fb104bb51fb738aa3ad22093c24f196f33df2..d4601c6a77f89d89ac9f042ee7b8c25461409523 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) {
|
||||
@@ -81,21 +85,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
|
||||
@@ -120,6 +125,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;
|
||||
@@ -1,16 +1,18 @@
|
||||
--- a/com/mojang/math/OctahedralGroup.java
|
||||
+++ b/com/mojang/math/OctahedralGroup.java
|
||||
@@ -99,6 +_,12 @@
|
||||
@@ -99,6 +_,14 @@
|
||||
.map(f -> Arrays.stream(values()).filter(s -> f.compose(s) == IDENTITY).findAny().get())
|
||||
.toArray(OctahedralGroup[]::new);
|
||||
|
||||
+ // Paper start - Avoid Lazy Initialization for Enum Fields
|
||||
+ static {
|
||||
+ for (OctahedralGroup octahedralGroup : values()) {
|
||||
+ octahedralGroup.initializeRotationDirections(); // Paper - Avoid Lazy Initialization for Enum Fields
|
||||
+ octahedralGroup.initializeRotationDirections();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Avoid Lazy Initialization for Enum Fields
|
||||
+
|
||||
private OctahedralGroup(final String name, final SymmetricGroup3 permutation, final boolean invertX, final boolean invertY, final boolean invertZ) {
|
||||
OctahedralGroup(final String name, final SymmetricGroup3 permutation, final boolean invertX, final boolean invertY, final boolean invertZ) {
|
||||
this.name = name;
|
||||
this.invertX = invertX;
|
||||
@@ -139,7 +_,7 @@
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
@@ -217,7 +_,7 @@
|
||||
@@ -214,7 +_,7 @@
|
||||
}
|
||||
|
||||
public static void preload() {
|
||||
|
||||
+7
-7
@@ -1,11 +1,11 @@
|
||||
--- a/net/minecraft/advancements/criterion/LocationPredicate.java
|
||||
+++ b/net/minecraft/advancements/criterion/LocationPredicate.java
|
||||
@@ -44,7 +_,7 @@
|
||||
public boolean matches(final ServerLevel level, final double x, final double y, final double z) {
|
||||
if (this.position.isPresent() && !this.position.get().matches(x, y, z)) {
|
||||
@@ -46,7 +_,7 @@
|
||||
return false;
|
||||
- } else if (this.dimension.isPresent() && this.dimension.get() != level.dimension()) {
|
||||
+ } else if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? level.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(level))) { // Paper - Add option for strict advancement dimension checks
|
||||
}
|
||||
|
||||
- if (this.dimension.isPresent() && this.dimension.get() != level.dimension()) {
|
||||
+ if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? level.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(level))) { // Paper - Add option for strict advancement dimension checks
|
||||
return false;
|
||||
} else {
|
||||
BlockPos pos = BlockPos.containing(x, y, z);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/commands/Commands.java
|
||||
+++ b/net/minecraft/commands/Commands.java
|
||||
@@ -157,6 +_,7 @@
|
||||
@@ -156,6 +_,7 @@
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class Commands {
|
||||
@@ -8,7 +8,7 @@
|
||||
public static final String COMMAND_PREFIX = "/";
|
||||
private static final ThreadLocal<@Nullable ExecutionContext<CommandSourceStack>> CURRENT_EXECUTION_CONTEXT = new ThreadLocal<>();
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -181,6 +_,7 @@
|
||||
@@ -180,6 +_,7 @@
|
||||
|
||||
@Override
|
||||
public boolean isRestricted(final CommandNode<CommandSourceStack> node) {
|
||||
@@ -16,7 +16,7 @@
|
||||
Predicate<CommandSourceStack> requirement = node.getRequirement();
|
||||
return !requirement.test(this.noPermissionSource);
|
||||
}
|
||||
@@ -188,6 +_,11 @@
|
||||
@@ -187,6 +_,11 @@
|
||||
private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
|
||||
|
||||
public Commands(final Commands.CommandSelection commandSelection, final CommandBuildContext context) {
|
||||
@@ -28,7 +28,7 @@
|
||||
AdvancementCommands.register(this.dispatcher);
|
||||
AttributeCommand.register(this.dispatcher, context);
|
||||
ExecuteCommand.register(this.dispatcher, context);
|
||||
@@ -299,6 +_,42 @@
|
||||
@@ -298,6 +_,42 @@
|
||||
PublishCommand.register(this.dispatcher);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer());
|
||||
}
|
||||
|
||||
@@ -318,6 +_,13 @@
|
||||
@@ -317,6 +_,13 @@
|
||||
}
|
||||
|
||||
public void performCommand(final ParseResults<CommandSourceStack> command, final String commandString) {
|
||||
@@ -85,36 +85,36 @@
|
||||
CommandSourceStack sender = command.getContext().getSource();
|
||||
Profiler.get().push(() -> "/" + commandString);
|
||||
ContextChain<CommandSourceStack> commandChain = finishParsing(command, commandString, sender);
|
||||
@@ -331,10 +_,12 @@
|
||||
@@ -330,10 +_,12 @@
|
||||
)
|
||||
);
|
||||
}
|
||||
- } catch (Exception var12) {
|
||||
- } catch (Exception e) {
|
||||
+ // Paper start
|
||||
+ } catch (Throwable var12) { // always gracefully handle it, no matter how bad:tm:
|
||||
+ if (throwCommandError) throw var12; // rethrow directly if requested
|
||||
MutableComponent hover = Component.literal(var12.getMessage() == null ? var12.getClass().getName() : var12.getMessage());
|
||||
+ } catch (Throwable e) { // always gracefully handle it, no matter how bad:tm:
|
||||
+ if (throwCommandError) throw e; // rethrow directly if requested
|
||||
MutableComponent hover = Component.literal(e.getMessage() == null ? e.getClass().getName() : e.getMessage());
|
||||
- if (LOGGER.isDebugEnabled()) {
|
||||
- LOGGER.error("Command exception: /{}", commandString, var12);
|
||||
+ LOGGER.error("Command exception: /{}", commandString, var12); // Paper - always show execution exception in console log
|
||||
- LOGGER.error("Command exception: /{}", commandString, e);
|
||||
+ LOGGER.error("Command exception: /{}", commandString, e); // Paper - always show execution exception in console log
|
||||
+ if (sender.getServer().isDebugging() || LOGGER.isDebugEnabled()) { // Paper - Debugging
|
||||
StackTraceElement[] stackTrace = var12.getStackTrace();
|
||||
StackTraceElement[] stackTrace = e.getStackTrace();
|
||||
|
||||
for (int i = 0; i < Math.min(stackTrace.length, 3); i++) {
|
||||
@@ -365,7 +_,11 @@
|
||||
@@ -364,7 +_,11 @@
|
||||
return ContextChain.tryFlatten(command.getContext().build(commandString))
|
||||
.orElseThrow(() -> CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(command.getReader()));
|
||||
} catch (CommandSyntaxException var7) {
|
||||
- sender.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage()));
|
||||
} catch (CommandSyntaxException e) {
|
||||
- sender.sendFailure(ComponentUtils.fromMessage(e.getRawMessage()));
|
||||
+ // Paper start - Add UnknownCommandEvent
|
||||
+ final net.kyori.adventure.text.TextComponent.Builder builder = net.kyori.adventure.text.Component.text();
|
||||
+ // sender.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage()));
|
||||
+ builder.color(net.kyori.adventure.text.format.NamedTextColor.RED).append(io.papermc.paper.command.brigadier.MessageComponentSerializer.message().deserialize(var7.getRawMessage()));
|
||||
+ builder.color(net.kyori.adventure.text.format.NamedTextColor.RED).append(io.papermc.paper.command.brigadier.MessageComponentSerializer.message().deserialize(e.getRawMessage()));
|
||||
+ // Paper end - Add UnknownCommandEvent
|
||||
if (var7.getInput() != null && var7.getCursor() >= 0) {
|
||||
int cursor = Math.min(var7.getInput().length(), var7.getCursor());
|
||||
if (e.getInput() != null && e.getCursor() >= 0) {
|
||||
int cursor = Math.min(e.getInput().length(), e.getCursor());
|
||||
MutableComponent context = Component.empty()
|
||||
@@ -382,7 +_,17 @@
|
||||
@@ -381,7 +_,17 @@
|
||||
}
|
||||
|
||||
context.append(Component.translatable("command.context.here").withStyle(ChatFormatting.RED, ChatFormatting.ITALIC));
|
||||
@@ -133,7 +133,7 @@
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -410,19 +_,112 @@
|
||||
@@ -409,19 +_,112 @@
|
||||
}
|
||||
|
||||
public void sendCommands(final ServerPlayer player) {
|
||||
@@ -249,7 +249,7 @@
|
||||
if (builder.getRedirect() != null) {
|
||||
builder.redirect(converted.get(builder.getRedirect()));
|
||||
}
|
||||
@@ -431,7 +_,7 @@
|
||||
@@ -430,7 +_,7 @@
|
||||
converted.put(child, node);
|
||||
target.addChild(node);
|
||||
if (!child.getChildren().isEmpty()) {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/commands/arguments/EntityArgument.java
|
||||
+++ b/net/minecraft/commands/arguments/EntityArgument.java
|
||||
@@ -107,9 +_,14 @@
|
||||
@@ -106,9 +_,14 @@
|
||||
}
|
||||
|
||||
private EntitySelector parse(final StringReader reader, final boolean allowSelectors) throws CommandSyntaxException {
|
||||
@@ -16,7 +16,7 @@
|
||||
if (selector.getMaxResults() > 1 && this.single) {
|
||||
if (this.playersOnly) {
|
||||
reader.setCursor(0);
|
||||
@@ -131,7 +_,13 @@
|
||||
@@ -130,7 +_,13 @@
|
||||
if (contextBuilder.getSource() instanceof SharedSuggestionProvider source) {
|
||||
StringReader reader = new StringReader(builder.getInput());
|
||||
reader.setCursor(builder.getStart());
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
+ private final int adjZ;
|
||||
+ // Paper end - Perf: Inline shift direction fields
|
||||
+
|
||||
private Direction(
|
||||
Direction(
|
||||
final int data3d,
|
||||
final int oppositeIndex,
|
||||
@@ -81,6 +_,11 @@
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
--- a/net/minecraft/core/HolderLookup.java
|
||||
+++ b/net/minecraft/core/HolderLookup.java
|
||||
@@ -69,6 +_,9 @@
|
||||
@@ -68,6 +_,8 @@
|
||||
}
|
||||
|
||||
public interface RegistryLookup<T> extends HolderLookup<T>, HolderOwner<T> {
|
||||
+
|
||||
interface RegistryLookup<T> extends HolderLookup<T>, HolderOwner<T> {
|
||||
+ Optional<T> getValueForCopying(ResourceKey<T> resourceKey); // Paper - add method to get the value for pre-filling builders in the reg mod API
|
||||
+
|
||||
ResourceKey<? extends Registry<? extends T>> key();
|
||||
|
||||
Lifecycle registryLifecycle();
|
||||
@@ -83,6 +_,13 @@
|
||||
Objects.requireNonNull(RegistryLookup.this);
|
||||
}
|
||||
@@ -78,6 +_,13 @@
|
||||
|
||||
default HolderLookup.RegistryLookup<T> filterElements(final Predicate<T> filter) {
|
||||
return new HolderLookup.RegistryLookup.Delegate<T>() {
|
||||
+ // Paper start - add getValueForCopying
|
||||
+ @Override
|
||||
+ public Optional<T> getValueForCopying(final ResourceKey<T> resourceKey) {
|
||||
@@ -24,9 +23,9 @@
|
||||
@Override
|
||||
public HolderLookup.RegistryLookup<T> parent() {
|
||||
return RegistryLookup.this;
|
||||
@@ -102,6 +_,13 @@
|
||||
@@ -97,6 +_,13 @@
|
||||
|
||||
public interface Delegate<T> extends HolderLookup.RegistryLookup<T> {
|
||||
interface Delegate<T> extends HolderLookup.RegistryLookup<T> {
|
||||
HolderLookup.RegistryLookup<T> parent();
|
||||
+
|
||||
+ // Paper start - add getValueForCopying
|
||||
|
||||
@@ -31,23 +31,23 @@
|
||||
|
||||
@Override
|
||||
public Stream<HolderSet.Named<T>> listTags() {
|
||||
@@ -114,6 +_,7 @@
|
||||
this.toId.put(value, newId);
|
||||
this.registrationInfos.put(key, registrationInfo);
|
||||
this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle());
|
||||
+ this.temporaryUnfrozenMap.put(key.identifier(), value); // Paper - support pre-filling in registry mod API
|
||||
return holder;
|
||||
}
|
||||
@@ -117,6 +_,7 @@
|
||||
this.toId.put(value, newId);
|
||||
this.registrationInfos.put(key, registrationInfo);
|
||||
this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle());
|
||||
+ this.temporaryUnfrozenMap.put(key.identifier(), value); // Paper - support pre-filling in registry mod API
|
||||
return holder;
|
||||
}
|
||||
@@ -275,6 +_,7 @@
|
||||
return this;
|
||||
} else {
|
||||
this.frozen = true;
|
||||
+ this.temporaryUnfrozenMap.clear(); // Paper - support pre-filling in registry mod API
|
||||
this.byValue.forEach((value, holder) -> holder.bindValue((T)value));
|
||||
List<Identifier> unboundEntries = this.byKey
|
||||
.entrySet()
|
||||
@@ -522,4 +_,13 @@
|
||||
|
||||
@@ -278,6 +_,7 @@
|
||||
}
|
||||
|
||||
this.frozen = true;
|
||||
+ this.temporaryUnfrozenMap.clear(); // Paper - support pre-filling in registry mod API
|
||||
this.byValue.forEach((value, holder) -> holder.bindValue((T)value));
|
||||
List<Identifier> unboundEntries = this.byKey
|
||||
.entrySet()
|
||||
@@ -512,4 +_,13 @@
|
||||
|
||||
Stream<HolderSet.Named<T>> getTags();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/core/RegistrySetBuilder.java
|
||||
+++ b/net/minecraft/core/RegistrySetBuilder.java
|
||||
@@ -42,6 +_,13 @@
|
||||
@@ -41,6 +_,13 @@
|
||||
final Map<ResourceKey<T>, Holder.Reference<T>> entries
|
||||
) {
|
||||
return new RegistrySetBuilder.EmptyTagRegistryLookup<T>(owner) {
|
||||
@@ -14,7 +14,7 @@
|
||||
@Override
|
||||
public ResourceKey<? extends Registry<? extends T>> key() {
|
||||
return key;
|
||||
@@ -128,6 +_,13 @@
|
||||
@@ -123,6 +_,13 @@
|
||||
public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(final ResourceKey<? extends Registry<? extends T>> registryKey) {
|
||||
return getEntry(registryKey).map(Entry::opsInfo);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/core/Rotations.java
|
||||
+++ b/net/minecraft/core/Rotations.java
|
||||
@@ -26,11 +_,22 @@
|
||||
@@ -26,10 +_,21 @@
|
||||
output.writeFloat(value.z);
|
||||
}
|
||||
};
|
||||
@@ -12,14 +12,13 @@
|
||||
+ SKIP_VALIDATION = false;
|
||||
+ return rotations;
|
||||
+ }
|
||||
+ // Paper end - add internal method for skipping validation for plugins using userdev
|
||||
+ // Paper end - add internal method for skipping validation for plugins using userdev
|
||||
|
||||
public Rotations(float x, float y, float z) {
|
||||
public Rotations {
|
||||
+ if (!SKIP_VALIDATION) { // Paper - add internal method for skipping validation for plugins using userdev
|
||||
x = !Float.isInfinite(x) && !Float.isNaN(x) ? x % 360.0F : 0.0F;
|
||||
y = !Float.isInfinite(y) && !Float.isNaN(y) ? y % 360.0F : 0.0F;
|
||||
z = !Float.isInfinite(z) && !Float.isNaN(z) ? z % 360.0F : 0.0F;
|
||||
+ } // Paper - add internal method for skipping validation for plugins using userdev
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,5 +10,5 @@
|
||||
- InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack itemInHand);
|
||||
+ InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack itemInHand, net.minecraft.core.Direction hitDirection); // Paper - add hitDirection
|
||||
|
||||
public static class Dispatcher {
|
||||
class Dispatcher {
|
||||
private final Map<TagKey<Item>, CauldronInteraction> tags = new HashMap<>();
|
||||
+98
-95
@@ -32,7 +32,7 @@
|
||||
state,
|
||||
level,
|
||||
pos,
|
||||
@@ -76,33 +_,43 @@
|
||||
@@ -76,23 +_,28 @@
|
||||
itemInHand,
|
||||
new ItemStack(Items.WATER_BUCKET),
|
||||
s -> s.getValue(LayeredCauldronBlock.LEVEL) == 3,
|
||||
@@ -64,23 +64,24 @@
|
||||
+ WATER.put(Items.POTION, (state, level, pos, player, hand, itemInHand, hitDirection) -> { // Paper - add hitDirection
|
||||
if (state.getValue(LayeredCauldronBlock.LEVEL) == 3) {
|
||||
return InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||
} else {
|
||||
PotionContents potion = itemInHand.get(DataComponents.POTION_CONTENTS);
|
||||
if (potion != null && potion.is(Potions.WATER)) {
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, state.cycle(LayeredCauldronBlock.LEVEL), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { // Paper - Call CauldronLevelChangeEvent
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.GLASS_BOTTLE)));
|
||||
player.awardStat(Stats.USE_CAULDRON);
|
||||
player.awardStat(Stats.ITEM_USED.get(itemInHand.getItem()));
|
||||
- level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL));
|
||||
+ // level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit
|
||||
level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
level.gameEvent(null, GameEvent.FLUID_PLACE, pos);
|
||||
}
|
||||
}
|
||||
@@ -100,10 +_,15 @@
|
||||
PotionContents potion = itemInHand.get(DataComponents.POTION_CONTENTS);
|
||||
if (potion != null && potion.is(Potions.WATER)) {
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, state.cycle(LayeredCauldronBlock.LEVEL), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { // Paper - Call CauldronLevelChangeEvent
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.GLASS_BOTTLE)));
|
||||
player.awardStat(Stats.USE_CAULDRON);
|
||||
player.awardStat(Stats.ITEM_USED.get(itemInHand.getItem()));
|
||||
- level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL));
|
||||
+ // level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit
|
||||
level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
level.gameEvent(null, GameEvent.FLUID_PLACE, pos);
|
||||
}
|
||||
@@ -148,14 +_,14 @@
|
||||
WATER.put(Items.YELLOW_SHULKER_BOX, CauldronInteractions::shulkerBoxInteraction);
|
||||
LAVA.put(
|
||||
@@ -108,7 +109,7 @@
|
||||
)
|
||||
);
|
||||
addDefaultInteractions(POWDER_SNOW);
|
||||
@@ -187,15 +_,46 @@
|
||||
@@ -187,16 +_,47 @@
|
||||
final Predicate<BlockState> canFill,
|
||||
final SoundEvent soundEvent
|
||||
) {
|
||||
@@ -131,31 +132,32 @@
|
||||
+ // Paper end - add hitDirection
|
||||
if (!canFill.test(state)) {
|
||||
return InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||
} else {
|
||||
if (!level.isClientSide()) {
|
||||
+ // Paper start - fire PlayerBucketFillEvent
|
||||
+ if (hitDirection != null) {
|
||||
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitDirection, itemInHand, newItem.getItem(), hand);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ newItem = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
if (!level.isClientSide()) {
|
||||
+ // Paper start - fire PlayerBucketFillEvent
|
||||
+ if (hitDirection != null) {
|
||||
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitDirection, itemInHand, newItem.getItem(), hand);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // Paper end - fire PlayerBucketFillEvent
|
||||
+ // CraftBukkit start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, Blocks.CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) { // Paper - Call CauldronLevelChangeEvent
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
Item itemUsed = itemInHand.getItem();
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, newItem));
|
||||
player.awardStat(Stats.USE_CAULDRON);
|
||||
player.awardStat(Stats.ITEM_USED.get(itemUsed));
|
||||
- level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState());
|
||||
+ // level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit
|
||||
level.playSound(null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
level.gameEvent(null, GameEvent.FLUID_PICKUP, pos);
|
||||
}
|
||||
+ newItem = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY;
|
||||
+ }
|
||||
+ // Paper end - fire PlayerBucketFillEvent
|
||||
+ // CraftBukkit start
|
||||
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, Blocks.CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) { // Paper - Call CauldronLevelChangeEvent
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
Item itemUsed = itemInHand.getItem();
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, newItem));
|
||||
player.awardStat(Stats.USE_CAULDRON);
|
||||
player.awardStat(Stats.ITEM_USED.get(itemUsed));
|
||||
- level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState());
|
||||
+ // level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit
|
||||
level.playSound(null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
level.gameEvent(null, GameEvent.FLUID_PICKUP, pos);
|
||||
}
|
||||
@@ -213,12 +_,42 @@
|
||||
final BlockState newState,
|
||||
final SoundEvent soundEvent
|
||||
@@ -218,25 +220,25 @@
|
||||
- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand
|
||||
+ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection
|
||||
) {
|
||||
return (InteractionResult)(isUnderWater(level, pos)
|
||||
return isUnderWater(level, pos)
|
||||
? InteractionResult.CONSUME
|
||||
- : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA));
|
||||
+ : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA, hitDirection)); // Paper - add hitDirection
|
||||
- : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA);
|
||||
+ : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA, hitDirection); // Paper - add hitDirection
|
||||
}
|
||||
|
||||
private static InteractionResult fillPowderSnowInteraction(
|
||||
- final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand
|
||||
+ final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection
|
||||
) {
|
||||
return (InteractionResult)(isUnderWater(level, pos)
|
||||
return isUnderWater(level, pos)
|
||||
? InteractionResult.CONSUME
|
||||
@@ -254,22 +_,27 @@
|
||||
@@ -254,12 +_,12 @@
|
||||
hand,
|
||||
itemInHand,
|
||||
Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3),
|
||||
- SoundEvents.BUCKET_EMPTY_POWDER_SNOW
|
||||
+ SoundEvents.BUCKET_EMPTY_POWDER_SNOW, hitDirection // Paper - add hitDirection
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
private static InteractionResult shulkerBoxInteraction(
|
||||
@@ -245,23 +247,23 @@
|
||||
) {
|
||||
Block block = Block.byItem(itemInHand.getItem());
|
||||
if (!(block instanceof ShulkerBoxBlock)) {
|
||||
return InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||
} else {
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) {
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
ItemStack cleanedShulkerBox = itemInHand.transmuteCopy(Blocks.SHULKER_BOX, 1);
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedShulkerBox, false));
|
||||
player.awardStat(Stats.CLEAN_SHULKER_BOX);
|
||||
- LayeredCauldronBlock.lowerFillLevel(state, level, pos);
|
||||
+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit
|
||||
}
|
||||
@@ -267,17 +_,22 @@
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
@@ -277,18 +_,23 @@
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) {
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
ItemStack cleanedShulkerBox = itemInHand.transmuteCopy(Blocks.SHULKER_BOX, 1);
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedShulkerBox, false));
|
||||
player.awardStat(Stats.CLEAN_SHULKER_BOX);
|
||||
- LayeredCauldronBlock.lowerFillLevel(state, level, pos);
|
||||
+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
private static InteractionResult bannerInteraction(
|
||||
@@ -270,24 +272,24 @@
|
||||
) {
|
||||
BannerPatternLayers patterns = itemInHand.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY);
|
||||
if (patterns.layers().isEmpty()) {
|
||||
return InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||
} else {
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) {
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
ItemStack cleanedBanner = itemInHand.copyWithCount(1);
|
||||
cleanedBanner.set(DataComponents.BANNER_PATTERNS, patterns.removeLast());
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedBanner, false));
|
||||
player.awardStat(Stats.CLEAN_BANNER);
|
||||
- LayeredCauldronBlock.lowerFillLevel(state, level, pos);
|
||||
+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit
|
||||
}
|
||||
@@ -285,27 +_,37 @@
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
@@ -296,15 +_,20 @@
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) {
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
ItemStack cleanedBanner = itemInHand.copyWithCount(1);
|
||||
cleanedBanner.set(DataComponents.BANNER_PATTERNS, patterns.removeLast());
|
||||
player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedBanner, false));
|
||||
player.awardStat(Stats.CLEAN_BANNER);
|
||||
- LayeredCauldronBlock.lowerFillLevel(state, level, pos);
|
||||
+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
private static InteractionResult dyedItemIteration(
|
||||
@@ -296,17 +298,18 @@
|
||||
) {
|
||||
if (!itemInHand.has(DataComponents.DYED_COLOR)) {
|
||||
return InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||
} else {
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) {
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
itemInHand.remove(DataComponents.DYED_COLOR);
|
||||
player.awardStat(Stats.CLEAN_ARMOR);
|
||||
- LayeredCauldronBlock.lowerFillLevel(state, level, pos);
|
||||
+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit
|
||||
}
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
if (!level.isClientSide()) {
|
||||
+ // CraftBukkit start
|
||||
+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) {
|
||||
+ return InteractionResult.SUCCESS;
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
itemInHand.remove(DataComponents.DYED_COLOR);
|
||||
player.awardStat(Stats.CLEAN_ARMOR);
|
||||
- LayeredCauldronBlock.lowerFillLevel(state, level, pos);
|
||||
+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit
|
||||
}
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
+3
-3
@@ -24,10 +24,10 @@
|
||||
@@ -126,6 +_,7 @@
|
||||
patch.map
|
||||
)) {
|
||||
Optional<?> value = entryx.getValue();
|
||||
+ value = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items
|
||||
Optional<?> value = entry.getValue();
|
||||
+ value = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entry.getKey(), entry.getValue()); // Paper - data sanitization for items
|
||||
if (value.isPresent()) {
|
||||
DataComponentType<?> type = entryx.getKey();
|
||||
DataComponentType<?> type = entry.getKey();
|
||||
DataComponentType.STREAM_CODEC.encode(output, type);
|
||||
@@ -145,7 +_,13 @@
|
||||
}
|
||||
|
||||
+49
-48
@@ -124,7 +124,7 @@
|
||||
return this.consumeWithRemainder(source, dispensed, new ItemStack(Items.BUCKET));
|
||||
} else {
|
||||
return this.defaultDispenseItemBehavior.dispense(source, dispensed);
|
||||
@@ -174,12 +_,19 @@
|
||||
@@ -174,13 +_,20 @@
|
||||
BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING));
|
||||
BlockState blockState = level.getBlockState(target);
|
||||
if (blockState.getBlock() instanceof BucketPickup bucket) {
|
||||
@@ -132,19 +132,20 @@
|
||||
+ ItemStack pickup = bucket.pickupBlock(null, org.bukkit.craftbukkit.util.DummyLevelAccessor.INSTANCE, target, blockState); // CraftBukkit
|
||||
if (pickup.isEmpty()) {
|
||||
return super.execute(source, dispensed);
|
||||
} else {
|
||||
level.gameEvent(null, GameEvent.FLUID_PICKUP, target);
|
||||
Item targetType = pickup.getItem();
|
||||
+ // Paper start - Call BlockDispenseEvent
|
||||
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this);
|
||||
+ if (result != null) {
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Paper end - Call BlockDispenseEvent
|
||||
+ pickup = bucket.pickupBlock(null, level, target, blockState); // CraftBukkit - from above
|
||||
return this.consumeWithRemainder(source, dispensed, new ItemStack(targetType));
|
||||
}
|
||||
|
||||
level.gameEvent(null, GameEvent.FLUID_PICKUP, target);
|
||||
Item targetType = pickup.getItem();
|
||||
+ // Paper start - Call BlockDispenseEvent
|
||||
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this);
|
||||
+ if (result != null) {
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Paper end - Call BlockDispenseEvent
|
||||
+ pickup = bucket.pickupBlock(null, level, target, blockState); // CraftBukkit - from above
|
||||
return this.consumeWithRemainder(source, dispensed, new ItemStack(targetType));
|
||||
} else {
|
||||
return super.execute(source, dispensed);
|
||||
@@ -194,15 +_,26 @@
|
||||
this.setSuccess(true);
|
||||
Direction facing = source.state().getValue(DispenserBlock.FACING);
|
||||
@@ -333,35 +334,35 @@
|
||||
RespawnAnchorBlock.charge(null, level, pos, blockState);
|
||||
dispensed.shrink(1);
|
||||
} else {
|
||||
@@ -383,6 +_,28 @@
|
||||
this.setSuccess(false);
|
||||
@@ -384,6 +_,28 @@
|
||||
return dispensed;
|
||||
} else {
|
||||
+ // CraftBukkit start
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos());
|
||||
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed); // Paper - ignore stack size on damageable items
|
||||
}
|
||||
|
||||
+ // CraftBukkit start
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos());
|
||||
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed); // Paper - ignore stack size on damageable items
|
||||
+
|
||||
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), armadillos.get(0).getBukkitLivingEntity());
|
||||
+ level.getCraftServer().getPluginManager().callEvent(event);
|
||||
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), armadillos.get(0).getBukkitLivingEntity());
|
||||
+ level.getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ this.setSuccess(false);
|
||||
+ if (event.isCancelled()) {
|
||||
+ this.setSuccess(false);
|
||||
+ return dispensed;
|
||||
+ }
|
||||
+
|
||||
+ if (!event.getItem().equals(craftItem)) {
|
||||
+ // Chain to handler for new item
|
||||
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack);
|
||||
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
|
||||
+ dispenseBehavior.dispense(source, eventStack);
|
||||
+ return dispensed;
|
||||
+ }
|
||||
+
|
||||
+ if (!event.getItem().equals(craftItem)) {
|
||||
+ // Chain to handler for new item
|
||||
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack);
|
||||
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
|
||||
+ dispenseBehavior.dispense(source, eventStack);
|
||||
+ return dispensed;
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
for (Armadillo armadillo : armadillos) {
|
||||
if (armadillo.brushOffScute(null, dispensed)) {
|
||||
dispensed.hurtAndBreak(16, level, null, item -> {});
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
for (Armadillo armadillo : armadillos) {
|
||||
if (armadillo.brushOffScute(null, dispensed)) {
|
||||
dispensed.hurtAndBreak(16, level, null, item -> {});
|
||||
@@ -403,6 +_,13 @@
|
||||
BlockState blockState = level.getBlockState(pos);
|
||||
Optional<BlockState> maybeWaxed = HoneycombItem.getWaxed(blockState);
|
||||
@@ -376,16 +377,16 @@
|
||||
level.setBlockAndUpdate(pos, maybeWaxed.get());
|
||||
level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_WAX_ON, pos, 0);
|
||||
dispensed.shrink(1);
|
||||
@@ -430,6 +_,12 @@
|
||||
if (!level.getBlockState(target).is(BlockTags.CONVERTABLE_TO_MUD)) {
|
||||
return this.defaultDispenseItemBehavior.dispense(source, dispensed);
|
||||
} else {
|
||||
+ // Paper start - Call BlockDispenseEvent
|
||||
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this);
|
||||
+ if (result != null) {
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Paper end - Call BlockDispenseEvent
|
||||
if (!level.isClientSide()) {
|
||||
RandomSource random = level.getRandom();
|
||||
@@ -432,6 +_,12 @@
|
||||
return this.defaultDispenseItemBehavior.dispense(source, dispensed);
|
||||
}
|
||||
|
||||
+ // Paper start - Call BlockDispenseEvent
|
||||
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this);
|
||||
+ if (result != null) {
|
||||
+ return result;
|
||||
+ }
|
||||
+ // Paper end - Call BlockDispenseEvent
|
||||
if (!level.isClientSide()) {
|
||||
RandomSource random = level.getRandom();
|
||||
|
||||
+39
-39
@@ -19,45 +19,45 @@
|
||||
BlockPos pos = source.pos().relative(source.state().getValue(DispenserBlock.FACING));
|
||||
List<LivingEntity> entities = source.level().getEntitiesOfClass(LivingEntity.class, new AABB(pos), entity -> entity.canEquipWithDispenser(dispensed));
|
||||
if (entities.isEmpty()) {
|
||||
@@ -25,13 +_,39 @@
|
||||
} else {
|
||||
LivingEntity target = entities.getFirst();
|
||||
EquipmentSlot slot = target.getEquipmentSlotForItem(dispensed);
|
||||
- ItemStack equip = dispensed.split(1);
|
||||
- target.setItemSlot(slot, equip);
|
||||
+ ItemStack equip = dispensed.copyWithCount(1); // Paper - shrink below and single item in event
|
||||
+ // CraftBukkit start
|
||||
+ net.minecraft.world.level.Level world = source.level();
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, source.pos());
|
||||
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(equip);
|
||||
+
|
||||
+ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) target.getBukkitEntity());
|
||||
+ world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ boolean shrink = true;
|
||||
+ if (!event.getItem().equals(craftItem)) {
|
||||
+ shrink = false;
|
||||
+ // Chain to handler for new item
|
||||
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(source, eventStack);
|
||||
+ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || dispenseItemBehavior != currentBehavior)) {
|
||||
+ dispenseItemBehavior.dispense(source, eventStack);
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ target.setItemSlot(slot, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()));
|
||||
+ // CraftBukkit end
|
||||
if (target instanceof Mob targetMob) {
|
||||
targetMob.setGuaranteedDrop(slot);
|
||||
targetMob.setPersistenceRequired();
|
||||
}
|
||||
@@ -26,13 +_,39 @@
|
||||
|
||||
+ if (shrink) dispensed.shrink(1); // Paper - shrink here
|
||||
return true;
|
||||
LivingEntity target = entities.getFirst();
|
||||
EquipmentSlot slot = target.getEquipmentSlotForItem(dispensed);
|
||||
- ItemStack equip = dispensed.split(1);
|
||||
- target.setItemSlot(slot, equip);
|
||||
+ ItemStack equip = dispensed.copyWithCount(1); // Paper - shrink below and single item in event
|
||||
+ // CraftBukkit start
|
||||
+ net.minecraft.world.level.Level world = source.level();
|
||||
+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, source.pos());
|
||||
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(equip);
|
||||
+
|
||||
+ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) target.getBukkitEntity());
|
||||
+ world.getCraftServer().getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ boolean shrink = true;
|
||||
+ if (!event.getItem().equals(craftItem)) {
|
||||
+ shrink = false;
|
||||
+ // Chain to handler for new item
|
||||
+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
|
||||
+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(source, eventStack);
|
||||
+ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || dispenseItemBehavior != currentBehavior)) {
|
||||
+ dispenseItemBehavior.dispense(source, eventStack);
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ target.setItemSlot(slot, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()));
|
||||
+ // CraftBukkit end
|
||||
if (target instanceof Mob targetMob) {
|
||||
targetMob.setGuaranteedDrop(slot);
|
||||
targetMob.setPersistenceRequired();
|
||||
}
|
||||
|
||||
+ if (shrink) dispensed.shrink(1); // Paper - shrink here
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -35,6 +35,6 @@
|
||||
+ dispensed.shrink(1); // vanilla shrink is in the place function above, manually handle it here
|
||||
+ }
|
||||
+ // Paper end - track changed items in the dispense event
|
||||
} catch (Exception var8) {
|
||||
LOGGER.error("Error trying to place shulker box at {}", relativePos, var8);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error trying to place shulker box at {}", relativePos, e);
|
||||
}
|
||||
+38
-38
@@ -1,42 +1,42 @@
|
||||
--- a/net/minecraft/core/dispenser/SpawnEggItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/SpawnEggItemBehavior.java
|
||||
@@ -18,14 +_,37 @@
|
||||
if (type == null) {
|
||||
return dispensed;
|
||||
} else {
|
||||
+ // Paper start - block dispense event
|
||||
+ ItemStack singleDispensed = dispensed.copyWithCount(1);
|
||||
+ final org.bukkit.craftbukkit.inventory.CraftItemStack eventItemCopy = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleDispensed);
|
||||
+ final org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(
|
||||
+ org.bukkit.craftbukkit.block.CraftBlock.at(source.level(), source.pos()),
|
||||
+ eventItemCopy,
|
||||
+ new org.bukkit.util.Vector(0, 0, 0)
|
||||
+ );
|
||||
+ if (!event.callEvent()) return dispensed;
|
||||
+
|
||||
+ final boolean shrink = event.getItem().equals(eventItemCopy);
|
||||
+ if (!shrink) {
|
||||
+ final ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem());
|
||||
+ final DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack);
|
||||
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
|
||||
+ dispenseBehavior.dispense(source, eventStack);
|
||||
+ return dispensed;
|
||||
+ }
|
||||
+
|
||||
+ type = SpawnEggItem.getType(eventStack);
|
||||
+ singleDispensed = eventStack;
|
||||
+ }
|
||||
+ // Paper end - block dispense event
|
||||
try {
|
||||
- type.spawn(source.level(), dispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false);
|
||||
+ type.spawn(source.level(), singleDispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); // Paper - block dispense event - update used item stack
|
||||
} catch (Exception var6) {
|
||||
LOGGER.error("Error while dispensing spawn egg from dispenser at {}", source.pos(), var6);
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
- dispensed.shrink(1);
|
||||
+ if (shrink) dispensed.shrink(1); // Paper - block dispense event - only shrink if above logic requires it.
|
||||
source.level().gameEvent(null, GameEvent.ENTITY_PLACE, source.pos());
|
||||
@@ -19,14 +_,37 @@
|
||||
return dispensed;
|
||||
}
|
||||
|
||||
+ // Paper start - block dispense event
|
||||
+ ItemStack singleDispensed = dispensed.copyWithCount(1);
|
||||
+ final org.bukkit.craftbukkit.inventory.CraftItemStack eventItemCopy = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleDispensed);
|
||||
+ final org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(
|
||||
+ org.bukkit.craftbukkit.block.CraftBlock.at(source.level(), source.pos()),
|
||||
+ eventItemCopy,
|
||||
+ new org.bukkit.util.Vector(0, 0, 0)
|
||||
+ );
|
||||
+ if (!event.callEvent()) return dispensed;
|
||||
+
|
||||
+ final boolean shrink = event.getItem().equals(eventItemCopy);
|
||||
+ if (!shrink) {
|
||||
+ final ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem());
|
||||
+ final DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack);
|
||||
+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
|
||||
+ dispenseBehavior.dispense(source, eventStack);
|
||||
+ return dispensed;
|
||||
+ }
|
||||
+
|
||||
+ type = SpawnEggItem.getType(eventStack);
|
||||
+ singleDispensed = eventStack;
|
||||
+ }
|
||||
+ // Paper end - block dispense event
|
||||
try {
|
||||
- type.spawn(source.level(), dispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false);
|
||||
+ type.spawn(source.level(), singleDispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); // Paper - block dispense event - update used item stack
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error while dispensing spawn egg from dispenser at {}", source.pos(), e);
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
- dispensed.shrink(1);
|
||||
+ if (shrink) dispensed.shrink(1); // Paper - block dispense event - only shrink if above logic requires it.
|
||||
source.level().gameEvent(null, GameEvent.ENTITY_PLACE, source.pos());
|
||||
return dispensed;
|
||||
}
|
||||
+7
-10
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/gametest/framework/GameTestServer.java
|
||||
+++ b/net/minecraft/gametest/framework/GameTestServer.java
|
||||
@@ -155,6 +_,8 @@
|
||||
@@ -154,6 +_,8 @@
|
||||
final int repeatCount
|
||||
) {
|
||||
super(
|
||||
@@ -9,21 +9,18 @@
|
||||
serverThread,
|
||||
levelStorageSource,
|
||||
packRepository,
|
||||
@@ -173,13 +_,21 @@
|
||||
@@ -172,9 +_,17 @@
|
||||
|
||||
@Override
|
||||
protected boolean initServer() {
|
||||
- this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) {});
|
||||
+ // Paper start
|
||||
this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) {
|
||||
{
|
||||
Objects.requireNonNull(GameTestServer.this);
|
||||
}
|
||||
+
|
||||
+ this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) {
|
||||
+ @Override
|
||||
+ public void loadAndSaveFiles() {
|
||||
+ throw new UnsupportedOperationException("Should not be called in a GameTestServer");
|
||||
+ }
|
||||
});
|
||||
+ });
|
||||
+ this.initPostWorld();
|
||||
Gizmos.withCollector(GizmoCollector.NOOP);
|
||||
- this.loadLevel();
|
||||
@@ -32,7 +29,7 @@
|
||||
ServerLevel level = this.overworld();
|
||||
this.testBatches = this.evaluateTestsToRun(level);
|
||||
LOGGER.info("Started game test server");
|
||||
@@ -385,6 +_,13 @@
|
||||
@@ -380,6 +_,13 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,7 +43,7 @@
|
||||
@Override
|
||||
public boolean isSingleplayerOwner(final NameAndId nameAndId) {
|
||||
return false;
|
||||
@@ -432,5 +_,16 @@
|
||||
@@ -427,5 +_,16 @@
|
||||
@Override
|
||||
public void save() {
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/nbt/CompoundTag.java
|
||||
+++ b/net/minecraft/nbt/CompoundTag.java
|
||||
@@ -54,7 +_,7 @@
|
||||
@@ -51,7 +_,7 @@
|
||||
|
||||
private static CompoundTag loadCompound(final DataInput input, final NbtAccounter accounter) throws IOException {
|
||||
accounter.accountBytes(48L);
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
byte tagType;
|
||||
while ((tagType = input.readByte()) != 0) {
|
||||
@@ -171,7 +_,7 @@
|
||||
@@ -165,7 +_,7 @@
|
||||
}
|
||||
|
||||
public CompoundTag() {
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -400,9 +_,16 @@
|
||||
@@ -394,9 +_,16 @@
|
||||
|
||||
@Override
|
||||
public CompoundTag copy() {
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -523,22 +_,47 @@
|
||||
@@ -517,22 +_,47 @@
|
||||
this.merge((CompoundTag)codec.encoder().encodeStart(ops, value).getOrThrow());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
--- a/net/minecraft/nbt/NbtAccounter.java
|
||||
+++ b/net/minecraft/nbt/NbtAccounter.java
|
||||
@@ -50,6 +_,16 @@
|
||||
this.usage += size;
|
||||
}
|
||||
|
||||
+ // Paper start - Track codec depth
|
||||
+ public void pushDepth(final int depth) {
|
||||
+ if (this.depth + depth >= this.maxDepth) {
|
||||
+ throw new NbtAccounterException("Tried to read NBT tag with too high complexity, depth > " + this.maxDepth);
|
||||
+ } else {
|
||||
+ this.depth += depth;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Track codec depth
|
||||
+
|
||||
public void pushDepth() {
|
||||
if (this.depth >= this.maxDepth) {
|
||||
throw new NbtAccounterException("Tried to read NBT tag with too high complexity, depth > " + this.maxDepth);
|
||||
Loaded 100 of 511 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user