This commit is contained in:
Noah van der Aa
2024-10-23 22:52:43 +02:00
parent 630bdd8cda
commit 57a91fb883
59 changed files with 179 additions and 186 deletions

View File

@@ -1,170 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Tue, 1 Feb 2022 15:51:55 -0700
Subject: [PATCH] API for creating command sender which forwards feedback
diff --git a/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java b/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/commands/FeedbackForwardingSender.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.commands;
+
+import io.papermc.paper.adventure.PaperAdventure;
+import java.util.UUID;
+import java.util.function.Consumer;
+import net.kyori.adventure.audience.MessageType;
+import net.kyori.adventure.identity.Identity;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import net.minecraft.commands.CommandSource;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.phys.Vec2;
+import net.minecraft.world.phys.Vec3;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.command.ServerCommandSender;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public final class FeedbackForwardingSender extends ServerCommandSender {
+ private final Consumer<? super Component> feedback;
+ private final CraftServer server;
+
+ public FeedbackForwardingSender(final Consumer<? super Component> feedback, final CraftServer server) {
+ super(((ServerCommandSender) server.getConsoleSender()).perm);
+ this.server = server;
+ this.feedback = feedback;
+ }
+
+ @Override
+ public void sendMessage(final String message) {
+ this.sendMessage(LegacyComponentSerializer.legacySection().deserialize(message));
+ }
+
+ @Override
+ public void sendMessage(final String... messages) {
+ for (final String message : messages) {
+ this.sendMessage(message);
+ }
+ }
+
+ @Override
+ public void sendMessage(final Identity identity, final Component message, final MessageType type) {
+ this.feedback.accept(message);
+ }
+
+ @Override
+ public String getName() {
+ return "FeedbackForwardingSender";
+ }
+
+ @Override
+ public Component name() {
+ return Component.text(this.getName());
+ }
+
+ @Override
+ public boolean isOp() {
+ return true;
+ }
+
+ @Override
+ public void setOp(final boolean value) {
+ throw new UnsupportedOperationException("Cannot change operator status of " + this.getClass().getName());
+ }
+
+ public CommandSourceStack asVanilla() {
+ final @Nullable ServerLevel overworld = this.server.getServer().overworld();
+ return new CommandSourceStack(
+ new Source(this),
+ overworld == null ? Vec3.ZERO : Vec3.atLowerCornerOf(overworld.getSharedSpawnPos()),
+ Vec2.ZERO,
+ overworld,
+ 4,
+ this.getName(),
+ net.minecraft.network.chat.Component.literal(this.getName()),
+ this.server.getServer(),
+ null
+ );
+ }
+
+ private record Source(FeedbackForwardingSender sender) implements CommandSource {
+ @Override
+ public void sendSystemMessage(final net.minecraft.network.chat.Component message) {
+ this.sender.sendMessage(Identity.nil(), PaperAdventure.asAdventure(message));
+ }
+
+ @Override
+ public boolean acceptsSuccess() {
+ return true;
+ }
+
+ @Override
+ public boolean acceptsFailure() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldInformAdmins() {
+ return false;
+ }
+
+ @Override
+ public CommandSender getBukkitSender(final CommandSourceStack stack) {
+ return this.sender;
+ }
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
return this.console.console;
}
+ // Paper start
+ @Override
+ public CommandSender createCommandSender(final java.util.function.Consumer<? super net.kyori.adventure.text.Component> feedback) {
+ return new io.papermc.paper.commands.FeedbackForwardingSender(feedback, this);
+ }
+ // Paper end
+
public EntityMetadataStore getEntityMetadata() {
return this.entityMetadata;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/ServerCommandSender.java
@@ -0,0 +0,0 @@ import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
public abstract class ServerCommandSender implements CommandSender {
- private final PermissibleBase perm;
+ public final PermissibleBase perm; // Paper
private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
protected ServerCommandSender() {
diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
@@ -0,0 +0,0 @@ public final class VanillaCommandWrapper extends BukkitCommand {
if (sender instanceof ProxiedCommandSender) {
return ((ProxiedNativeCommandSender) sender).getHandle();
}
+ // Paper start
+ if (sender instanceof io.papermc.paper.commands.FeedbackForwardingSender feedback) {
+ return feedback.asVanilla();
+ }
+ // Paper end
throw new IllegalArgumentException("Cannot make " + sender + " a vanilla command listener");
}

View File

@@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 28 Aug 2021 09:00:45 -0700
Subject: [PATCH] Add API for item entity health
== AT ==
public net.minecraft.world.entity.item.ItemEntity health
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
@@ -0,0 +0,0 @@ public class CraftItem extends CraftEntity implements Item {
public void setWillAge(boolean willAge) {
this.getHandle().age = willAge ? 0 : NO_AGE_TIME;
}
+
+ @Override
+ public int getHealth() {
+ return this.getHandle().health;
+ }
+
+ @Override
+ public void setHealth(int health) {
+ if (health <= 0) {
+ this.getHandle().getItem().onDestroyed(this.getHandle());
+ this.getHandle().discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PLUGIN);
+ } else {
+ this.getHandle().health = health;
+ }
+ }
// Paper end
@Override

View File

@@ -1,81 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 3 Jan 2021 20:03:35 -0800
Subject: [PATCH] Add GameEvent tags
diff --git a/src/main/java/io/papermc/paper/CraftGameEventTag.java b/src/main/java/io/papermc/paper/CraftGameEventTag.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/CraftGameEventTag.java
@@ -0,0 +0,0 @@
+package io.papermc.paper;
+
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.tags.TagKey;
+import org.bukkit.GameEvent;
+import org.bukkit.craftbukkit.tag.CraftTag;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class CraftGameEventTag extends CraftTag<net.minecraft.world.level.gameevent.GameEvent, GameEvent> {
+
+ public CraftGameEventTag(net.minecraft.core.Registry<net.minecraft.world.level.gameevent.GameEvent> registry, TagKey<net.minecraft.world.level.gameevent.GameEvent> tag) {
+ super(registry, tag);
+ }
+
+ private static final Map<GameEvent, ResourceKey<net.minecraft.world.level.gameevent.GameEvent>> KEY_CACHE = Collections.synchronizedMap(new IdentityHashMap<>());
+ @Override
+ public boolean isTagged(@NotNull GameEvent gameEvent) {
+ return registry.getHolderOrThrow(KEY_CACHE.computeIfAbsent(gameEvent, event -> ResourceKey.create(Registries.GAME_EVENT, CraftNamespacedKey.toMinecraft(event.getKey())))).is(tag);
+ }
+
+ @Override
+ public @NotNull Set<GameEvent> getValues() {
+ return getHandle().stream().map((nms) -> Objects.requireNonNull(GameEvent.getByKey(CraftNamespacedKey.fromMinecraft(BuiltInRegistries.GAME_EVENT.getKey(nms.value()))), nms + " is not a recognized game event")).collect(Collectors.toUnmodifiableSet());
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
return (org.bukkit.Tag<T>) new CraftEntityTag(BuiltInRegistries.ENTITY_TYPE, entityTagKey);
}
}
+ // Paper start
+ case org.bukkit.Tag.REGISTRY_GAME_EVENTS -> {
+ Preconditions.checkArgument(clazz == org.bukkit.GameEvent.class, "Game Event namespace must have GameEvent type");
+ TagKey<net.minecraft.world.level.gameevent.GameEvent> gameEventTagKey = TagKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, key);
+ if (net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.getTag(gameEventTagKey).isPresent()) {
+ return (org.bukkit.Tag<T>) new io.papermc.paper.CraftGameEventTag(net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT, gameEventTagKey);
+ }
+ }
+ // Paper end
default -> throw new IllegalArgumentException();
}
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
net.minecraft.core.Registry<EntityType<?>> entityTags = BuiltInRegistries.ENTITY_TYPE;
return entityTags.getTags().map(pair -> (org.bukkit.Tag<T>) new CraftEntityTag(entityTags, pair.getFirst())).collect(ImmutableList.toImmutableList());
}
+ // Paper start
+ case org.bukkit.Tag.REGISTRY_GAME_EVENTS -> {
+ Preconditions.checkArgument(clazz == org.bukkit.GameEvent.class);
+ net.minecraft.core.Registry<net.minecraft.world.level.gameevent.GameEvent> gameEvents = net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT;
+ return gameEvents.getTags().map(pair -> (org.bukkit.Tag<T>) new io.papermc.paper.CraftGameEventTag(gameEvents, pair.getFirst())).collect(ImmutableList.toImmutableList());
+ }
+ // Paper end
default -> throw new IllegalArgumentException();
}
}

View File

@@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Mon, 21 Jun 2021 21:24:45 -0400
Subject: [PATCH] Add TameableDeathMessageEvent
diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java
+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java
@@ -0,0 +0,0 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity {
@Override
public void die(DamageSource damageSource) {
if (!this.level().isClientSide && this.level().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES) && this.getOwner() instanceof ServerPlayer) {
- this.getOwner().sendSystemMessage(this.getCombatTracker().getDeathMessage());
+ // Paper start - Add TameableDeathMessageEvent
+ io.papermc.paper.event.entity.TameableDeathMessageEvent event = new io.papermc.paper.event.entity.TameableDeathMessageEvent((org.bukkit.entity.Tameable) getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getCombatTracker().getDeathMessage()));
+ if (event.callEvent()) {
+ this.getOwner().sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.deathMessage()));
+ }
+ // Paper end - Add TameableDeathMessageEvent
}
super.die(damageSource);

View File

@@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 2 Jan 2022 22:34:51 -0800
Subject: [PATCH] Add config option for worlds affected by time cmd
diff --git a/src/main/java/net/minecraft/server/commands/TimeCommand.java b/src/main/java/net/minecraft/server/commands/TimeCommand.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/commands/TimeCommand.java
+++ b/src/main/java/net/minecraft/server/commands/TimeCommand.java
@@ -0,0 +0,0 @@ public class TimeCommand {
}
public static int setTime(CommandSourceStack source, int time) {
- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in
+ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
@@ -0,0 +0,0 @@ public class TimeCommand {
}
public static int addTime(CommandSourceStack source, int time) {
- Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in
+ Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();

View File

@@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Doc <nachito94@msn.com>
Date: Mon, 2 Aug 2021 11:24:39 -0400
Subject: [PATCH] Add configurable height for slime spawn
diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
@@ -0,0 +0,0 @@ public class Slime extends Mob implements Enemy {
return checkMobSpawnRules(type, world, spawnReason, pos, random);
}
- if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > 50 && pos.getY() < 70 && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) {
+ // Paper start - Replace rules for Height in Swamp Biome
+ final double maxHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.maximum;
+ final double minHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.minimum;
+ if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > minHeightSwamp && pos.getY() < maxHeightSwamp && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) {
+ // Paper end - Replace rules for Height in Swamp Biome
return checkMobSpawnRules(type, world, spawnReason, pos, random);
}
@@ -0,0 +0,0 @@ public class Slime extends Mob implements Enemy {
ChunkPos chunkcoordintpair = new ChunkPos(pos);
boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper
- if (random.nextInt(10) == 0 && flag && pos.getY() < 40) {
+ // Paper start - Replace rules for Height in Slime Chunks
+ final double maxHeightSlimeChunk = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum;
+ if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) {
+ // Paper end - Replace rules for Height in Slime Chunks
return checkMobSpawnRules(type, world, spawnReason, pos, random);
}
}

View File

@@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: u9g <winworkswow@gmail.com>
Date: Mon, 3 Jan 2022 23:32:42 -0500
Subject: [PATCH] Add missing IAE check for PersistentDataContainer#has
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
@@ -0,0 +0,0 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
@Override
public boolean has(NamespacedKey key) {
+ Preconditions.checkArgument(key != null, "The provided key for the custom value was null"); // Paper
return this.customDataTags.get(key.toString()) != null;
}

View File

@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Sat, 12 Feb 2022 12:40:50 -0700
Subject: [PATCH] Add missing Validate calls to CraftServer#getSpawnLimit
Copies appropriate checks from CraftWorld#getSpawnLimit
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
@Override
public int getSpawnLimit(SpawnCategory spawnCategory) {
// Paper start - Add mobcaps commands
+ Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null");
+ Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory." + spawnCategory + " does not have a spawn limit.");
return this.getSpawnLimitUnsafe(spawnCategory);
}
public int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) {

View File

@@ -1,214 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 16 Oct 2021 22:57:31 -0700
Subject: [PATCH] Add missing block data API
General purpose patch adding missing getters/setters to BlockData and
its child types.
Co-authored-by: SoSeDiK <mrsosedik@gmail.com>
Co-authored-by: Fabrizio La Rosa <lr.fabrizio@gmail.com>
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftBed.java
@@ -0,0 +0,0 @@ public final class CraftBed extends org.bukkit.craftbukkit.block.data.CraftBlock
public java.util.Set<org.bukkit.block.BlockFace> getFaces() {
return this.getValues(CraftBed.FACING, org.bukkit.block.BlockFace.class);
}
+
+ // Paper start
+ @Override
+ public void setOccupied(boolean occupied) {
+ set(CraftBed.OCCUPIED, occupied);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCandle.java
@@ -0,0 +0,0 @@ public final class CraftCandle extends org.bukkit.craftbukkit.block.data.CraftBl
public int getMaximumCandles() {
return getMax(CraftCandle.CANDLES);
}
+ // Paper start
+ @Override
+ public int getMinimumCandles() {
+ return getMin(CraftCandle.CANDLES);
+ }
+ // Paper end
// org.bukkit.craftbukkit.block.data.CraftLightable
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftCherryLeaves.java
@@ -0,0 +0,0 @@ public final class CraftCherryLeaves extends org.bukkit.craftbukkit.block.data.C
public void setWaterlogged(boolean waterlogged) {
this.set(CraftCherryLeaves.WATERLOGGED, waterlogged);
}
+
+ // Paper start
+ @Override
+ public int getMaximumDistance() {
+ return getMax(DISTANCE);
+ }
+
+ @Override
+ public int getMinimumDistance() {
+ return getMin(DISTANCE);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftComposter.java
@@ -0,0 +0,0 @@ public final class CraftComposter extends org.bukkit.craftbukkit.block.data.Craf
public int getMaximumLevel() {
return getMax(CraftComposter.LEVEL);
}
+
+ // Paper start
+ @Override
+ public int getMinimumLevel() {
+ return getMin(CraftComposter.LEVEL);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftDecoratedPot.java
@@ -0,0 +0,0 @@ public final class CraftDecoratedPot extends org.bukkit.craftbukkit.block.data.C
public void setWaterlogged(boolean waterlogged) {
this.set(CraftDecoratedPot.WATERLOGGED, waterlogged);
}
+
+ // Paper start - add missing block data api
+ private static final net.minecraft.world.level.block.state.properties.BooleanProperty CRACKED = getBoolean(net.minecraft.world.level.block.DecoratedPotBlock.class, "cracked");
+
+ @Override
+ public boolean isCracked() {
+ return this.get(CraftDecoratedPot.CRACKED);
+ }
+
+ @Override
+ public void setCracked(final boolean cracked) {
+ this.set(CraftDecoratedPot.CRACKED, cracked);
+ }
+ // Paper end - add missing block data api
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftFluids.java
@@ -0,0 +0,0 @@ public final class CraftFluids extends org.bukkit.craftbukkit.block.data.CraftBl
public int getMaximumLevel() {
return getMax(CraftFluids.LEVEL);
}
+
+ // Paper start
+ @Override
+ public int getMinimumLevel() {
+ return getMin(CraftFluids.LEVEL);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLayeredCauldron.java
@@ -0,0 +0,0 @@ public final class CraftLayeredCauldron extends org.bukkit.craftbukkit.block.dat
public int getMaximumLevel() {
return getMax(CraftLayeredCauldron.LEVEL);
}
+
+ // Paper start
+ @Override
+ public int getMinimumLevel() {
+ return getMin(CraftLayeredCauldron.LEVEL);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLeaves.java
@@ -0,0 +0,0 @@ public final class CraftLeaves extends org.bukkit.craftbukkit.block.data.CraftBl
public void setWaterlogged(boolean waterlogged) {
this.set(CraftLeaves.WATERLOGGED, waterlogged);
}
+
+ // Paper start
+ @Override
+ public int getMaximumDistance() {
+ return getMax(CraftLeaves.DISTANCE);
+ }
+
+ @Override
+ public int getMinimumDistance() {
+ return getMin(CraftLeaves.DISTANCE);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftLight.java
@@ -0,0 +0,0 @@ public final class CraftLight extends org.bukkit.craftbukkit.block.data.CraftBlo
return getMax(CraftLight.LEVEL);
}
+ // Paper start
+ @Override
+ public int getMinimumLevel() {
+ return getMin(CraftLight.LEVEL);
+ }
+ // Paper end
+
// org.bukkit.craftbukkit.block.data.CraftWaterlogged
private static final net.minecraft.world.level.block.state.properties.BooleanProperty WATERLOGGED = getBoolean(net.minecraft.world.level.block.LightBlock.class, "waterlogged");
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftMangroveLeaves.java
@@ -0,0 +0,0 @@ public final class CraftMangroveLeaves extends org.bukkit.craftbukkit.block.data
public void setWaterlogged(boolean waterlogged) {
this.set(CraftMangroveLeaves.WATERLOGGED, waterlogged);
}
+
+ // Paper start
+ @Override
+ public int getMinimumDistance() {
+ return getMin(CraftMangroveLeaves.DISTANCE);
+ }
+
+ @Override
+ public int getMaximumDistance() {
+ return getMax(CraftMangroveLeaves.DISTANCE);
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPinkPetals.java
@@ -0,0 +0,0 @@ public final class CraftPinkPetals extends org.bukkit.craftbukkit.block.data.Cra
this.set(CraftPinkPetals.FLOWER_AMOUNT, flower_amount);
}
+ // Paper start
+ @Override
+ public int getMinimumFlowerAmount() {
+ return getMin(CraftPinkPetals.FLOWER_AMOUNT);
+ }
+ // Paper end
+
@Override
public int getMaximumFlowerAmount() {
return getMax(CraftPinkPetals.FLOWER_AMOUNT);

View File

@@ -1,399 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 13 Jan 2022 23:05:53 -0800
Subject: [PATCH] Add missing structure set seed configs
The 4 missing structure set seed configs are strongholds, mineshafts,
buried treasure, and ancient cities.
Strongholds use a ring placement scheme which isn't random so they
utilize the world seed by default, this adds a config to override it
for just generating the ring positions.
Mineshafts and Buried Treasure structure sets are special cases
where the "salt" that can be defined for them via datapacks has 0
effect because the difference between the spacing and separation is 1
which is used as the upper bound in the random with salt. So the random
always returns the same int (0) so the salt has no effect. This adds
seeds/salts to the frequency reducer which has a similar effect.
Co-authored-by: William Blake Galbreath <blake.galbreath@gmail.com>
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -0,0 +0,0 @@ public abstract class ChunkGenerator {
}
}
- if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z)) {
+ if (structureplacement.isStructureChunk(placementCalculator, chunkcoordintpair.x, chunkcoordintpair.z, structureplacement instanceof net.minecraft.world.level.chunk.ChunkGeneratorStructureState.KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs
if (list.size() == 1) {
this.tryGenerateStructure((StructureSet.StructureSelectionEntry) list.get(0), structureAccessor, registryManager, randomstate, structureTemplateManager, placementCalculator.getLevelSeed(), chunk, chunkcoordintpair, sectionposition);
} else {
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
@@ -0,0 +0,0 @@ public class ChunkGeneratorStructureState {
private final Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap();
private boolean hasGeneratedPositions;
private final List<Holder<StructureSet>> possibleStructureSets;
+ public final SpigotWorldConfig conf; // Paper - Add missing structure set seed configs
public static ChunkGeneratorStructureState createForFlat(RandomState randomstate, long i, BiomeSource worldchunkmanager, Stream<Holder<StructureSet>> stream, SpigotWorldConfig conf) { // Spigot
List<Holder<StructureSet>> list = stream.filter((holder) -> {
return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder.value(), worldchunkmanager);
}).toList();
- return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf)); // Spigot
+ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, 0L, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot
}
public static ChunkGeneratorStructureState createForNormal(RandomState randomstate, long i, BiomeSource worldchunkmanager, HolderLookup<StructureSet> holderlookup, SpigotWorldConfig conf) { // Spigot
@@ -0,0 +0,0 @@ public class ChunkGeneratorStructureState {
return ChunkGeneratorStructureState.hasBiomesForStructureSet((StructureSet) holder_c.value(), worldchunkmanager);
}).collect(Collectors.toUnmodifiableList());
- return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, i, ChunkGeneratorStructureState.injectSpigot(list, conf)); // Spigot
+ return new ChunkGeneratorStructureState(randomstate, worldchunkmanager, i, i, ChunkGeneratorStructureState.injectSpigot(list, conf), conf); // Spigot
}
+ // Paper start - Add missing structure set seed configs; horrible hack because spigot creates a ton of direct Holders which lose track of the identifying key
+ public static final class KeyedRandomSpreadStructurePlacement extends RandomSpreadStructurePlacement {
+ public final net.minecraft.resources.ResourceKey<StructureSet> key;
+ public KeyedRandomSpreadStructurePlacement(net.minecraft.resources.ResourceKey<StructureSet> key, net.minecraft.core.Vec3i locateOffset, FrequencyReductionMethod frequencyReductionMethod, float frequency, int salt, java.util.Optional<StructurePlacement.ExclusionZone> exclusionZone, int spacing, int separation, net.minecraft.world.level.levelgen.structure.placement.RandomSpreadType spreadType) {
+ super(locateOffset, frequencyReductionMethod, frequency, salt, exclusionZone, spacing, separation, spreadType);
+ this.key = key;
+ }
+ }
+ // Paper end - Add missing structure set seed configs
// Spigot start
private static List<Holder<StructureSet>> injectSpigot(List<Holder<StructureSet>> list, SpigotWorldConfig conf) {
return list.stream().map((holder) -> {
StructureSet structureset = holder.value();
- if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig) {
+ final Holder<StructureSet> newHolder; // Paper - Add missing structure set seed configs
+ if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig && holder.unwrapKey().orElseThrow().location().getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)) { // Paper - Add missing structure set seed configs; check namespace cause datapacks could add structure sets with the same path
String name = holder.unwrapKey().orElseThrow().location().getPath();
int seed = randomConfig.salt;
@@ -0,0 +0,0 @@ public class ChunkGeneratorStructureState {
case "villages":
seed = conf.villageSeed;
break;
+ // Paper start - Add missing structure set seed configs
+ case "ancient_cities":
+ seed = conf.ancientCitySeed;
+ break;
+ case "trail_ruins":
+ seed = conf.trailRuinsSeed;
+ break;
+ case "trial_chambers":
+ seed = conf.trialChambersSeed;
+ break;
+ // Paper end - Add missing structure set seed configs
}
- structureset = new StructureSet(structureset.structures(), new RandomSpreadStructurePlacement(randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType()));
+ // Paper start - Add missing structure set seed configs
+ structureset = new StructureSet(structureset.structures(), new KeyedRandomSpreadStructurePlacement(holder.unwrapKey().orElseThrow(), randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType()));
+ newHolder = Holder.direct(structureset); // I really wish we didn't have to do this here
+ } else {
+ newHolder = holder;
}
- return Holder.direct(structureset);
+ return newHolder;
+ // Paper end - Add missing structure set seed configs
}).collect(Collectors.toUnmodifiableList());
}
// Spigot end
@@ -0,0 +0,0 @@ public class ChunkGeneratorStructureState {
return stream.anyMatch(set::contains);
}
- private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List<Holder<StructureSet>> structureSets) {
+ private ChunkGeneratorStructureState(RandomState noiseConfig, BiomeSource biomeSource, long structureSeed, long concentricRingSeed, List<Holder<StructureSet>> structureSets, SpigotWorldConfig conf) { // Paper - Add missing structure set seed configs
this.randomState = noiseConfig;
this.levelSeed = structureSeed;
this.biomeSource = biomeSource;
this.concentricRingsSeed = concentricRingSeed;
this.possibleStructureSets = structureSets;
+ this.conf = conf; // Paper - Add missing structure set seed configs
}
public List<Holder<StructureSet>> possibleStructureSets() {
@@ -0,0 +0,0 @@ public class ChunkGeneratorStructureState {
HolderSet<Biome> holderset = placement.preferredBiomes();
RandomSource randomsource = RandomSource.create();
+ // Paper start - Add missing structure set seed configs
+ if (this.conf.strongholdSeed != null && structureSetEntry.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) {
+ randomsource.setSeed(this.conf.strongholdSeed);
+ } else {
+ // Paper end - Add missing structure set seed configs
randomsource.setSeed(this.concentricRingsSeed);
+ } // Paper - Add missing structure set seed configs
double d0 = randomsource.nextDouble() * Math.PI * 2.0D;
int l = 0;
int i1 = 0;
@@ -0,0 +0,0 @@ public class ChunkGeneratorStructureState {
for (int l = centerChunkX - chunkCount; l <= centerChunkX + chunkCount; ++l) {
for (int i1 = centerChunkZ - chunkCount; i1 <= centerChunkZ + chunkCount; ++i1) {
- if (structureplacement.isStructureChunk(this, l, i1)) {
+ if (structureplacement.isStructureChunk(this, l, i1, structureplacement instanceof KeyedRandomSpreadStructurePlacement keyed ? keyed.key : null)) { // Paper - Add missing structure set seed configs
return true;
}
}
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java
@@ -0,0 +0,0 @@ public class StructureCheck {
this.fixerUpper = dataFixer;
}
+ // Paper start - add missing structure salt configs
+ @Nullable
+ private Integer getSaltOverride(Structure type) {
+ if (this.heightAccessor instanceof net.minecraft.server.level.ServerLevel serverLevel) {
+ if (type instanceof net.minecraft.world.level.levelgen.structure.structures.MineshaftStructure) {
+ return serverLevel.spigotConfig.mineshaftSeed;
+ } else if (type instanceof net.minecraft.world.level.levelgen.structure.structures.BuriedTreasureStructure) {
+ return serverLevel.spigotConfig.buriedTreasureSeed;
+ }
+ }
+ return null;
+ }
+ // Paper end - add missing structure seed configs
+
public StructureCheckResult checkStart(ChunkPos pos, Structure type, StructurePlacement placement, boolean skipReferencedStructures) {
long l = pos.toLong();
Object2IntMap<Structure> object2IntMap = this.loadedChunks.get(l);
@@ -0,0 +0,0 @@ public class StructureCheck {
StructureCheckResult structureCheckResult = this.tryLoadFromStorage(pos, type, skipReferencedStructures, l);
if (structureCheckResult != null) {
return structureCheckResult;
- } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed)) {
+ } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed, this.getSaltOverride(type))) { // Paper - add missing structure seed configs
return StructureCheckResult.START_NOT_PRESENT;
} else {
boolean bl = this.featureChecks
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
@@ -0,0 +0,0 @@ public abstract class StructurePlacement {
return this.exclusionZone;
}
+ @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add missing structure set seed configs
public boolean isStructureChunk(ChunkGeneratorStructureState calculator, int chunkX, int chunkZ) {
+ // Paper start - Add missing structure set seed configs
+ return this.isStructureChunk(calculator, chunkX, chunkZ, null);
+ }
+ public boolean isStructureChunk(ChunkGeneratorStructureState calculator, int chunkX, int chunkZ, @org.jetbrains.annotations.Nullable net.minecraft.resources.ResourceKey<StructureSet> structureSetKey) {
+ Integer saltOverride = null;
+ if (structureSetKey != null) {
+ if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.MINESHAFTS) {
+ saltOverride = calculator.conf.mineshaftSeed;
+ } else if (structureSetKey == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.BURIED_TREASURES) {
+ saltOverride = calculator.conf.buriedTreasureSeed;
+ }
+ }
+ // Paper end - Add missing structure set seed configs
return this.isPlacementChunk(calculator, chunkX, chunkZ)
- && this.applyAdditionalChunkRestrictions(chunkX, chunkZ, calculator.getLevelSeed())
+ && this.applyAdditionalChunkRestrictions(chunkX, chunkZ, calculator.getLevelSeed(), saltOverride) // Paper - Add missing structure set seed configs
&& this.applyInteractionsWithOtherStructures(calculator, chunkX, chunkZ);
}
- public boolean applyAdditionalChunkRestrictions(int chunkX, int chunkZ, long seed) {
- return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency);
+ // Paper start - Add missing structure set seed configs
+ public boolean applyAdditionalChunkRestrictions(int chunkX, int chunkZ, long seed, @org.jetbrains.annotations.Nullable Integer saltOverride) {
+ return !(this.frequency < 1.0F) || this.frequencyReductionMethod.shouldGenerate(seed, this.salt, chunkX, chunkZ, this.frequency, saltOverride);
+ // Paper end - Add missing structure set seed configs
}
public boolean applyInteractionsWithOtherStructures(ChunkGeneratorStructureState calculator, int centerChunkX, int centerChunkZ) {
@@ -0,0 +0,0 @@ public abstract class StructurePlacement {
public abstract StructurePlacementType<?> type();
- private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) {
+ private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here
WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
worldgenRandom.setLargeFeatureWithSalt(seed, salt, chunkX, chunkZ);
return worldgenRandom.nextFloat() < frequency;
}
- private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency) {
+ private static boolean legacyProbabilityReducerWithDouble(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs
WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
+ if (saltOverride == null) { // Paper - Add missing structure set seed configs
worldgenRandom.setLargeFeatureSeed(seed, chunkX, chunkZ);
+ // Paper start - Add missing structure set seed configs
+ } else {
+ worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride);
+ }
+ // Paper end - Add missing structure set seed configs
return worldgenRandom.nextDouble() < (double)frequency;
}
- private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) {
+ private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs
WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
- worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, 10387320);
+ worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride != null ? saltOverride : HIGHLY_ARBITRARY_RANDOM_SALT); // Paper - Add missing structure set seed configs
return worldgenRandom.nextFloat() < frequency;
}
- private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency) {
+ private static boolean legacyPillagerOutpostReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here
int i = chunkX >> 4;
int j = chunkZ >> 4;
WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
@@ -0,0 +0,0 @@ public abstract class StructurePlacement {
@FunctionalInterface
public interface FrequencyReducer {
- boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance);
+ boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride); // Paper - Add missing structure set seed configs
}
public static enum FrequencyReductionMethod implements StringRepresentable {
@@ -0,0 +0,0 @@ public abstract class StructurePlacement {
this.reducer = generationPredicate;
}
- public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance) {
- return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance);
+ public boolean shouldGenerate(long seed, int salt, int chunkX, int chunkZ, float chance, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs
+ return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance, saltOverride); // Paper - Add missing structure set seed configs
}
@Override
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -0,0 +0,0 @@ public class SpigotWorldConfig
public int mansionSeed;
public int fossilSeed;
public int portalSeed;
+ // Paper start - add missing structure set configs
+ public int ancientCitySeed;
+ public int trailRuinsSeed;
+ public int trialChambersSeed;
+ public int buriedTreasureSeed;
+ public Integer mineshaftSeed;
+ public Long strongholdSeed;
+ private <N extends Number> N getSeed(String path, java.util.function.Function<String, N> toNumberFunc) {
+ final String value = this.getString(path, "default");
+ return org.apache.commons.lang3.math.NumberUtils.isParsable(value) ? toNumberFunc.apply(value) : null;
+ }
+ // Paper end
private void initWorldGenSeeds()
{
this.villageSeed = this.getInt( "seed-village", 10387312 );
@@ -0,0 +0,0 @@ public class SpigotWorldConfig
this.mansionSeed = this.getInt( "seed-mansion", 10387319 );
this.fossilSeed = this.getInt( "seed-fossil", 14357921 );
this.portalSeed = this.getInt( "seed-portal", 34222645 );
+ // Paper start - add missing structure set configs
+ this.ancientCitySeed = this.getInt("seed-ancientcity", 20083232);
+ this.trailRuinsSeed = this.getInt("seed-trailruins", 83469867);
+ this.trialChambersSeed = this.getInt("seed-trialchambers", 94251327);
+ this.buriedTreasureSeed = this.getInt("seed-buriedtreasure", 10387320); // StructurePlacement#HIGHLY_ARBITRARY_RANDOM_SALT
+ this.mineshaftSeed = this.getSeed("seed-mineshaft", Integer::parseInt);
+ this.strongholdSeed = this.getSeed("seed-stronghold", Long::parseLong);
+ // Paper end
this.log( "Custom Map Seeds: Village: " + this.villageSeed + " Desert: " + this.desertSeed + " Igloo: " + this.iglooSeed + " Jungle: " + this.jungleSeed + " Swamp: " + this.swampSeed + " Monument: " + this.monumentSeed
+ " Ocean: " + this.oceanSeed + " Shipwreck: " + this.shipwreckSeed + " End City: " + this.endCitySeed + " Slime: " + this.slimeSeed + " Nether: " + this.netherSeed + " Mansion: " + this.mansionSeed + " Fossil: " + this.fossilSeed + " Portal: " + this.portalSeed );
}
diff --git a/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java b/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/test/java/io/papermc/paper/world/structure/StructureSeedConfigTest.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.world.structure;
+
+import io.papermc.paper.configuration.PaperConfigurations;
+import java.io.File;
+import java.lang.reflect.Field;
+import net.minecraft.core.Registry;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.level.levelgen.structure.BuiltinStructureSets;
+import net.minecraft.world.level.levelgen.structure.StructureSet;
+import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.support.RegistryHelper;
+import org.bukkit.support.environment.AllFeatures;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.Test;
+import org.spigotmc.SpigotConfig;
+import org.spigotmc.SpigotWorldConfig;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@AllFeatures
+public class StructureSeedConfigTest {
+
+ @Test
+ public void checkStructureSeedDefaults() throws ReflectiveOperationException {
+ SpigotConfig.config = new YamlConfiguration() {
+ @Override
+ public void save(final @NotNull File file) {
+ // no-op
+ }
+ };
+ final SpigotWorldConfig config = PaperConfigurations.SPIGOT_WORLD_DEFAULTS.get();
+
+
+ final Registry<StructureSet> structureSets = RegistryHelper.getRegistry().registryOrThrow(Registries.STRUCTURE_SET);
+ for (final ResourceKey<StructureSet> setKey : structureSets.registryKeySet()) {
+ assertEquals(ResourceLocation.DEFAULT_NAMESPACE, setKey.location().getNamespace());
+ final StructureSet set = structureSets.getOrThrow(setKey);
+ if (setKey == BuiltinStructureSets.STRONGHOLDS) { // special case due to seed matching world seed
+ assertEquals(0, set.placement().salt);
+ continue;
+ }
+ int salt = switch (setKey.location().getPath()) {
+ case "villages" -> config.villageSeed;
+ case "desert_pyramids" -> config.desertSeed;
+ case "igloos" -> config.iglooSeed;
+ case "jungle_temples" -> config.jungleSeed;
+ case "swamp_huts" -> config.swampSeed;
+ case "pillager_outposts" -> config.outpostSeed;
+ case "ocean_monuments" -> config.monumentSeed;
+ case "woodland_mansions" -> config.mansionSeed;
+ case "buried_treasures" -> config.buriedTreasureSeed;
+ case "mineshafts" -> config.mineshaftSeed == null ? 0 : config.mineshaftSeed; // mineshaft seed is set differently
+ case "ruined_portals" -> config.portalSeed;
+ case "shipwrecks" -> config.shipwreckSeed;
+ case "ocean_ruins" -> config.oceanSeed;
+ case "nether_complexes" -> config.netherSeed;
+ case "nether_fossils" -> config.fossilSeed;
+ case "end_cities" -> config.endCitySeed;
+ case "ancient_cities" -> config.ancientCitySeed;
+ case "trail_ruins" -> config.trailRuinsSeed;
+ case "trial_chambers" -> config.trialChambersSeed;
+ default -> throw new AssertionError("Missing structure set seed in SpigotWorldConfig for " + setKey);
+ };
+ if (setKey == BuiltinStructureSets.BURIED_TREASURES) {
+ final Field field = StructurePlacement.class.getDeclaredField("HIGHLY_ARBITRARY_RANDOM_SALT");
+ field.trySetAccessible();
+ assertEquals(0, set.placement().salt);
+ assertEquals(field.get(null), salt, "Mismatched default seed for " + setKey + ". Should be " + field.get(null));
+ continue;
+ }
+ assertEquals(set.placement().salt, salt, "Mismatched default seed for " + setKey + ". Should be " + set.placement().salt);
+ }
+ }
+}

View File

@@ -1,151 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Doc <nachito94@msn.com>
Date: Sun, 3 Apr 2022 11:31:42 -0400
Subject: [PATCH] Allow changing the EnderDragon podium
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -0,0 +0,0 @@ public class EnderDragon extends Mob implements Enemy {
private final int[] nodeAdjacency;
private final BinaryHeap openSet;
private final Explosion explosionSource; // CraftBukkit - reusable source for CraftTNTPrimed.getSource()
+ // Paper start - Allow changing the EnderDragon podium
+ @Nullable
+ private BlockPos podium;
+ // Paper end - Allow changing the EnderDragon podium
public EnderDragon(EntityType<? extends EnderDragon> entitytypes, Level world) {
super(EntityType.ENDER_DRAGON, world);
@@ -0,0 +0,0 @@ public class EnderDragon extends Mob implements Enemy {
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 200.0D);
}
+ // Paper start - Allow changing the EnderDragon podium
+ public BlockPos getPodium() {
+ if (this.podium == null) {
+ return EndPodiumFeature.getLocation(this.getFightOrigin());
+ }
+ return this.podium;
+ }
+
+ public void setPodium(@Nullable BlockPos blockPos) {
+ this.podium = blockPos;
+ }
+ // Paper end - Allow changing the EnderDragon podium
+
@Override
public boolean isFlapping() {
float f = Mth.cos(this.flapTime * 6.2831855F);
@@ -0,0 +0,0 @@ public class EnderDragon extends Mob implements Enemy {
d0 = segment2[1] - segment1[1];
}
} else {
- BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin));
+ BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium
double d1 = Math.max(Math.sqrt(blockposition.distToCenterSqr(this.position())) / 4.0D, 1.0D);
d0 = (double) segmentOffset / d1;
@@ -0,0 +0,0 @@ public class EnderDragon extends Mob implements Enemy {
vec3d = this.getViewVector(tickDelta);
}
} else {
- BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.fightOrigin));
+ BlockPos blockposition = this.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - Allow changing the EnderDragon podium
f1 = Math.max((float) Math.sqrt(blockposition.distToCenterSqr(this.position())) / 4.0F, 1.0F);
float f3 = 6.0F / f1;
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonDeathPhase.java
@@ -0,0 +0,0 @@ public class DragonDeathPhase extends AbstractDragonPhaseInstance {
if (this.targetLocation == null) {
BlockPos blockPos = this.dragon
.level()
- .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
+ .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
this.targetLocation = Vec3.atBottomCenterOf(blockPos);
}
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonHoldingPatternPhase.java
@@ -0,0 +0,0 @@ public class DragonHoldingPatternPhase extends AbstractDragonPhaseInstance {
if (this.currentPath != null && this.currentPath.isDone()) {
BlockPos blockPos = this.dragon
.level()
- .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, new BlockPos(EndPodiumFeature.getLocation(this.dragon.getFightOrigin())));
+ .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, new BlockPos(this.dragon.getPodium())); // Paper - Allow changing the EnderDragon podium
int i = this.dragon.getDragonFight() == null ? 0 : this.dragon.getDragonFight().getCrystalsAlive();
if (this.dragon.getRandom().nextInt(i + 3) == 0) {
this.dragon.getPhaseManager().setPhase(EnderDragonPhase.LANDING_APPROACH);
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingApproachPhase.java
@@ -0,0 +0,0 @@ public class DragonLandingApproachPhase extends AbstractDragonPhaseInstance {
int i = this.dragon.findClosestNode();
BlockPos blockPos = this.dragon
.level()
- .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
+ .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
Player player = this.dragon
.level()
.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, (double)blockPos.getX(), (double)blockPos.getY(), (double)blockPos.getZ());
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonLandingPhase.java
@@ -0,0 +0,0 @@ public class DragonLandingPhase extends AbstractDragonPhaseInstance {
public void doServerTick() {
if (this.targetLocation == null) {
this.targetLocation = Vec3.atBottomCenterOf(
- this.dragon.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()))
+ this.dragon.level().getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()) // Paper - Allow changing the EnderDragon podium
);
}
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/phases/DragonTakeoffPhase.java
@@ -0,0 +0,0 @@ public class DragonTakeoffPhase extends AbstractDragonPhaseInstance {
if (!this.firstTick && this.currentPath != null) {
BlockPos blockPos = this.dragon
.level()
- .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.getLocation(this.dragon.getFightOrigin()));
+ .getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - Allow changing the EnderDragon podium
if (!blockPos.closerToCenterThan(this.dragon.position(), 10.0)) {
this.dragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java
@@ -0,0 +0,0 @@ public class CraftEnderDragon extends CraftMob implements EnderDragon, CraftEnem
public int getDeathAnimationTicks() {
return this.getHandle().dragonDeathTime;
}
+
+ // Paper start - Allow changing the EnderDragon podium
+ @Override
+ public org.bukkit.Location getPodium() {
+ net.minecraft.core.BlockPos blockPosOrigin = this.getHandle().getPodium();
+ return new org.bukkit.Location(getWorld(), blockPosOrigin.getX(), blockPosOrigin.getY(), blockPosOrigin.getZ());
+ }
+
+ @Override
+ public void setPodium(org.bukkit.Location location) {
+ if (location == null) {
+ this.getHandle().setPodium(null);
+ } else {
+ org.apache.commons.lang.Validate.isTrue(location.getWorld() == null || location.getWorld().equals(getWorld()), "You cannot set a podium in a different world to where the dragon is");
+ this.getHandle().setPodium(io.papermc.paper.util.MCUtil.toBlockPos(location));
+ }
+ }
+ // Paper end - Allow changing the EnderDragon podium
}

View File

@@ -1,69 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 26 Dec 2021 14:03:17 -0500
Subject: [PATCH] Bucketable API
diff --git a/src/main/java/io/papermc/paper/entity/PaperBucketable.java b/src/main/java/io/papermc/paper/entity/PaperBucketable.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/entity/PaperBucketable.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.entity;
+
+import org.bukkit.Sound;
+import org.bukkit.craftbukkit.CraftSound;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.inventory.ItemStack;
+
+public interface PaperBucketable extends Bucketable {
+
+ net.minecraft.world.entity.animal.Bucketable getHandle();
+
+ @Override
+ default boolean isFromBucket() {
+ return this.getHandle().fromBucket();
+ }
+
+ @Override
+ default void setFromBucket(boolean fromBucket) {
+ this.getHandle().setFromBucket(fromBucket);
+ }
+
+ @Override
+ default ItemStack getBaseBucketItem() {
+ return CraftItemStack.asBukkitCopy(this.getHandle().getBucketItemStack());
+ }
+
+ @Override
+ default Sound getPickupSound() {
+ return CraftSound.minecraftToBukkit(this.getHandle().getPickupSound());
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAxolotl.java
@@ -0,0 +0,0 @@ import com.google.common.base.Preconditions;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Axolotl;
-public class CraftAxolotl extends CraftAnimals implements Axolotl {
+public class CraftAxolotl extends CraftAnimals implements Axolotl, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API
public CraftAxolotl(CraftServer server, net.minecraft.world.entity.animal.axolotl.Axolotl entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFish.java
@@ -0,0 +0,0 @@ import net.minecraft.world.entity.animal.AbstractFish;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Fish;
-public class CraftFish extends CraftWaterMob implements Fish {
+public class CraftFish extends CraftWaterMob implements Fish, io.papermc.paper.entity.PaperBucketable { // Paper - Bucketable API
public CraftFish(CraftServer server, AbstractFish entity) {
super(server, entity);

View File

@@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sat, 19 Mar 2022 12:12:22 +0000
Subject: [PATCH] Buffer OOB setBlock calls
lets debug mode throw a trace in order to potentially see where
such calls are cascading from easier, but, generally, if you see one setBlock
call, you're gonna see more, and this just potentially causes a flood of logs
which can cause issues for slower terminals, etc.
We can limit the flood by just allowing one for a single gen region,
we'll also only gen a trace for the first one, I see no real pressing need
to generate more, given that that would *massively* negate this patch otherwise
diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java
+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java
@@ -0,0 +0,0 @@ public class WorldGenRegion implements WorldGenLevel {
}
}
+ private boolean hasSetFarWarned = false; // Paper - Buffer OOB setBlock calls
@Override
public boolean ensureCanWrite(BlockPos pos) {
int i = SectionPos.blockToSectionCoord(pos.getX());
@@ -0,0 +0,0 @@ public class WorldGenRegion implements WorldGenLevel {
return true;
} else {
+ // Paper start - Buffer OOB setBlock calls
+ if (!hasSetFarWarned) {
Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + String.valueOf(pos) + ", status: " + String.valueOf(this.generatingStep.targetStatus()) + (this.currentlyGenerating == null ? "" : ", currently generating: " + (String) this.currentlyGenerating.get()));
+ hasSetFarWarned = true;
+ if (this.getServer() != null && this.getServer().isDebugging()) {
+ io.papermc.paper.util.TraceUtil.dumpTraceForThread("far setBlock call");
+ }
+ }
+ // Paper end - Buffer OOB setBlock calls
return false;
}
}

View File

@@ -1,66 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 20 Mar 2022 22:06:47 -0700
Subject: [PATCH] Cache resource keys and optimize reference Holder tags set
TagKeys are always interned, so we can use a reference hash set for them
diff --git a/src/main/java/net/minecraft/core/Holder.java b/src/main/java/net/minecraft/core/Holder.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/core/Holder.java
+++ b/src/main/java/net/minecraft/core/Holder.java
@@ -0,0 +0,0 @@ public interface Holder<T> {
}
void bindTags(Collection<TagKey<T>> tags) {
- this.tags = Set.copyOf(tags);
+ this.tags = java.util.Collections.unmodifiableSet(new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(tags)); // Paper
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBiome.java
@@ -0,0 +0,0 @@ package org.bukkit.craftbukkit.block;
import com.google.common.base.Preconditions;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
import org.bukkit.Registry;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.CraftRegistry;
@@ -0,0 +0,0 @@ public class CraftBiome {
return CraftBiome.minecraftToBukkit(minecraft.value());
}
+ private static final java.util.Map<org.bukkit.block.Biome, ResourceKey<net.minecraft.world.level.biome.Biome>> BIOME_KEY_CACHE = java.util.Collections.synchronizedMap(new java.util.EnumMap<>(Biome.class)); // Paper
public static net.minecraft.world.level.biome.Biome bukkitToMinecraft(Biome bukkit) {
if (bukkit == null || bukkit == Biome.CUSTOM) {
return null;
}
return CraftRegistry.getMinecraftRegistry(Registries.BIOME)
- .getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow();
+ .getOptional(BIOME_KEY_CACHE.computeIfAbsent(bukkit, b -> ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(b.getKey())))).orElseThrow();
}
public static Holder<net.minecraft.world.level.biome.Biome> bukkitToMinecraftHolder(Biome bukkit) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityType.java
@@ -0,0 +0,0 @@ public class CraftEntityType {
return bukkit;
}
+ private static final java.util.Map<EntityType, net.minecraft.resources.ResourceKey<net.minecraft.world.entity.EntityType<?>>> KEY_CACHE = java.util.Collections.synchronizedMap(new java.util.EnumMap<>(EntityType.class)); // Paper
public static net.minecraft.world.entity.EntityType<?> bukkitToMinecraft(EntityType bukkit) {
Preconditions.checkArgument(bukkit != null);
-
return CraftRegistry.getMinecraftRegistry(Registries.ENTITY_TYPE)
- .getOptional(CraftNamespacedKey.toMinecraft(bukkit.getKey())).orElseThrow();
+ .getOptional(KEY_CACHE.computeIfAbsent(bukkit, type -> net.minecraft.resources.ResourceKey.create(Registries.ENTITY_TYPE, CraftNamespacedKey.toMinecraft(type.getKey())))).orElseThrow();
}
public static String bukkitToString(EntityType bukkit) {

View File

@@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Thu, 16 Dec 2021 09:40:39 +0100
Subject: [PATCH] Configurable max block light for monster spawning
diff --git a/src/main/java/net/minecraft/world/entity/monster/Monster.java b/src/main/java/net/minecraft/world/entity/monster/Monster.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Monster.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Monster.java
@@ -0,0 +0,0 @@ public abstract class Monster extends PathfinderMob implements Enemy {
return false;
} else {
DimensionType dimensionType = world.dimensionType();
- int i = dimensionType.monsterSpawnBlockLightLimit();
+ int i = world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning
if (i < 15 && world.getBrightness(LightLayer.BLOCK, pos) > i) {
return false;
} else {

View File

@@ -1,106 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 19 Aug 2021 18:45:42 -0700
Subject: [PATCH] Configurable sculk sensor listener range
== AT ==
public-f net.minecraft.world.level.gameevent.vibrations.VibrationListener listenerRange
diff --git a/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java
@@ -0,0 +0,0 @@ public class CalibratedSculkSensorBlockEntity extends SculkSensorBlockEntity {
public VibrationSystem.User createVibrationUser() {
return new CalibratedSculkSensorBlockEntity.VibrationUser(this.getBlockPos());
}
+ // Paper start - Configurable sculk sensor listener range
+ @Override
+ protected void saveRangeOverride(final net.minecraft.nbt.CompoundTag nbt) {
+ if (this.rangeOverride != null && this.rangeOverride != 16) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default
+ }
+ // Paper end - Configurable sculk sensor listener range
protected class VibrationUser extends SculkSensorBlockEntity.VibrationUser {
public VibrationUser(final BlockPos pos) {
@@ -0,0 +0,0 @@ public class CalibratedSculkSensorBlockEntity extends SculkSensorBlockEntity {
@Override
public int getListenerRadius() {
+ if (CalibratedSculkSensorBlockEntity.this.rangeOverride != null) return CalibratedSculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range
return 16;
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java
@@ -0,0 +0,0 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList
private final VibrationSystem.Listener vibrationListener;
private final VibrationSystem.User vibrationUser = this.createVibrationUser();
public int lastVibrationFrequency;
+ @Nullable public Integer rangeOverride = null; // Paper - Configurable sculk sensor listener range
protected SculkSensorBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
@@ -0,0 +0,0 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList
.resultOrPartial(string -> LOGGER.error("Failed to parse vibration listener for Sculk Sensor: '{}'", string))
.ifPresent(listener -> this.vibrationData = listener);
}
+ // Paper start - Configurable sculk sensor listener range
+ if (nbt.contains(PAPER_LISTENER_RANGE_NBT_KEY)) {
+ this.rangeOverride = nbt.getInt(PAPER_LISTENER_RANGE_NBT_KEY);
+ } else {
+ this.rangeOverride = null;
+ }
+ // Paper end - Configurable sculk sensor listener range
}
+ protected static final String PAPER_LISTENER_RANGE_NBT_KEY = "Paper.ListenerRange"; // Paper - Configurable sculk sensor listener range
@Override
protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registryLookup) {
super.saveAdditional(nbt, registryLookup);
@@ -0,0 +0,0 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList
.encodeStart(registryOps, this.vibrationData)
.resultOrPartial(string -> LOGGER.error("Failed to encode vibration listener for Sculk Sensor: '{}'", string))
.ifPresent(listenerNbt -> nbt.put("listener", listenerNbt));
+ this.saveRangeOverride(nbt); // Paper - Configurable sculk sensor listener range
+ }
+ // Paper start - Configurable sculk sensor listener range
+ protected void saveRangeOverride(CompoundTag nbt) {
+ if (this.rangeOverride != null && this.rangeOverride != VibrationUser.LISTENER_RANGE) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.rangeOverride); // only save if it's different from the default
}
+ // Paper end - Configurable sculk sensor listener range
@Override
public VibrationSystem.Data getVibrationData() {
@@ -0,0 +0,0 @@ public class SculkSensorBlockEntity extends BlockEntity implements GameEventList
@Override
public int getListenerRadius() {
+ if (SculkSensorBlockEntity.this.rangeOverride != null) return SculkSensorBlockEntity.this.rangeOverride; // Paper - Configurable sculk sensor listener range
return 8;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSculkSensor.java
@@ -0,0 +0,0 @@ public class CraftSculkSensor<T extends SculkSensorBlockEntity> extends CraftBlo
public CraftSculkSensor<T> copy(Location location) {
return new CraftSculkSensor<>(this, location);
}
+
+ // Paper start
+ @Override
+ public int getListenerRange() {
+ return this.getSnapshot().getListener().getListenerRadius();
+ }
+
+ @Override
+ public void setListenerRange(int range) {
+ Preconditions.checkArgument(range > 0, "Vibration listener range must be greater than 0");
+ this.getSnapshot().rangeOverride = range;
+ }
+ // Paper end
}

View File

@@ -1,329 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 7 Oct 2021 14:34:55 -0700
Subject: [PATCH] Custom Potion Mixes
== AT ==
public-f net.minecraft.server.MinecraftServer potionBrewing
diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java b/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/potion/PaperPotionBrewer.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.potion;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.NamespacedKey;
+import org.bukkit.potion.PotionBrewer;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionType;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+@DefaultQualifier(NonNull.class)
+public class PaperPotionBrewer implements PotionBrewer {
+
+ private final MinecraftServer minecraftServer;
+
+ public PaperPotionBrewer(final MinecraftServer minecraftServer) {
+ this.minecraftServer = minecraftServer;
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ public Collection<PotionEffect> getEffects(PotionType type, boolean upgraded, boolean extended) {
+ final org.bukkit.NamespacedKey key = type.getKey();
+
+ Preconditions.checkArgument(!key.getKey().startsWith("strong_"), "Strong potion type cannot be used directly, got %s", key);
+ Preconditions.checkArgument(!key.getKey().startsWith("long_"), "Extended potion type cannot be used directly, got %s", key);
+
+ org.bukkit.NamespacedKey effectiveKey = key;
+ if (upgraded) {
+ effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "strong_" + key.key());
+ } else if (extended) {
+ effectiveKey = new org.bukkit.NamespacedKey(key.namespace(), "long_" + key.key());
+ }
+
+ final org.bukkit.potion.PotionType effectivePotionType = org.bukkit.Registry.POTION.get(effectiveKey);
+ Preconditions.checkNotNull(type, "Unknown potion type from data " + effectiveKey.asMinimalString()); // Legacy error message in 1.20.4
+ return effectivePotionType.getPotionEffects();
+ }
+
+ @Override
+ public void addPotionMix(final PotionMix potionMix) {
+ this.minecraftServer.potionBrewing().addPotionMix(potionMix);
+ }
+
+ @Override
+ public void removePotionMix(final NamespacedKey key) {
+ this.minecraftServer.potionBrewing.removePotionMix(key);
+ }
+
+ @Override
+ public void resetPotionMixes() {
+ this.minecraftServer.potionBrewing = this.minecraftServer.potionBrewing().reload(this.minecraftServer.getWorldData().enabledFeatures());
+ }
+}
diff --git a/src/main/java/io/papermc/paper/potion/PaperPotionMix.java b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/potion/PaperPotionMix.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.potion;
+
+import java.util.function.Predicate;
+import net.minecraft.world.item.ItemStack;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
+import org.bukkit.inventory.RecipeChoice;
+
+public record PaperPotionMix(ItemStack result, Predicate<ItemStack> input, Predicate<ItemStack> ingredient) {
+
+ public PaperPotionMix(PotionMix potionMix) {
+ this(CraftItemStack.asNMSCopy(potionMix.getResult()), convert(potionMix.getInput()), convert(potionMix.getIngredient()));
+ }
+
+ static Predicate<ItemStack> convert(final RecipeChoice choice) {
+ if (choice instanceof PredicateRecipeChoice predicateRecipeChoice) {
+ return stack -> predicateRecipeChoice.test(CraftItemStack.asBukkitCopy(stack));
+ }
+ return CraftRecipe.toIngredient(choice, true);
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.worldData.setDataConfiguration(worlddataconfiguration);
this.resources.managers.updateRegistryTags();
+ this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes
this.getPlayerList().saveAll();
this.getPlayerList().reloadResources();
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
diff --git a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
@@ -0,0 +0,0 @@ public class BrewingStandMenu extends AbstractContainerMenu {
this.brewingStandData = propertyDelegate;
PotionBrewing potionbrewer = playerInventory.player.level().potionBrewing();
- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 0, 56, 51));
- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 1, 79, 58));
- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 2, 102, 51));
+ // Paper start - custom potion mixes
+ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 0, 56, 51, potionbrewer));
+ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 1, 79, 58, potionbrewer));
+ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 2, 102, 51, potionbrewer));
+ // Paper end - custom potion mixes
this.ingredientSlot = this.addSlot(new BrewingStandMenu.IngredientsSlot(potionbrewer, inventory, 3, 79, 17));
this.addSlot(new BrewingStandMenu.FuelSlot(inventory, 4, 17, 17));
this.addDataSlots(propertyDelegate);
@@ -0,0 +0,0 @@ public class BrewingStandMenu extends AbstractContainerMenu {
if (!this.moveItemStackTo(itemstack1, 3, 4, false)) {
return ItemStack.EMPTY;
}
- } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemstack)) {
+ } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemstack, this.player.player.level().potionBrewing())) { // Paper - custom potion mixes
if (!this.moveItemStackTo(itemstack1, 0, 3, false)) {
return ItemStack.EMPTY;
}
@@ -0,0 +0,0 @@ public class BrewingStandMenu extends AbstractContainerMenu {
private static class PotionSlot extends Slot {
- public PotionSlot(Container inventory, int index, int x, int y) {
+ private final PotionBrewing potionBrewing; // Paper - custom potion mixes
+ public PotionSlot(Container inventory, int index, int x, int y, PotionBrewing potionBrewing) { // Paper - custom potion mixes
super(inventory, index, x, y);
+ this.potionBrewing = potionBrewing; // Paper - custom potion mixes
}
@Override
public boolean mayPlace(ItemStack stack) {
- return PotionSlot.mayPlaceItem(stack);
+ return PotionSlot.mayPlaceItem(stack, this.potionBrewing); // Paper - custom potion mixes
}
@Override
@@ -0,0 +0,0 @@ public class BrewingStandMenu extends AbstractContainerMenu {
super.onTake(player, stack);
}
- public static boolean mayPlaceItem(ItemStack stack) {
- return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE);
+ public static boolean mayPlaceItem(ItemStack stack, PotionBrewing potionBrewing) { // Paper - custom potion mixes
+ return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(stack); // Paper - Custom Potion Mixes
}
}
diff --git a/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java b/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java
+++ b/src/main/java/net/minecraft/world/item/alchemy/PotionBrewing.java
@@ -0,0 +0,0 @@ public class PotionBrewing {
private final List<Ingredient> containers;
private final List<PotionBrewing.Mix<Potion>> potionMixes;
private final List<PotionBrewing.Mix<Item>> containerMixes;
+ private final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<org.bukkit.NamespacedKey, io.papermc.paper.potion.PaperPotionMix> customMixes = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper - Custom Potion Mixes
PotionBrewing(List<Ingredient> potionTypes, List<PotionBrewing.Mix<Potion>> potionRecipes, List<PotionBrewing.Mix<Item>> itemRecipes) {
this.containers = potionTypes;
@@ -0,0 +0,0 @@ public class PotionBrewing {
}
public boolean isIngredient(ItemStack stack) {
- return this.isContainerIngredient(stack) || this.isPotionIngredient(stack);
+ return this.isContainerIngredient(stack) || this.isPotionIngredient(stack) || this.isCustomIngredient(stack); // Paper - Custom Potion Mixes
}
private boolean isContainer(ItemStack stack) {
@@ -0,0 +0,0 @@ public class PotionBrewing {
}
public boolean hasMix(ItemStack input, ItemStack ingredient) {
+ // Paper start - Custom Potion Mixes
+ if (this.hasCustomMix(input, ingredient)) {
+ return true;
+ }
+ // Paper end - Custom Potion Mixes
return this.isContainer(input) && (this.hasContainerMix(input, ingredient) || this.hasPotionMix(input, ingredient));
}
@@ -0,0 +0,0 @@ public class PotionBrewing {
if (input.isEmpty()) {
return input;
} else {
+ // Paper start - Custom Potion Mixes
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) {
+ return mix.result().copy();
+ }
+ }
+ // Paper end - Custom Potion Mixes
Optional<Holder<Potion>> optional = input.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion();
if (optional.isEmpty()) {
return input;
@@ -0,0 +0,0 @@ public class PotionBrewing {
builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING);
}
+ // Paper start - Custom Potion Mixes
+ public boolean isCustomIngredient(ItemStack stack) {
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
+ if (mix.ingredient().test(stack)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isCustomInput(ItemStack stack) {
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
+ if (mix.input().test(stack)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasCustomMix(ItemStack input, ItemStack ingredient) {
+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) {
+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void addPotionMix(io.papermc.paper.potion.PotionMix mix) {
+ if (this.customMixes.containsKey(mix.getKey())) {
+ throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey());
+ }
+ this.customMixes.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix));
+ }
+
+ public boolean removePotionMix(org.bukkit.NamespacedKey key) {
+ return this.customMixes.remove(key) != null;
+ }
+
+ public PotionBrewing reload(FeatureFlagSet flags) {
+ return bootstrap(flags);
+ }
+ // Paper end - Custom Potion Mixes
+
public static class Builder {
private final List<Ingredient> containers = new ArrayList<>();
private final List<PotionBrewing.Mix<Potion>> potionMixes = new ArrayList<>();
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
@@ -0,0 +0,0 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
@Override
public boolean canPlaceItem(int slot, ItemStack stack) {
+ PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY; // Paper - move up
if (slot == 3) {
- PotionBrewing potionbrewer = this.level != null ? this.level.potionBrewing() : PotionBrewing.EMPTY;
return potionbrewer.isIngredient(stack);
} else {
- return slot == 4 ? stack.is(Items.BLAZE_POWDER) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE)) && this.getItem(slot).isEmpty();
+ return slot == 4 ? stack.is(Items.BLAZE_POWDER) : (stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionbrewer.isCustomInput(stack)) && this.getItem(slot).isEmpty(); // Paper - Custom Potion Mixes
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
private final io.papermc.paper.datapack.PaperDatapackManager datapackManager; // Paper
public static Exception excessiveVelEx; // Paper - Velocity warnings
private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher(); // Paper
+ private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer; // Paper - Custom Potion Mixes
static {
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
if (this.configuration.getBoolean("settings.use-map-color-cache")) {
MapPalette.setMapColorCache(new CraftMapColorCache(this.logger));
}
+ this.potionBrewer = new io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes
datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper
}
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
return datapackManager;
}
+ @Override
+ public io.papermc.paper.potion.PaperPotionBrewer getPotionBrewer() {
+ return this.potionBrewer;
+ }
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
@@ -0,0 +0,0 @@ public interface CraftRecipe extends Recipe {
void addToCraftingManager();
default Ingredient toNMS(RecipeChoice bukkit, boolean requireNotEmpty) {
+ // Paper start
+ return toIngredient(bukkit, requireNotEmpty);
+ }
+ static Ingredient toIngredient(RecipeChoice bukkit, boolean requireNotEmpty) {
+ // Paper end
Ingredient stack;
if (bukkit == null) {

View File

@@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 14 Mar 2022 12:35:37 -0700
Subject: [PATCH] Don't allow vehicle movement from players while teleporting
Bring the vehicle move packet behavior in line with the
regular player move packet.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
this.disconnect((Component) Component.translatable("multiplayer.disconnect.invalid_vehicle_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_VEHICLE_MOVEMENT); // Paper - kick event cause
} else if (!this.updateAwaitingTeleport()) {
Entity entity = this.player.getRootVehicle();
+ // Paper start - Don't allow vehicle movement from players while teleporting
+ if (this.awaitingPositionFromClient != null || this.player.isImmobile() || entity.isRemoved()) {
+ return;
+ }
+ // Paper end - Don't allow vehicle movement from players while teleporting
if (entity != this.player && entity.getControllingPassenger() == this.player && entity == this.lastVehicle) {
ServerLevel worldserver = this.player.serverLevel();

View File

@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Thu, 31 Mar 2022 05:11:37 -0700
Subject: [PATCH] Ensure entity passenger world matches ridden entity
Bad plugins doing this would cause some obvious problems...
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public boolean startRiding(Entity entity, boolean force) {
- if (entity == this.vehicle) {
+ if (entity == this.vehicle || entity.level != this.level) { // Paper - Ensure entity passenger world matches ridden entity (bad plugins)
return false;
} else if (!entity.couldAcceptPassenger()) {
return false;

View File

@@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 24 Oct 2021 20:58:43 -0700
Subject: [PATCH] Entity powdered snow API
== AT ==
public net.minecraft.world.entity.monster.Skeleton inPowderSnowTime
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -0,0 +0,0 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
}
// Paper end - raw entity serialization API
+ // Paper start - entity powdered snow API
+ @Override
+ public boolean isInPowderedSnow() {
+ return getHandle().isInPowderSnow || getHandle().wasInPowderSnow; // depending on the location in the entity "tick" either could be needed.
+ }
+ // Paper end - entity powdered snow API
+
// Paper start - missing entity api
@Override
public boolean isInvisible() { // Paper - moved up from LivingEntity
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSkeleton.java
@@ -0,0 +0,0 @@ public class CraftSkeleton extends CraftAbstractSkeleton implements Skeleton {
public SkeletonType getSkeletonType() {
return SkeletonType.NORMAL;
}
+
+ // Paper start
+ @Override
+ public int inPowderedSnowTime() {
+ return getHandle().inPowderSnowTime;
+ }
+ // Paper end
}

View File

@@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 28 Dec 2021 07:19:01 -0800
Subject: [PATCH] Execute chunk tasks fairly for worlds while waiting for next
tick
Currently, only the first world would have had tasks executed.
This might result in chunks loading far slower in the nether,
for example.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (super.pollTask()) {
return true;
} else {
+ boolean ret = false; // Paper - force execution of all worlds, do not just bias the first
if (this.tickRateManager.isSprinting() || this.haveTime()) {
Iterator iterator = this.getAllLevels().iterator();
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
ServerLevel worldserver = (ServerLevel) iterator.next();
if (worldserver.getChunkSource().pollTask()) {
- return true;
+ ret = true; // Paper - force execution of all worlds, do not just bias the first
}
}
}
- return false;
+ return ret; // Paper - force execution of all worlds, do not just bias the first
}
}

View File

@@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: HexedHero <6012891+HexedHero@users.noreply.github.com>
Date: Sun, 10 Apr 2022 06:26:32 +0100
Subject: [PATCH] Expand PlayerItemDamageEvent
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -0,0 +0,0 @@ public final class ItemStack implements DataComponentHolder {
if (this.isDamageableItem()) {
if (player == null || !player.hasInfiniteMaterials()) {
if (amount > 0) {
+ int originalDamage = amount; // Paper - Expand PlayerItemDamageEvent
amount = EnchantmentHelper.processDurabilityChange(world, this, amount);
// CraftBukkit start
if (player instanceof ServerPlayer serverPlayer) { // Paper - Add EntityDamageItemEvent
- PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), amount); // Paper - Add EntityDamageItemEvent
+ PlayerItemDamageEvent event = new PlayerItemDamageEvent(serverPlayer.getBukkitEntity(), CraftItemStack.asCraftMirror(this), amount, originalDamage); // Paper - Add EntityDamageItemEvent & Expand PlayerItemDamageEvent
event.getPlayer().getServer().getPluginManager().callEvent(event);
if (amount != event.getDamage() || event.isCancelled()) {

View File

@@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: EpicKnarvik97 <kristian.knarvik@knett.no>
Date: Sat, 5 Mar 2022 20:58:46 +0100
Subject: [PATCH] Expose furnace minecart push values
Adds methods for getting and setting a furnace minecart's push values
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartFurnace.java
@@ -0,0 +0,0 @@ public class CraftMinecartFurnace extends CraftMinecart implements PoweredMineca
this.getHandle().fuel = fuel;
}
+ // Paper start
+ @Override
+ public double getPushX() {
+ return getHandle().xPush;
+ }
+
+ @Override
+ public double getPushZ() {
+ return getHandle().zPush;
+ }
+
+ @Override
+ public void setPushX(double xPush) {
+ getHandle().xPush = xPush;
+ }
+
+ @Override
+ public void setPushZ(double zPush) {
+ getHandle().zPush = zPush;
+ }
+ // Paper end
+
@Override
public String toString() {
return "CraftMinecartFurnace";

View File

@@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <blake.galbreath@gmail.com>
Date: Thu, 23 Dec 2021 15:32:50 -0600
Subject: [PATCH] Expose isFuel and canSmelt methods to FurnaceInventory
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryFurnace.java
@@ -0,0 +0,0 @@ public class CraftInventoryFurnace extends CraftInventory implements FurnaceInve
this.setItem(0, stack);
}
+ // Paper start
+ @Override
+ public boolean isFuel(ItemStack stack) {
+ return stack != null && !stack.getType().isEmpty() && AbstractFurnaceBlockEntity.isFuel(CraftItemStack.asNMSCopy(stack));
+ }
+
+ @Override
+ public boolean canSmelt(ItemStack stack) {
+ // data packs are always loaded in the main world
+ net.minecraft.server.level.ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorlds().get(0)).getHandle();
+ return stack != null && !stack.getType().isEmpty() && world.getRecipeManager().getRecipeFor(((AbstractFurnaceBlockEntity) this.inventory).recipeType, new net.minecraft.world.item.crafting.SingleRecipeInput(CraftItemStack.asNMSCopy(stack)), world).isPresent();
+ }
+ // Paper end
+
@Override
public Furnace getHolder() {
return (Furnace) this.inventory.getOwner();

View File

@@ -1,177 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Thu, 6 Jan 2022 15:59:06 -0800
Subject: [PATCH] Expose vanilla BiomeProvider from WorldInfo
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
List<CustomSpawner> list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(iworlddataserver));
LevelStem worlddimension = (LevelStem) dimensions.get(dimensionKey);
- org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value());
+ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value(), worlddimension.generator(), this.registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo
if (biomeProvider == null && gen != null) {
biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
this.serverLevelData.setWorld(this);
if (biomeProvider != null) {
- BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().registryOrThrow(Registries.BIOME));
+ BiomeSource worldChunkManager = new CustomWorldChunkManager(this.getWorld(), biomeProvider, this.server.registryAccess().registryOrThrow(Registries.BIOME), chunkgenerator.getBiomeSource()); // Paper - add vanillaBiomeProvider
if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) {
chunkgenerator = new NoiseBasedChunkGenerator(worldChunkManager, cga.settings);
} else if (chunkgenerator instanceof FlatLevelSource cpf) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
List<CustomSpawner> list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata));
LevelStem worlddimension = iregistry.get(actualDimension);
- WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), worlddimension.type().value());
+ WorldInfo worldInfo = new CraftWorldInfo(worlddata, worldSession, creator.environment(), worlddimension.type().value(), worlddimension.generator(), this.getHandle().getServer().registryAccess()); // Paper - Expose vanilla BiomeProvider from WorldInfo
if (biomeProvider == null && generator != null) {
biomeProvider = generator.getDefaultBiomeProvider(worldInfo);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public int getPlayerCount() {
return world.players().size();
}
+
+ @Override
+ public BiomeProvider vanillaBiomeProvider() {
+ net.minecraft.server.level.ServerChunkCache serverCache = this.getHandle().chunkSource;
+
+ final net.minecraft.world.level.chunk.ChunkGenerator gen = serverCache.getGenerator();
+ net.minecraft.world.level.biome.BiomeSource biomeSource;
+ if (gen instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator custom) {
+ biomeSource = custom.getDelegate().getBiomeSource();
+ } else {
+ biomeSource = gen.getBiomeSource();
+ }
+ if (biomeSource instanceof org.bukkit.craftbukkit.generator.CustomWorldChunkManager customBiomeSource) {
+ biomeSource = customBiomeSource.vanillaBiomeSource;
+ }
+ final net.minecraft.world.level.biome.BiomeSource finalBiomeSource = biomeSource;
+ final net.minecraft.world.level.biome.Climate.Sampler sampler = serverCache.randomState().sampler();
+
+ final List<Biome> possibleBiomes = finalBiomeSource.possibleBiomes().stream()
+ .map(CraftBiome::minecraftHolderToBukkit)
+ .toList();
+ return new BiomeProvider() {
+ @Override
+ public Biome getBiome(final org.bukkit.generator.WorldInfo worldInfo, final int x, final int y, final int z) {
+ return CraftBiome.minecraftHolderToBukkit(finalBiomeSource.getNoiseBiome(x >> 2, y >> 2, z >> 2, sampler));
+ }
+
+ @Override
+ public List<Biome> getBiomes(final org.bukkit.generator.WorldInfo worldInfo) {
+ return possibleBiomes;
+ }
+ };
+ }
// Paper end
private static final Random rand = new Random();
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftWorldInfo.java
@@ -0,0 +0,0 @@ public class CraftWorldInfo implements WorldInfo {
private final long seed;
private final int minHeight;
private final int maxHeight;
+ // Paper start
+ private final net.minecraft.world.level.chunk.ChunkGenerator vanillaChunkGenerator;
+ private final net.minecraft.core.RegistryAccess.Frozen registryAccess;
- public CraftWorldInfo(ServerLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager) {
+ public CraftWorldInfo(PrimaryLevelData worldDataServer, LevelStorageSource.LevelStorageAccess session, World.Environment environment, DimensionType dimensionManager, net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator, net.minecraft.core.RegistryAccess.Frozen registryAccess) {
+ this.registryAccess = registryAccess;
+ this.vanillaChunkGenerator = chunkGenerator;
+ // Paper end
this.name = worldDataServer.getLevelName();
this.uuid = WorldUUID.getUUID(session.levelDirectory.path().toFile());
this.environment = environment;
@@ -0,0 +0,0 @@ public class CraftWorldInfo implements WorldInfo {
this.maxHeight = dimensionManager.minY() + dimensionManager.height();
}
- public CraftWorldInfo(String name, UUID uuid, World.Environment environment, long seed, int minHeight, int maxHeight) {
- this.name = name;
- this.uuid = uuid;
- this.environment = environment;
- this.seed = seed;
- this.minHeight = minHeight;
- this.maxHeight = maxHeight;
- }
-
@Override
public String getName() {
return this.name;
@@ -0,0 +0,0 @@ public class CraftWorldInfo implements WorldInfo {
public int getMaxHeight() {
return this.maxHeight;
}
+
+ // Paper start
+ @Override
+ public org.bukkit.generator.BiomeProvider vanillaBiomeProvider() {
+ final net.minecraft.world.level.levelgen.RandomState randomState;
+ if (vanillaChunkGenerator instanceof net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
+ randomState = net.minecraft.world.level.levelgen.RandomState.create(noiseBasedChunkGenerator.generatorSettings().value(),
+ registryAccess.lookupOrThrow(net.minecraft.core.registries.Registries.NOISE), getSeed());
+ } else {
+ randomState = net.minecraft.world.level.levelgen.RandomState.create(net.minecraft.world.level.levelgen.NoiseGeneratorSettings.dummy(),
+ registryAccess.lookupOrThrow(net.minecraft.core.registries.Registries.NOISE), getSeed());
+ }
+
+ final java.util.List<org.bukkit.block.Biome> possibleBiomes = CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().possibleBiomes().stream()
+ .map(biome -> org.bukkit.craftbukkit.block.CraftBiome.minecraftHolderToBukkit(biome))
+ .toList();
+ return new org.bukkit.generator.BiomeProvider() {
+ @Override
+ public org.bukkit.block.Biome getBiome(final WorldInfo worldInfo, final int x, final int y, final int z) {
+ return org.bukkit.craftbukkit.block.CraftBiome.minecraftHolderToBukkit(
+ CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().getNoiseBiome(x >> 2, y >> 2, z >> 2, randomState.sampler()));
+ }
+
+ @Override
+ public java.util.List<org.bukkit.block.Biome> getBiomes(final org.bukkit.generator.WorldInfo worldInfo) {
+ return possibleBiomes;
+ }
+ };
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomWorldChunkManager.java
@@ -0,0 +0,0 @@ public class CustomWorldChunkManager extends BiomeSource {
return biomeBases;
}
- public CustomWorldChunkManager(WorldInfo worldInfo, BiomeProvider biomeProvider, Registry<net.minecraft.world.level.biome.Biome> registry) {
+ // Paper start - add vanillaBiomeProvider
+ public final BiomeSource vanillaBiomeSource;
+ public CustomWorldChunkManager(WorldInfo worldInfo, BiomeProvider biomeProvider, Registry<net.minecraft.world.level.biome.Biome> registry, BiomeSource vanillaBiomeSource) {
+ this.vanillaBiomeSource = vanillaBiomeSource;
+ // Paper end - add vanillaBiomeProvider
this.worldInfo = worldInfo;
this.biomeProvider = biomeProvider;
this.registry = registry;

View File

@@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gero <gecam59@gmail.com>
Date: Sat, 2 Oct 2021 20:08:30 +0200
Subject: [PATCH] Fix CME in CraftPersistentDataTypeRegistry
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataTypeRegistry.java
@@ -0,0 +0,0 @@ public final class CraftPersistentDataTypeRegistry {
}
}
- private final Map<Class, TagAdapter> adapters = new HashMap<>();
+ private final Map<Class, TagAdapter> adapters = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - Replace HashMap with ConcurrentHashMap to avoid CME
/**
* Creates a suitable adapter instance for the primitive class type.

View File

@@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: etil2jz <blanchot.arthur@protonmail.ch>
Date: Sat, 2 Apr 2022 23:29:24 +0200
Subject: [PATCH] Fix NBT pieces overriding a block entity during worldgen
deadlock
By checking if the world passed into StructureTemplate's placeInWorld
is not a WorldGenRegion, we can bypass the deadlock entirely.
See https://bugs.mojang.com/browse/MC-246262
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
@@ -0,0 +0,0 @@ public class StructureTemplate {
if (definedstructure_blockinfo.nbt != null) {
tileentity = world.getBlockEntity(blockposition2);
- Clearable.tryClear(tileentity);
+ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock
+ if (!(world instanceof net.minecraft.world.level.WorldGenLevel)) {
+ Clearable.tryClear(tileentity);
+ }
+ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock
world.setBlock(blockposition2, Blocks.BARRIER.defaultBlockState(), 20);
}
// CraftBukkit start
@@ -0,0 +0,0 @@ public class StructureTemplate {
if (pair1.getSecond() != null) {
tileentity = world.getBlockEntity(blockposition6);
if (tileentity != null) {
- tileentity.setChanged();
+ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock
+ if (!(world instanceof net.minecraft.world.level.WorldGenLevel)) {
+ tileentity.setChanged();
+ }
+ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock
}
}
}

View File

@@ -1,54 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kieran Wallbanks <kieran.wallbanks@gmail.com>
Date: Mon, 21 Jun 2021 14:23:50 +0100
Subject: [PATCH] Fix NotePlayEvent
== AT ==
public org.bukkit.craftbukkit.block.data.CraftBlockData toNMS(Ljava/lang/Enum;Ljava/lang/Class;)Ljava/lang/Enum;
diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
@@ -0,0 +0,0 @@ public class NoteBlock extends Block {
private void playNote(@Nullable Entity entity, BlockState state, Level world, BlockPos pos) {
if (((NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT)).worksAboveNoteBlock() || world.getBlockState(pos.above()).isAir()) {
// CraftBukkit start
- org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE));
- if (event.isCancelled()) {
- return;
- }
+ // org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(NoteBlock.INSTRUMENT), state.getValue(NoteBlock.NOTE));
+ // if (event.isCancelled()) {
+ // return;
+ // }
// CraftBukkit end
+ // Paper - move NotePlayEvent call to fix instrument/note changes; TODO any way to cancel the game event?
world.blockEvent(pos, this, 0, 0);
world.gameEvent(entity, (Holder) GameEvent.NOTE_BLOCK_PLAY, pos);
}
@@ -0,0 +0,0 @@ public class NoteBlock extends Block {
@Override
protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
NoteBlockInstrument blockpropertyinstrument = (NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT);
+ // Paper start - move NotePlayEvent call to fix instrument/note changes
+ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, blockpropertyinstrument, state.getValue(NOTE));
+ if (event.isCancelled()) return false;
+ // Paper end - move NotePlayEvent call to fix instrument/note changes
float f;
if (blockpropertyinstrument.isTunable()) {
- int k = (Integer) state.getValue(NoteBlock.NOTE);
+ int k = event.getNote().getId(); // Paper - move NotePlayEvent call to fix instrument/note changes
f = NoteBlock.getPitchFromNote(k);
world.addParticle(ParticleTypes.NOTE, (double) pos.getX() + 0.5D, (double) pos.getY() + 1.2D, (double) pos.getZ() + 0.5D, (double) k / 24.0D, 0.0D, 0.0D);
@@ -0,0 +0,0 @@ public class NoteBlock extends Block {
holder = Holder.direct(SoundEvent.createVariableRangeEvent(minecraftkey));
} else {
- holder = blockpropertyinstrument.getSoundEvent();
+ holder = org.bukkit.craftbukkit.block.data.CraftBlockData.toNMS(event.getInstrument(), NoteBlockInstrument.class).getSoundEvent(); // Paper - move NotePlayEvent call to fix instrument/note changes
}
world.playSeededSound((Player) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, holder, SoundSource.RECORDS, 3.0F, f, world.random.nextLong());

View File

@@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 8 Oct 2021 13:12:58 -0700
Subject: [PATCH] Fix cancelled powdered snow bucket placement
Cancelling the placement of powdered snow from the powdered
snow bucket didn't revert grass that became snowy because of the
placement.
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -0,0 +0,0 @@ public final class ItemStack implements DataComponentHolder {
int oldCount = this.getCount();
ServerLevel world = (ServerLevel) context.getLevel();
- if (!(item instanceof BucketItem || item instanceof SolidBucketItem)) { // if not bucket
+ if (!(item instanceof BucketItem/* || item instanceof SolidBucketItem*/)) { // if not bucket // Paper - Fix cancelled powdered snow bucket placement
world.captureBlockStates = true;
// special case bonemeal
if (item == Items.BONE_MEAL) {
@@ -0,0 +0,0 @@ public final class ItemStack implements DataComponentHolder {
world.capturedBlockStates.clear();
if (blocks.size() > 1) {
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, enumhand, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ());
- } else if (blocks.size() == 1) {
+ } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, enumhand, blocks.get(0), blockposition.getX(), blockposition.getY(), blockposition.getZ());
}

View File

@@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 19 Feb 2022 19:05:59 -0800
Subject: [PATCH] Fix cancelling ProjectileHitEvent for piercing arrows
Piercing arrows search for multiple entities inside a while
loop that is checking the projectile entity's removed state.
If the hit event is cancelled on the first entity, the event will
be called over and over again inside that while loop until the event
is not cancelled. The solution here, is to make use of an
already-existing field on AbstractArrow for tracking entities hit by
piercing arrows to avoid duplicate damage being applied.
== AT ==
protected net.minecraft.world.entity.projectile.Projectile hitCancelled
diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -0,0 +0,0 @@ public abstract class AbstractArrow extends Projectile {
}
}
+ // Paper start - Fix cancelling ProjectileHitEvent for piercing arrows
+ @Override
+ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult hitResult) {
+ if (hitResult instanceof EntityHitResult entityHitResult && this.hitCancelled && this.getPierceLevel() > 0) {
+ if (this.piercingIgnoreEntityIds == null) {
+ this.piercingIgnoreEntityIds = new IntOpenHashSet(5);
+ }
+ this.piercingIgnoreEntityIds.add(entityHitResult.getEntity().getId());
+ }
+ return super.preHitTargetOrDeflectSelf(hitResult);
+ }
+ // Paper end - Fix cancelling ProjectileHitEvent for piercing arrows
+
@Override
protected double getDefaultGravity() {
return 0.05D;

View File

@@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Fri, 4 Mar 2022 20:35:19 +0100
Subject: [PATCH] Fix falling block spawn methods
Restores the API behavior from previous versions of the server
- Do not call API events
- Do not replace the existing block in the world
== AT ==
public net.minecraft.world.entity.item.FallingBlockEntity <init>(Lnet/minecraft/world/level/Level;DDDLnet/minecraft/world/level/block/state/BlockState;)V
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
Preconditions.checkArgument(material != null, "Material cannot be null");
Preconditions.checkArgument(material.isBlock(), "Material.%s must be a block", material);
- FallingBlockEntity entity = FallingBlockEntity.fall(this.world, BlockPos.containing(location.getX(), location.getY(), location.getZ()), CraftBlockType.bukkitToMinecraft(material).defaultBlockState(), SpawnReason.CUSTOM);
+ // Paper start - restore API behavior for spawning falling blocks
+ FallingBlockEntity entity = new FallingBlockEntity(this.world, location.getX(), location.getY(), location.getZ(), CraftBlockType.bukkitToMinecraft(material).defaultBlockState()); // Paper
+ entity.time = 1;
+
+ this.world.addFreshEntity(entity, SpawnReason.CUSTOM);
+ // Paper end - restore API behavior for spawning falling blocks
return (FallingBlock) entity.getBukkitEntity();
}
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
Preconditions.checkArgument(location != null, "Location cannot be null");
Preconditions.checkArgument(data != null, "BlockData cannot be null");
- FallingBlockEntity entity = FallingBlockEntity.fall(this.world, BlockPos.containing(location.getX(), location.getY(), location.getZ()), ((CraftBlockData) data).getState(), SpawnReason.CUSTOM);
+ // Paper start - restore API behavior for spawning falling blocks
+ FallingBlockEntity entity = new FallingBlockEntity(this.world, location.getX(), location.getY(), location.getZ(), ((CraftBlockData) data).getState());
+ entity.time = 1;
+
+ this.world.addFreshEntity(entity, SpawnReason.CUSTOM);
+ // Paper end - restore API behavior for spawning falling blocks
return (FallingBlock) entity.getBukkitEntity();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
@@ -0,0 +0,0 @@ public final class CraftEntityTypes {
register(new EntityTypeData<>(EntityType.TNT, TNTPrimed.class, CraftTNTPrimed::new, spawnData -> new PrimedTnt(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null)));
register(new EntityTypeData<>(EntityType.FALLING_BLOCK, FallingBlock.class, CraftFallingBlock::new, spawnData -> {
BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z());
- return FallingBlockEntity.fall(spawnData.minecraftWorld(), pos, spawnData.world().getBlockState(pos));
+ return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly
}));
register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), net.minecraft.world.item.ItemStack.EMPTY)));
register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null)));

View File

@@ -1,215 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: SoSeDiK <mrsosedik@gmail.com>
Date: Mon, 21 Mar 2022 20:00:53 +0200
Subject: [PATCH] Fix new block data for EntityChangeBlockEvent
Also standardizes how to handle EntityChangeBlockEvent before a removeBlock or destroyBlock
call. Always use 'state.getFluidState().createLegacyBlock()' to get the new state instead of
just using the 'air' state.
Also fixes the new block data for EntityBreakDoorEvent (a sub-event from
EntityChangeBlockEvent)
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java
@@ -0,0 +0,0 @@ public class HarvestFarmland extends Behavior<Villager> {
Block block1 = world.getBlockState(this.aboveFarmlandPos.below()).getBlock();
if (block instanceof CropBlock && ((CropBlock) block).isMaxAge(iblockdata)) {
- if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, Blocks.AIR.defaultBlockState())) { // CraftBukkit
+ if (CraftEventFactory.callEntityChangeBlockEvent(entity, this.aboveFarmlandPos, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit // Paper - fix wrong block state
world.destroyBlock(this.aboveFarmlandPos, true, entity);
} // CraftBukkit
}
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/BreakDoorGoal.java
@@ -0,0 +0,0 @@ public class BreakDoorGoal extends DoorInteractGoal {
if (this.breakTime == this.getDoorBreakTime() && this.isValidDifficulty(this.mob.level().getDifficulty())) {
// CraftBukkit start
- if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.mob, this.doorPos).isCancelled()) {
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreakDoorEvent(this.mob, this.doorPos, this.mob.level().getFluidState(this.doorPos).createLegacyBlock()).isCancelled()) { // Paper - fix wrong block state
this.start();
return;
}
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
@@ -0,0 +0,0 @@ public class EatBlockGoal extends Goal {
if (this.eatAnimationTick == this.adjustedTickDelay(4)) {
BlockPos blockposition = this.mob.blockPosition();
- if (EatBlockGoal.IS_TALL_GRASS.test(this.level.getBlockState(blockposition))) {
- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, Blocks.AIR.defaultBlockState(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit
+ final BlockState blockState = this.level.getBlockState(blockposition); // Paper - fix wrong block state
+ if (EatBlockGoal.IS_TALL_GRASS.test(blockState)) { // Paper - fix wrong block state
+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, blockState.getFluidState().createLegacyBlock(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - fix wrong block state
this.level.destroyBlock(blockposition, false);
}
@@ -0,0 +0,0 @@ public class EatBlockGoal extends Goal {
BlockPos blockposition1 = blockposition.below();
if (this.level.getBlockState(blockposition1).is(Blocks.GRASS_BLOCK)) {
- if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.AIR.defaultBlockState(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit
+ if (CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Paper - Fix wrong block state
this.level.levelEvent(2001, blockposition1, Block.getId(Blocks.GRASS_BLOCK.defaultBlockState()));
this.level.setBlock(blockposition1, Blocks.DIRT.defaultBlockState(), 2);
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Rabbit.java
@@ -0,0 +0,0 @@ public class Rabbit extends Animal implements VariantHolder<Rabbit.Variant> {
if (i == 0) {
// CraftBukkit start
- if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, Blocks.AIR.defaultBlockState())) {
+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.rabbit, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
return;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
@@ -0,0 +0,0 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob
if (WitherBoss.canDestroy(iblockdata)) {
// CraftBukkit start
- if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, Blocks.AIR.defaultBlockState())) {
+ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
continue;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
@@ -0,0 +0,0 @@ public class EnderMan extends Monster implements NeutralMob {
boolean flag = movingobjectpositionblock.getBlockPos().equals(blockposition);
if (iblockdata.is(BlockTags.ENDERMAN_HOLDABLE) && flag) {
- if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, Blocks.AIR.defaultBlockState())) { // CraftBukkit - Place event
+ if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit - Place event // Paper - fix wrong block state
world.removeBlock(blockposition, false);
world.gameEvent((Holder) GameEvent.BLOCK_DESTROY, blockposition, GameEvent.Context.of(this.enderman, iblockdata));
this.enderman.setCarriedBlock(iblockdata.getBlock().defaultBlockState());
diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
@@ -0,0 +0,0 @@ public class Ravager extends Raider {
if (block instanceof LeavesBlock) {
// CraftBukkit start
- if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) {
+ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
continue;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
@@ -0,0 +0,0 @@ public class Silverfish extends Monster {
if (block instanceof InfestedBlock) {
// CraftBukkit start
- if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState())) {
+ BlockState afterState = world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? iblockdata.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1)); // Paper - fix wrong block state
+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, afterState)) { // Paper - fix wrong block state
continue;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
@@ -0,0 +0,0 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
if (iblockdata.is(BlockTags.FIRE)) {
// CraftBukkit start
- if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, Blocks.AIR.defaultBlockState())) {
+ if (CraftEventFactory.callEntityChangeBlockEvent(this, pos, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
this.level().destroyBlock(pos, false, this);
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java b/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ChorusFlowerBlock.java
@@ -0,0 +0,0 @@ public class ChorusFlowerBlock extends Block {
if (!world.isClientSide && projectile.mayInteract(world, blockposition) && projectile.mayBreak(world)) {
// CraftBukkit
- if (!CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState())) {
+ if (!CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
return;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/PointedDripstoneBlock.java
@@ -0,0 +0,0 @@ public class PointedDripstoneBlock extends Block implements Fallable, SimpleWate
if (projectile.mayInteract(world, blockposition) && projectile.mayBreak(world) && projectile instanceof ThrownTrident && projectile.getDeltaMovement().length() > 0.6D) {
// CraftBukkit start
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState())) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
return;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/block/TntBlock.java b/src/main/java/net/minecraft/world/level/block/TntBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/TntBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TntBlock.java
@@ -0,0 +0,0 @@ public class TntBlock extends Block {
if (projectile.isOnFire() && projectile.mayInteract(world, blockposition)) {
// CraftBukkit start
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState()) || !CraftEventFactory.callTNTPrimeEvent(world, blockposition, PrimeCause.PROJECTILE, projectile, null)) {
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock()) || !CraftEventFactory.callTNTPrimeEvent(world, blockposition, PrimeCause.PROJECTILE, projectile, null)) { // Paper - fix wrong block state
return;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java
@@ -0,0 +0,0 @@ public class WaterlilyBlock extends BushBlock {
if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
if (world instanceof ServerLevel && entity instanceof Boat) {
// CraftBukkit start
- if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState())) {
+ if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state
return;
}
// CraftBukkit end
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -0,0 +0,0 @@ public class CraftEventFactory {
return event;
}
- public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos) {
+ public static EntityBreakDoorEvent callEntityBreakDoorEvent(Entity entity, BlockPos pos, net.minecraft.world.level.block.state.BlockState newState) { // Paper
org.bukkit.entity.Entity entity1 = entity.getBukkitEntity();
Block block = CraftBlock.at(entity.level(), pos);
- EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block);
+ EntityBreakDoorEvent event = new EntityBreakDoorEvent((LivingEntity) entity1, block, newState.createCraftBlockData()); // Paper
entity1.getServer().getPluginManager().callEvent(event);
return event;

View File

@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Philip Kelley <philip@thoriumcube.org>
Date: Wed, 16 Mar 2022 12:05:59 +0000
Subject: [PATCH] Fix saving in unloadWorld
Change savingDisabled to false to ensure ServerLevel's saving logic gets called when unloadWorld is called with save = true
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
try {
if (save) {
- handle.save(null, true, true);
+ handle.save(null, true, false); // Paper - Fix saving in unloadWorld
}
handle.getChunkSource().close(save);

View File

@@ -1,85 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 22 Dec 2021 09:51:48 -0800
Subject: [PATCH] Fix sticky pistons and BlockPistonRetractEvent
There is an explicit check in the handling code for empty pistons that
prevents sticky pistons from firing the event. However when we look back
at the history we see that this check was originally added so that ONLY
sticky pistons would fire the retract event. I'm not sure why.
https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1092acbddf07edfa4100bc6824504ac75088e913
Over the course of several updates, the meaning of that field appears to
have changed from "is NOT sticky" to "is sticky". So now its having the
opposite effect. Only normal pistons fire the retraction event. And like
all things in CB, it's just been carried around since.
If we are to believe the history, the correct fix for this issue is to
flip it so it only fires for sticky pistons, but that puts us in a
bind. It's already firing for non-sticky pistons, changing it now would
likely result in breakage. Furthermore, there is little documentation as
to WHY that was ever intended to be the case.
Instead we opt to remove the check entirely so that the event fires for
all piston types.
Co-authored-by: Zach Brown <1254957+zachbr@users.noreply.github.com>
Co-authored-by: Madeline Miller <mnmiller1@me.com>
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -0,0 +0,0 @@ public class PistonBaseBlock extends DirectionalBlock {
}
// CraftBukkit start
- if (!this.isSticky) {
- org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
- BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.<org.bukkit.block.Block>of(), CraftBlock.notchToBlockFace(enumdirection));
- world.getCraftServer().getPluginManager().callEvent(event);
-
- if (event.isCancelled()) {
- return;
- }
- }
+ // if (!this.isSticky) { // Paper - Fix sticky pistons and BlockPistonRetractEvent; Move further down
+ // org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
+ // BlockPistonRetractEvent event = new BlockPistonRetractEvent(block, ImmutableList.<org.bukkit.block.Block>of(), CraftBlock.notchToBlockFace(enumdirection));
+ // world.getCraftServer().getPluginManager().callEvent(event);
+ //
+ // if (event.isCancelled()) {
+ // return;
+ // }
+ // }
// PAIL: checkME - what happened to setTypeAndData?
// CraftBukkit end
world.blockEvent(pos, this, b0, enumdirection.get3DDataValue());
@@ -0,0 +0,0 @@ public class PistonBaseBlock extends DirectionalBlock {
BlockState iblockdata2 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
+ // Paper start - Fix sticky pistons and BlockPistonRetractEvent; Move empty piston retract call to fix multiple event fires
+ if (!this.isSticky) {
+ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) {
+ return false;
+ }
+ }
+ // Paper end - Fix sticky pistons and BlockPistonRetractEvent
world.setBlock(pos, iblockdata2, 20);
world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata2, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true));
world.blockUpdated(pos, iblockdata2.getBlock());
@@ -0,0 +0,0 @@ public class PistonBaseBlock extends DirectionalBlock {
if (type == 1 && !iblockdata3.isAir() && PistonBaseBlock.isPushable(iblockdata3, world, blockposition1, enumdirection.getOpposite(), false, enumdirection) && (iblockdata3.getPistonPushReaction() == PushReaction.NORMAL || iblockdata3.is(Blocks.PISTON) || iblockdata3.is(Blocks.STICKY_PISTON))) {
this.moveBlocks(world, pos, enumdirection, false);
} else {
+ // Paper start - Fix sticky pistons and BlockPistonRetractEvent; fire BlockPistonRetractEvent for sticky pistons retracting nothing (air)
+ if (type == TRIGGER_CONTRACT && iblockdata2.isAir()) {
+ if (!new BlockPistonRetractEvent(CraftBlock.at(world, pos), java.util.Collections.emptyList(), CraftBlock.notchToBlockFace(enumdirection)).callEvent()) {
+ return false;
+ }
+ }
+ // Paper end - Fix sticky pistons and BlockPistonRetractEvent
world.removeBlock(pos.relative(enumdirection), false);
}
}

View File

@@ -1,64 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 12 Mar 2022 06:31:13 -0800
Subject: [PATCH] Fix swamp hut cat generation deadlock
The worldgen thread will attempt to get structure references
via the world's getChunkAt method, which is fine if the gen is
not cancelled - but if the chunk was unloaded, the call will block
indefinitely. Instead of using the world state, we use the already
supplied ServerLevelAccessor which will always have the chunk available.
diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Cat.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java
@@ -0,0 +0,0 @@ public class Cat extends TamableAnimal implements VariantHolder<Holder<CatVarian
BuiltInRegistries.CAT_VARIANT.getRandomElementOf(tagkey, world.getRandom()).ifPresent(this::setVariant);
ServerLevel worldserver = world.getLevel();
- if (worldserver.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK).isValid()) {
+ if (worldserver.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK, world).isValid()) { // Paper - Fix swamp hut cat generation deadlock
this.setVariant((Holder) BuiltInRegistries.CAT_VARIANT.getHolderOrThrow(CatVariant.ALL_BLACK));
this.setPersistenceRequired();
}
diff --git a/src/main/java/net/minecraft/world/level/StructureManager.java b/src/main/java/net/minecraft/world/level/StructureManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/StructureManager.java
+++ b/src/main/java/net/minecraft/world/level/StructureManager.java
@@ -0,0 +0,0 @@ public class StructureManager {
}
public List<StructureStart> startsForStructure(ChunkPos pos, Predicate<Structure> predicate) {
- Map<Structure, LongSet> map = this.level.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
+ // Paper start - Fix swamp hut cat generation deadlock
+ return this.startsForStructure(pos, predicate, null);
+ }
+ public List<StructureStart> startsForStructure(ChunkPos pos, Predicate<Structure> predicate, @Nullable ServerLevelAccessor levelAccessor) {
+ Map<Structure, LongSet> map = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences();
+ // Paper end - Fix swamp hut cat generation deadlock
Builder<StructureStart> builder = ImmutableList.builder();
for (Entry<Structure, LongSet> entry : map.entrySet()) {
@@ -0,0 +0,0 @@ public class StructureManager {
}
public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate<Holder<Structure>> predicate) {
+ // Paper start - Fix swamp hut cat generation deadlock
+ return this.getStructureWithPieceAt(pos, predicate, null);
+ }
+
+ public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey<Structure> tag, @Nullable ServerLevelAccessor levelAccessor) {
+ return this.getStructureWithPieceAt(pos, structure -> structure.is(tag), levelAccessor);
+ }
+
+ public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate<Holder<Structure>> predicate, @Nullable ServerLevelAccessor levelAccessor) {
+ // Paper end - Fix swamp hut cat generation deadlock
Registry<Structure> registry = this.registryAccess().registryOrThrow(Registries.STRUCTURE);
for (StructureStart structureStart : this.startsForStructure(
- new ChunkPos(pos), structure -> registry.getHolder(registry.getId(structure)).map(predicate::test).orElse(false)
+ new ChunkPos(pos), structure -> registry.getHolder(registry.getId(structure)).map(predicate::test).orElse(false), levelAccessor // Paper - Fix swamp hut cat generation deadlock
)) {
if (this.structureHasPieceAt(pos, structureStart)) {
return structureStart;

View File

@@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 16 Jan 2022 10:34:02 -0800
Subject: [PATCH] Fix xp reward for baby zombies
The field that tracks the xpReward was not
getting reset if the death was cancelled
so this resets it after each call to
Zombie#getExperienceReward
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
@@ -0,0 +0,0 @@ public class Zombie extends Monster {
@Override
protected int getBaseExperienceReward() {
+ final int previousReward = this.xpReward; // Paper - store previous value to reset after calculating XP reward
if (this.isBaby()) {
this.xpReward = (int) ((double) this.xpReward * 2.5D);
}
- return super.getBaseExperienceReward();
+ // Paper start - store previous value to reset after calculating XP reward
+ int reward = super.getBaseExperienceReward();
+ this.xpReward = previousReward;
+ return reward;
+ // Paper end - store previous value to reset after calculating XP reward
}
@Override

View File

@@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Wed, 2 Mar 2022 09:45:56 +0100
Subject: [PATCH] Force close world loading screen
Dead players would be stuck in the world loading screen and other players may
miss messages and similar sent in the join event if chunk loading is slow.
Paper already circumvents falling through the world before chunks are loaded,
so we do not need that. The client only needs the chunk it is currently in to
be loaded to close the loading screen, so we just send an empty one.
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -0,0 +0,0 @@ public abstract class PlayerList {
this.sendActivePlayerEffects(player);
// Paper start - Fire PlayerJoinEvent when Player is actually ready; move vehicle into method so it can be called above - short circuit around that code
this.onPlayerJoinFinish(player, worldserver1, s1);
+ // Paper start - Send empty chunk, so players aren't stuck in the world loading screen with our chunk system not sending chunks when dead
+ if (player.isDeadOrDying()) {
+ net.minecraft.core.Holder<net.minecraft.world.level.biome.Biome> plains = worldserver1.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME)
+ .getHolderOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
+ new net.minecraft.world.level.chunk.EmptyLevelChunk(worldserver1, player.chunkPosition(), plains),
+ worldserver1.getLightEngine(), (java.util.BitSet)null, (java.util.BitSet) null)
+ );
+ }
+ // Paper end - Send empty chunk
}
private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, Optional<CompoundTag> optional) {
// Paper end - Fire PlayerJoinEvent when Player is actually ready

View File

@@ -1,82 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 26 Dec 2021 20:27:43 -0500
Subject: [PATCH] Freeze Tick Lock API
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
private org.bukkit.util.Vector origin;
@javax.annotation.Nullable
private UUID originWorld;
+ public boolean freezeLocked = false; // Paper - Freeze Tick Lock API
public void setOrigin(@javax.annotation.Nonnull Location location) {
this.origin = location.toVector();
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.setRemainingFireTicks(this.remainingFireTicks - 1);
}
- if (this.getTicksFrozen() > 0) {
+ if (this.getTicksFrozen() > 0 && !freezeLocked) { // Paper - Freeze Tick Lock API
this.setTicksFrozen(0);
this.level().levelEvent((Player) null, 1009, this.blockPosition, 1);
}
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
if (fromNetherPortal) {
nbttagcompound.putBoolean("Paper.FromNetherPortal", true);
}
+ if (freezeLocked) {
+ nbttagcompound.putBoolean("Paper.FreezeLock", true);
+ }
// Paper end
return nbttagcompound;
} catch (Throwable throwable) {
@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
if (spawnReason == null) {
spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT;
}
+ if (nbt.contains("Paper.FreezeLock")) {
+ freezeLocked = nbt.getBoolean("Paper.FreezeLock");
+ }
// Paper end
} catch (Throwable throwable) {
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.level().getProfiler().pop();
this.level().getProfiler().push("freezing");
- if (!this.level().isClientSide && !this.isDeadOrDying()) {
+ if (!this.level().isClientSide && !this.isDeadOrDying() && !this.freezeLocked) { // Paper - Freeze Tick Lock API
int i = this.getTicksFrozen();
if (this.isInPowderSnow && this.canFreeze()) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -0,0 +0,0 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return this.getHandle().isFullyFrozen();
}
+ // Paper start - Freeze Tick Lock API
+ @Override
+ public boolean isFreezeTickingLocked() {
+ return this.entity.freezeLocked;
+ }
+
+ @Override
+ public void lockFreezeTicks(boolean locked) {
+ this.entity.freezeLocked = locked;
+ }
+ // Paper end - Freeze Tick Lock API
@Override
public void remove() {
this.entity.pluginRemoved = true;

View File

@@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 13 Jan 2022 15:20:47 -0800
Subject: [PATCH] Furnace RecipesUsed API
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftFurnace.java
@@ -0,0 +0,0 @@ public abstract class CraftFurnace<T extends AbstractFurnaceBlockEntity> extends
snapshot.cookSpeedMultiplier = multiplier;
snapshot.cookingTotalTime = AbstractFurnaceBlockEntity.getTotalCookTime(this.isPlaced() ? this.world.getHandle() : null, snapshot.recipeType, snapshot, snapshot.cookSpeedMultiplier); // Update the snapshot's current total cook time to scale with the newly set multiplier
}
+
+ @Override
+ public int getRecipeUsedCount(org.bukkit.NamespacedKey furnaceRecipe) {
+ return this.getSnapshot().getRecipesUsed().getInt(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(furnaceRecipe));
+ }
+
+ @Override
+ public boolean hasRecipeUsedCount(org.bukkit.NamespacedKey furnaceRecipe) {
+ return this.getSnapshot().getRecipesUsed().containsKey(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(furnaceRecipe));
+ }
+
+ @Override
+ public void setRecipeUsedCount(org.bukkit.inventory.CookingRecipe<?> furnaceRecipe, int count) {
+ final net.minecraft.resources.ResourceLocation location = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(furnaceRecipe.getKey());
+ java.util.Optional<net.minecraft.world.item.crafting.RecipeHolder<?>> nmsRecipe = (this.isPlaced() ? this.world.getHandle().getRecipeManager() : net.minecraft.server.MinecraftServer.getServer().getRecipeManager()).byKey(location);
+ com.google.common.base.Preconditions.checkArgument(nmsRecipe.isPresent() && nmsRecipe.get().value() instanceof net.minecraft.world.item.crafting.AbstractCookingRecipe, furnaceRecipe.getKey() + " is not recognized as a valid and registered furnace recipe");
+ if (count > 0) {
+ this.getSnapshot().getRecipesUsed().put(location, count);
+ } else {
+ this.getSnapshot().getRecipesUsed().removeInt(location);
+ }
+ }
+
+ @Override
+ public void setRecipesUsed(java.util.Map<org.bukkit.inventory.CookingRecipe<?>, Integer> recipesUsed) {
+ this.getSnapshot().getRecipesUsed().clear();
+ recipesUsed.forEach((recipe, integer) -> {
+ if (integer != null) {
+ this.setRecipeUsedCount(recipe, integer);
+ }
+ });
+ }
// Paper end
}

View File

@@ -1,58 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Wed, 16 Mar 2022 20:35:21 -0700
Subject: [PATCH] Implement enchantWithLevels API
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
@@ -0,0 +0,0 @@ public final class CraftItemFactory implements ItemFactory {
return eggItem == null ? null : new net.minecraft.world.item.ItemStack(eggItem).asBukkitMirror();
}
// Paper end - old getSpawnEgg API
+ // Paper start - enchantWithLevels API
+ @Override
+ public ItemStack enchantWithLevels(ItemStack itemStack, int levels, boolean allowTreasure, java.util.Random random) {
+ return enchantWithLevels(
+ itemStack,
+ levels,
+ allowTreasure
+ ? Optional.empty()
+ // While IN_ENCHANTING_TABLE is not logically the same as all but TREASURE, the tag is defined as
+ // NON_TREASURE, which does contain all enchantments not in the treasure tag.
+ // Additionally, the allowTreasure boolean is more intended to configure this method to behave like
+ // an enchanting table.
+ : net.minecraft.server.MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.ENCHANTMENT).getTag(EnchantmentTags.IN_ENCHANTING_TABLE),
+ random
+ );
+ }
+
+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+ private ItemStack enchantWithLevels(
+ ItemStack itemStack,
+ int levels,
+ Optional<? extends net.minecraft.core.HolderSet<net.minecraft.world.item.enchantment.Enchantment>> possibleEnchantments,
+ java.util.Random random
+ ) {
+ Preconditions.checkArgument(itemStack != null, "Argument 'itemStack' must not be null");
+ Preconditions.checkArgument(!itemStack.isEmpty(), "Argument 'itemStack' cannot be empty");
+ Preconditions.checkArgument(levels > 0 && levels <= 30, "Argument 'levels' must be in range [1, 30] (attempted " + levels + ")");
+ Preconditions.checkArgument(random != null, "Argument 'random' must not be null");
+ final net.minecraft.world.item.ItemStack internalStack = CraftItemStack.asNMSCopy(itemStack);
+ if (internalStack.isEnchanted()) {
+ internalStack.set(net.minecraft.core.component.DataComponents.ENCHANTMENTS, net.minecraft.world.item.enchantment.ItemEnchantments.EMPTY);
+ }
+ final net.minecraft.core.RegistryAccess registryAccess = net.minecraft.server.MinecraftServer.getServer().registryAccess();
+ final net.minecraft.world.item.ItemStack enchanted = net.minecraft.world.item.enchantment.EnchantmentHelper.enchantItem(
+ new org.bukkit.craftbukkit.util.RandomSourceWrapper(random),
+ internalStack,
+ levels,
+ registryAccess,
+ possibleEnchantments
+ );
+ return CraftItemStack.asCraftMirror(enchanted);
+ }
+ // Paper end - enchantWithLevels API
}

View File

@@ -1,61 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Mon, 14 Mar 2022 22:46:05 -0700
Subject: [PATCH] Implement getComputedBiome API
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -0,0 +0,0 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
return CraftBiome.minecraftHolderToBukkit(this.getHandle().getNoiseBiome(x >> 2, y >> 2, z >> 2));
}
+ // Paper start
+ @Override
+ public Biome getComputedBiome(int x, int y, int z) {
+ return CraftBiome.minecraftHolderToBukkit(this.getHandle().getBiome(new BlockPos(x, y, z)));
+ }
+ // Paper end
+
@Override
public void setBiome(Location location, Biome biome) {
this.setBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ(), biome);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -0,0 +0,0 @@ public class CraftBlock implements Block {
return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ());
}
+ // Paper start
+ @Override
+ public Biome getComputedBiome() {
+ return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ());
+ }
+ // Paper end
+
@Override
public void setBiome(Biome bio) {
this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio);
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
@@ -0,0 +0,0 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe
return super.getBiome(x, y, z);
}
+ // Paper start
+ @Override
+ public Biome getComputedBiome(int x, int y, int z) {
+ Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
+ return super.getComputedBiome(x, y, z);
+ }
+ // Paper end
+
@Override
public void setBiome(int x, int y, int z, Holder<net.minecraft.world.level.biome.Biome> biomeBase) {
Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);

View File

@@ -1,28 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 15 Mar 2022 01:38:15 -0700
Subject: [PATCH] Make some itemstacks nonnull
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
@@ -0,0 +0,0 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i
case OFF_HAND:
return this.getItemInOffHand();
case FEET:
- return this.getBoots();
+ return java.util.Objects.requireNonNullElseGet(this.getBoots(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull
case LEGS:
- return this.getLeggings();
+ return java.util.Objects.requireNonNullElseGet(this.getLeggings(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull
case CHEST:
- return this.getChestplate();
+ return java.util.Objects.requireNonNullElseGet(this.getChestplate(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull
case HEAD:
- return this.getHelmet();
+ return java.util.Objects.requireNonNullElseGet(this.getHelmet(), () -> new ItemStack(org.bukkit.Material.AIR)); // Paper - make nonnull
default:
throw new IllegalArgumentException("Not implemented. This is a bug");
}

View File

@@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brokkonaut <hannos17@gmx.de>
Date: Sat, 18 Dec 2021 08:26:55 +0100
Subject: [PATCH] Make water animal spawn height configurable
diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
+++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
@@ -0,0 +0,0 @@ public abstract class WaterAnimal extends PathfinderMob {
) {
int i = world.getSeaLevel();
int j = i - 13;
+ // Paper start - Make water animal spawn height configurable
+ i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i);
+ j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j);
+ // Paper end - Make water animal spawn height configurable
return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER);
}
}

View File

@@ -1,98 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 27 May 2021 21:58:24 -0700
Subject: [PATCH] More PotionEffectType API
== AT ==
public net.minecraft.world.effect.MobEffect attributeModifiers
public net.minecraft.world.effect.MobEffect$AttributeTemplate
diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java
+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionEffectType.java
@@ -0,0 +0,0 @@ public class CraftPotionEffectType extends PotionEffectType implements Handleabl
return this.handle.getDescriptionId();
}
+ // Paper start
+ @Override
+ public java.util.Map<org.bukkit.attribute.Attribute, org.bukkit.attribute.AttributeModifier> getEffectAttributes() {
+ // re-create map each time because a nms MobEffect can have its attributes modified
+ final java.util.Map<org.bukkit.attribute.Attribute, org.bukkit.attribute.AttributeModifier> attributeMap = new java.util.HashMap<>();
+ this.handle.attributeModifiers.forEach((attribute, attributeModifier) -> {
+ attributeMap.put(
+ org.bukkit.craftbukkit.attribute.CraftAttribute.minecraftHolderToBukkit(attribute),
+ // use zero as amplifier to get the base amount, as it is amount = base * (amplifier + 1)
+ org.bukkit.craftbukkit.attribute.CraftAttributeInstance.convert(attributeModifier.create(0))
+ );
+ });
+ return java.util.Map.copyOf(attributeMap);
+ }
+
+ @Override
+ public double getAttributeModifierAmount(org.bukkit.attribute.Attribute attribute, int effectAmplifier) {
+ com.google.common.base.Preconditions.checkArgument(effectAmplifier >= 0, "effectAmplifier must be greater than or equal to 0");
+ Holder<net.minecraft.world.entity.ai.attributes.Attribute> nmsAttribute = org.bukkit.craftbukkit.attribute.CraftAttribute.bukkitToMinecraftHolder(attribute);
+ com.google.common.base.Preconditions.checkArgument(this.handle.attributeModifiers.containsKey(nmsAttribute), attribute + " is not present on " + this.getKey());
+ return this.handle.attributeModifiers.get(nmsAttribute).create(effectAmplifier).amount();
+ }
+
+ @Override
+ public PotionEffectType.Category getEffectCategory() {
+ return fromNMS(handle.getCategory());
+ }
+
+ @Override
+ public String translationKey() {
+ return this.handle.getDescriptionId();
+ }
+
+ public static PotionEffectType.Category fromNMS(net.minecraft.world.effect.MobEffectCategory mobEffectInfo) {
+ return switch (mobEffectInfo) {
+ case BENEFICIAL -> PotionEffectType.Category.BENEFICIAL;
+ case HARMFUL -> PotionEffectType.Category.HARMFUL;
+ case NEUTRAL -> PotionEffectType.Category.NEUTRAL;
+ };
+ }
+ // Paper end
+
@Override
public boolean equals(Object other) {
if (this == other) {
diff --git a/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java b/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/test/java/io/papermc/paper/effects/EffectCategoryTest.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.effects;
+
+import io.papermc.paper.adventure.PaperAdventure;
+import net.minecraft.world.effect.MobEffectCategory;
+import org.bukkit.craftbukkit.potion.CraftPotionEffectType;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.support.environment.AllFeatures;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@AllFeatures
+public class EffectCategoryTest {
+
+ @Test
+ public void testEffectCategoriesExist() {
+ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) {
+ assertNotNull(CraftPotionEffectType.fromNMS(mobEffectInfo), mobEffectInfo + " is missing a bukkit equivalent");
+ }
+ }
+
+ @Test
+ public void testCategoryHasEquivalentColors() {
+ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) {
+ PotionEffectType.Category bukkitEffectCategory = CraftPotionEffectType.fromNMS(mobEffectInfo);
+ assertEquals(bukkitEffectCategory.getColor(), PaperAdventure.asAdventure(mobEffectInfo.getTooltipFormatting()), mobEffectInfo.getTooltipFormatting().name() + " doesn't equal " + bukkitEffectCategory.getColor());
+ }
+ }
+}

View File

@@ -1,929 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Tue, 22 Jun 2021 23:41:11 -0400
Subject: [PATCH] More Projectile API
== AT ==
public net.minecraft.world.entity.projectile.FishingHook timeUntilLured
public net.minecraft.world.entity.projectile.FishingHook fishAngle
public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaX
public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaY
public net.minecraft.world.entity.projectile.ShulkerBullet targetDeltaZ
public net.minecraft.world.entity.projectile.ShulkerBullet currentMoveDirection
public net.minecraft.world.entity.projectile.ShulkerBullet flightSteps
public net.minecraft.world.entity.projectile.AbstractArrow soundEvent
public net.minecraft.world.entity.projectile.AbstractArrow setPickupItemStack(Lnet/minecraft/world/item/ItemStack;)V
public net.minecraft.world.entity.projectile.ThrownTrident dealtDamage
public net.minecraft.world.entity.projectile.Arrow NO_EFFECT_COLOR
public net.minecraft.world.entity.projectile.Projectile hasBeenShot
public net.minecraft.world.entity.projectile.Projectile leftOwner
public net.minecraft.world.entity.projectile.Projectile preOnHit(Lnet/minecraft/world/phys/HitResult;)V
public net.minecraft.world.entity.projectile.Projectile canHitEntity(Lnet/minecraft/world/entity/Entity;)Z
public net.minecraft.world.entity.projectile.FireworkRocketEntity getDefaultItem()Lnet/minecraft/world/item/ItemStack;
public net.minecraft.world.item.CrossbowItem FIREWORK_POWER
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
Co-authored-by: SoSeDiK <mrsosedik@gmail.com>
Co-authored-by: MelnCat <melncatuwu@gmail.com>
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -0,0 +0,0 @@ public class FishingHook extends Projectile {
}
} else {
// CraftBukkit start - logic to modify fishing wait time
- this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime);
- this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop
+ this.resetTimeUntilLured(); // Paper - more projectile api - extract time until lured reset logic
// CraftBukkit end
}
}
}
+ // Paper start - more projectile api - extract time until lured reset logic
+ public void resetTimeUntilLured() {
+ this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime);
+ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed ) : 0; // Paper - Fix Lure infinite loop
+ }
+ // Paper end - more projectile api - extract time until lured reset logic
public boolean calculateOpenWater(BlockPos pos) {
FishingHook.OpenWaterType entityfishinghook_waterposition = FishingHook.OpenWaterType.INVALID;
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
@@ -0,0 +0,0 @@ public abstract class Projectile extends Entity implements TraceableEntity {
}
// CraftBukkit start - call projectile hit event
- protected ProjectileDeflection preHitTargetOrDeflectSelf(HitResult movingobjectposition) {
+ public ProjectileDeflection preHitTargetOrDeflectSelf(HitResult movingobjectposition) { // Paper - protected -> public
org.bukkit.event.entity.ProjectileHitEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileHitEvent(this, movingobjectposition);
this.hitCancelled = event != null && event.isCancelled();
if (movingobjectposition.getType() == HitResult.Type.BLOCK || !this.hitCancelled) {
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownPotion.java
@@ -0,0 +0,0 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
@Override
protected void onHit(HitResult hitResult) {
super.onHit(hitResult);
+ // Paper start - More projectile API
+ this.splash(hitResult);
+ }
+ public void splash(@Nullable HitResult hitResult) {
+ // Paper end - More projectile API
if (!this.level().isClientSide) {
ItemStack itemstack = this.getItem();
PotionContents potioncontents = (PotionContents) itemstack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
@@ -0,0 +0,0 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
if (this.isLingering()) {
showParticles = this.makeAreaOfEffectCloud(potioncontents, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper
} else {
- showParticles = this.applySplash(potioncontents.getAllEffects(), hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper
+ showParticles = this.applySplash(potioncontents.getAllEffects(), hitResult != null && hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null, hitResult); // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API
}
}
@@ -0,0 +0,0 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
}
- private boolean applySplash(Iterable<MobEffectInstance> iterable, @Nullable Entity entity, HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events
+ private boolean applySplash(Iterable<MobEffectInstance> iterable, @Nullable Entity entity, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - Fix potions splash events & More projectile API
AABB axisalignedbb = this.getBoundingBox().inflate(4.0D, 2.0D, 4.0D);
List<net.minecraft.world.entity.LivingEntity> list = this.level().getEntitiesOfClass(net.minecraft.world.entity.LivingEntity.class, axisalignedbb);
Map<LivingEntity, Double> affected = new HashMap<LivingEntity, Double>(); // CraftBukkit
@@ -0,0 +0,0 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
}
- private boolean makeAreaOfEffectCloud(PotionContents potioncontents, HitResult position) { // CraftBukkit - Pass MovingObjectPosition
+ private boolean makeAreaOfEffectCloud(PotionContents potioncontents, @Nullable HitResult position) { // CraftBukkit - Pass MovingObjectPosition // Paper - More projectile API
AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
Entity entity = this.getOwner();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java
@@ -0,0 +0,0 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti
@Override
public void setBounce(boolean doesBounce) {}
+ // Paper start - More projectile API
+ @Override
+ public boolean hasLeftShooter() {
+ return this.getHandle().leftOwner;
+ }
+
+ @Override
+ public void setHasLeftShooter(boolean leftShooter) {
+ this.getHandle().leftOwner = leftShooter;
+ }
+
+ @Override
+ public boolean hasBeenShot() {
+ return this.getHandle().hasBeenShot;
+ }
+
+ @Override
+ public void setHasBeenShot(boolean beenShot) {
+ this.getHandle().hasBeenShot = beenShot;
+ }
+
+ @Override
+ public boolean canHitEntity(org.bukkit.entity.Entity entity) {
+ return this.getHandle().canHitEntity(((CraftEntity) entity).getHandle());
+ }
+
+ @Override
+ public void hitEntity(org.bukkit.entity.Entity entity) {
+ this.getHandle().preHitTargetOrDeflectSelf(new net.minecraft.world.phys.EntityHitResult(((CraftEntity) entity).getHandle()));
+ }
+
+ @Override
+ public void hitEntity(org.bukkit.entity.Entity entity, org.bukkit.util.Vector vector) {
+ this.getHandle().preHitTargetOrDeflectSelf(new net.minecraft.world.phys.EntityHitResult(((CraftEntity) entity).getHandle(), new net.minecraft.world.phys.Vec3(vector.getX(), vector.getY(), vector.getZ())));
+ }
+
+ @Override
+ public net.minecraft.world.entity.projectile.Projectile getHandle() {
+ return (net.minecraft.world.entity.projectile.Projectile) entity;
+ }
+
+ @Override
+ public final org.bukkit.projectiles.ProjectileSource getShooter() {
+ return this.getHandle().projectileSource;
+ }
+
+ @Override
+ public final void setShooter(org.bukkit.projectiles.ProjectileSource shooter) {
+ if (shooter instanceof CraftEntity craftEntity) {
+ this.getHandle().setOwner(craftEntity.getHandle());
+ } else {
+ this.getHandle().setOwner(null);
+ }
+ this.getHandle().projectileSource = shooter;
+ }
+
+ @Override
+ public java.util.UUID getOwnerUniqueId() {
+ return this.getHandle().ownerUUID;
+ }
+ // Paper end - More projectile API
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java
@@ -0,0 +0,0 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr
this.getHandle().setCritArrow(critical);
}
- @Override
- public ProjectileSource getShooter() {
- return this.getHandle().projectileSource;
- }
-
- @Override
- public void setShooter(ProjectileSource shooter) {
- if (shooter instanceof Entity) {
- this.getHandle().setOwner(((CraftEntity) shooter).getHandle());
- } else {
- this.getHandle().setOwner(null);
- }
- this.getHandle().projectileSource = shooter;
- }
+ // Paper - moved to AbstractProjectile
@Override
public boolean isInBlock() {
@@ -0,0 +0,0 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr
@Override
public ItemStack getWeapon() {
+ if (this.getHandle().getWeaponItem() == null) return null; // Paper - fix NPE
return CraftItemStack.asBukkitCopy(this.getHandle().getWeaponItem());
}
@@ -0,0 +0,0 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr
public String toString() {
return "CraftArrow";
}
+
+ // Paper start
+ @Override
+ public CraftItemStack getItemStack() {
+ return CraftItemStack.asCraftMirror(this.getHandle().getPickupItem());
+ }
+
+ @Override
+ public void setItemStack(final ItemStack stack) {
+ Preconditions.checkArgument(stack != null, "ItemStack cannot be null");
+ this.getHandle().setPickupItemStack(CraftItemStack.asNMSCopy(stack));
+ }
+
+ @Override
+ public void setLifetimeTicks(int ticks) {
+ this.getHandle().life = ticks;
+ }
+
+ @Override
+ public int getLifetimeTicks() {
+ return this.getHandle().life;
+ }
+
+ @Override
+ public org.bukkit.Sound getHitSound() {
+ return org.bukkit.craftbukkit.CraftSound.minecraftToBukkit(this.getHandle().soundEvent);
+ }
+
+ @Override
+ public void setHitSound(org.bukkit.Sound sound) {
+ this.getHandle().setSoundEvent(org.bukkit.craftbukkit.CraftSound.bukkitToMinecraft(sound));
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java
@@ -0,0 +0,0 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud
@Override
public Color getColor() {
- return Color.fromRGB(this.getHandle().potionContents.getColor());
+ return Color.fromRGB(this.getHandle().potionContents.getColor() & 0x00FFFFFF); // Paper - skip alpha channel
}
@Override
@@ -0,0 +0,0 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud
this.removeCustomEffect(effect.getType());
}
this.getHandle().addEffect(CraftPotionUtil.fromBukkit(effect));
- this.getHandle().updateColor();
+ // this.getHandle().updateColor(); // Paper - already done above
return true;
}
@@ -0,0 +0,0 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud
public void clearCustomEffects() {
PotionContents old = this.getHandle().potionContents;
this.getHandle().setPotionContents(new PotionContents(old.potion(), old.customColor(), List.of()));
- this.getHandle().updateColor();
+ // this.getHandle().updateColor(); // Paper - already done above
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
@@ -0,0 +0,0 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow {
this.removeCustomEffect(effect.getType());
}
this.getHandle().addEffect(CraftPotionUtil.fromBukkit(effect));
- this.getHandle().updateColor();
+ // this.getHandle().updateColor(); // Paper - already done above
return true;
}
@@ -0,0 +0,0 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow {
public void clearCustomEffects() {
PotionContents old = this.getHandle().getPotionContents();
this.getHandle().setPotionContents(new PotionContents(old.potion(), old.customColor(), List.of()));
- this.getHandle().updateColor();
+ // this.getHandle().updateColor(); // Paper - already done above
}
@Override
@@ -0,0 +0,0 @@ public class CraftArrow extends CraftAbstractArrow implements Arrow {
@Override
public void setColor(Color color) {
- int colorRGB = (color == null) ? -1 : color.asRGB();
+ int colorRGB = (color == null) ? net.minecraft.world.entity.projectile.Arrow.NO_EFFECT_COLOR : color.asARGB(); // Paper
PotionContents old = this.getHandle().getPotionContents();
this.getHandle().setPotionContents(new PotionContents(old.potion(), Optional.of(colorRGB), old.customEffects()));
}
@Override
public Color getColor() {
- if (this.getHandle().getColor() <= -1) {
+ int color = this.getHandle().getColor(); // Paper
+ if (color == net.minecraft.world.entity.projectile.Arrow.NO_EFFECT_COLOR) { // Paper
return null;
}
- return Color.fromRGB(this.getHandle().getColor());
+ return Color.fromARGB(color); // Paper
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
@@ -0,0 +0,0 @@ public final class CraftEntityTypes {
BlockPos pos = BlockPos.containing(spawnData.x(), spawnData.y(), spawnData.z());
return new FallingBlockEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), spawnData.world().getBlockState(pos)); // Paper - create falling block entities correctly
}));
- register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), net.minecraft.world.item.ItemStack.EMPTY)));
+ register(new EntityTypeData<>(EntityType.FIREWORK_ROCKET, Firework.class, CraftFirework::new, spawnData -> new FireworkRocketEntity(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), FireworkRocketEntity.getDefaultItem()))); // Paper - pass correct default to rocket for data storage
register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new net.minecraft.world.entity.projectile.EvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null)));
register(new EntityTypeData<>(EntityType.COMMAND_BLOCK_MINECART, CommandMinecart.class, CraftMinecartCommand::new, spawnData -> new MinecartCommandBlock(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z())));
register(new EntityTypeData<>(EntityType.MINECART, RideableMinecart.class, CraftMinecartRideable::new, spawnData -> new Minecart(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z())));
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFireball.java
@@ -0,0 +0,0 @@ public class CraftFireball extends AbstractProjectile implements Fireball {
this.getHandle().bukkitYield = yield;
}
- @Override
- public ProjectileSource getShooter() {
- return this.getHandle().projectileSource;
- }
-
- @Override
- public void setShooter(ProjectileSource shooter) {
- if (shooter instanceof CraftLivingEntity) {
- this.getHandle().setOwner(((CraftLivingEntity) shooter).getHandle());
- } else {
- this.getHandle().setOwner(null);
- }
- this.getHandle().projectileSource = shooter;
- }
+ // Paper - moved to AbstractProjectile
@Override
public Vector getDirection() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java
@@ -0,0 +0,0 @@ import org.bukkit.inventory.meta.FireworkMeta;
public class CraftFirework extends CraftProjectile implements Firework {
private final Random random = new Random();
- private final CraftItemStack item;
+ //private CraftItemStack item; // Paper - Remove usage, not accurate representation of current item.
public CraftFirework(CraftServer server, FireworkRocketEntity entity) {
super(server, entity);
- ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
-
- if (item.isEmpty()) {
- item = new ItemStack(Items.FIREWORK_ROCKET);
- this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item);
- }
-
- this.item = CraftItemStack.asCraftMirror(item);
-
- // Ensure the item is a firework...
- if (this.item.getType() != Material.FIREWORK_ROCKET) {
- this.item.setType(Material.FIREWORK_ROCKET);
- }
+ // Paper start - Expose firework item directly
+// ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM);
+//
+// if (item.isEmpty()) {
+// item = new ItemStack(Items.FIREWORK_ROCKET);
+// this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item);
+// }
+//
+// this.item = CraftItemStack.asCraftMirror(item);
+//
+// // Ensure the item is a firework...
+// if (this.item.getType() != Material.FIREWORK_ROCKET) {
+// this.item.setType(Material.FIREWORK_ROCKET);
+// }
+ // Paper end - Expose firework item directly
}
@Override
@@ -0,0 +0,0 @@ public class CraftFirework extends CraftProjectile implements Firework {
@Override
public FireworkMeta getFireworkMeta() {
- return (FireworkMeta) this.item.getItemMeta();
+ return (FireworkMeta) CraftItemStack.getItemMeta(this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM), org.bukkit.inventory.ItemType.FIREWORK_ROCKET); // Paper - Expose firework item directly
}
@Override
public void setFireworkMeta(FireworkMeta meta) {
- this.item.setItemMeta(meta);
+ applyFireworkEffect(meta); // Paper - Expose firework item directly
// Copied from EntityFireworks constructor, update firework lifetime/power
this.getHandle().lifetime = 10 * (1 + meta.getPower()) + this.random.nextInt(6) + this.random.nextInt(7);
@@ -0,0 +0,0 @@ public class CraftFirework extends CraftProjectile implements Firework {
return getHandle().spawningEntity;
}
// Paper end
+ // Paper start - Expose firework item directly + manually setting flight
+ @Override
+ public org.bukkit.inventory.ItemStack getItem() {
+ return CraftItemStack.asBukkitCopy(this.getHandle().getItem());
+ }
+
+ @Override
+ public void setItem(org.bukkit.inventory.ItemStack itemStack) {
+ FireworkMeta meta = getFireworkMeta();
+ ItemStack nmsItem = itemStack == null ? FireworkRocketEntity.getDefaultItem() : CraftItemStack.asNMSCopy(itemStack);
+ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, nmsItem);
+
+ applyFireworkEffect(meta);
+ }
+
+ @Override
+ public int getTicksFlown() {
+ return this.getHandle().life;
+ }
+
+ @Override
+ public void setTicksFlown(int ticks) {
+ this.getHandle().life = ticks;
+ }
+
+ @Override
+ public int getTicksToDetonate() {
+ return this.getHandle().lifetime;
+ }
+
+ @Override
+ public void setTicksToDetonate(int ticks) {
+ this.getHandle().lifetime = ticks;
+ }
+
+ void applyFireworkEffect(FireworkMeta meta) {
+ ItemStack item = this.getHandle().getItem();
+ CraftItemStack.applyMetaToItem(item, meta);
+
+ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item);
+ }
+ // Paper end - Expose firework item directly + manually setting flight
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java
@@ -0,0 +0,0 @@ public class CraftFishHook extends CraftProjectile implements FishHook {
public HookState getState() {
return HookState.values()[this.getHandle().currentState.ordinal()];
}
+ // Paper start - More FishHook API
+ @Override
+ public int getWaitTime() {
+ return this.getHandle().timeUntilLured;
+ }
+
+ @Override
+ public void setWaitTime(int ticks) {
+ this.getHandle().timeUntilLured = ticks;
+ }
+
+ @Override
+ public int getTimeUntilBite() {
+ return this.getHandle().timeUntilHooked;
+ }
+
+ @Override
+ public void setTimeUntilBite(final int ticks) {
+ com.google.common.base.Preconditions.checkArgument(ticks >= 1, "Cannot set time until bite to less than 1 (%s<1)", ticks);
+ final FishingHook hook = this.getHandle();
+
+ // Reset the fish angle hook only when this call "enters" the fish into the lure stage.
+ final boolean alreadyInLuringPhase = hook.timeUntilHooked > 0 && hook.timeUntilLured <= 0;
+ if (!alreadyInLuringPhase) {
+ hook.fishAngle = net.minecraft.util.Mth.nextFloat(hook.random, hook.minLureAngle, hook.maxLureAngle);
+ hook.timeUntilLured = 0;
+ }
+
+ hook.timeUntilHooked = ticks;
+ }
+
+ @Override
+ public void resetFishingState() {
+ final FishingHook hook = this.getHandle();
+ hook.resetTimeUntilLured();
+ hook.timeUntilHooked = 0; // Reset time until hooked, will be repopulated once lured time is ticked down.
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -0,0 +0,0 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
}
@Override
- @SuppressWarnings("unchecked")
public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity) {
+ // Paper start - launchProjectile consumer
+ return this.launchProjectile(projectile, velocity, null);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity, java.util.function.Consumer<? super T> function) {
+ // Paper end - launchProjectile consumer
Preconditions.checkState(!this.getHandle().generation, "Cannot launch projectile during world generation");
net.minecraft.world.level.Level world = ((CraftWorld) this.getWorld()).getHandle();
@@ -0,0 +0,0 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
} else {
launch = new net.minecraft.world.entity.projectile.Arrow(world, this.getHandle(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.ARROW), null);
}
- ((net.minecraft.world.entity.projectile.AbstractArrow) launch).shootFromRotation(this.getHandle(), this.getHandle().getXRot(), this.getHandle().getYRot(), 0.0F, 3.0F, 1.0F); // ItemBow
+ ((net.minecraft.world.entity.projectile.AbstractArrow) launch).shootFromRotation(this.getHandle(), this.getHandle().getXRot(), this.getHandle().getYRot(), 0.0F, Trident.class.isAssignableFrom(projectile) ? net.minecraft.world.item.TridentItem.SHOOT_POWER : 3.0F, 1.0F); // ItemBow // Paper - see TridentItem
} else if (ThrownPotion.class.isAssignableFrom(projectile)) {
if (LingeringPotion.class.isAssignableFrom(projectile)) {
launch = new net.minecraft.world.entity.projectile.ThrownPotion(world, this.getHandle());
@@ -0,0 +0,0 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
} else if (Firework.class.isAssignableFrom(projectile)) {
Location location = this.getEyeLocation();
- launch = new FireworkRocketEntity(world, net.minecraft.world.item.ItemStack.EMPTY, this.getHandle());
- launch.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+ // Paper start - see CrossbowItem
+ launch = new FireworkRocketEntity(world, FireworkRocketEntity.getDefaultItem(), this.getHandle(), location.getX(), location.getY() - 0.15F, location.getZ(), true); // Paper - pass correct default to rocket for data storage & see CrossbowItem for regular launch without elytra boost
+
+ // Lifted from net.minecraft.world.item.ProjectileWeaponItem.shoot
+ float f2 = /* net.minecraft.world.item.enchantment.EnchantmentHelper.processProjectileSpread((ServerLevel) world, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.CROSSBOW), this.getHandle(), 0.0F); */ 0; // Just shortcut this to 0, no need to do any calculations on a non existing stack
+ int projectileSize = 1;
+ int i = 0;
+
+ float f3 = projectileSize == 1 ? 0.0F : 2.0F * f2 / (float) (projectileSize - 1);
+ float f4 = (float) ((projectileSize - 1) % 2) * f3 / 2.0F;
+ float f5 = 1.0F;
+ float yaw = f4 + f5 * (float) ((i + 1) / 2) * f3;
+
+ // Lifted from net.minecraft.world.item.CrossbowItem.shootProjectile
+ Vec3 vec3 = this.getHandle().getUpVector(1.0F);
+ org.joml.Quaternionf quaternionf = new org.joml.Quaternionf().setAngleAxis((double)(yaw * (float) (Math.PI / 180.0)), vec3.x, vec3.y, vec3.z);
+ Vec3 vec32 = this.getHandle().getViewVector(1.0F);
+ org.joml.Vector3f vector3f = vec32.toVector3f().rotate(quaternionf);
+ ((FireworkRocketEntity) launch).shoot((double)vector3f.x(), (double)vector3f.y(), (double)vector3f.z(), net.minecraft.world.item.CrossbowItem.FIREWORK_POWER, 1.0F);
+ // Paper end
}
Preconditions.checkArgument(launch != null, "Projectile (%s) not supported", projectile.getName());
@@ -0,0 +0,0 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
if (velocity != null) {
((T) launch.getBukkitEntity()).setVelocity(velocity);
}
+ // Paper start - launchProjectile consumer
+ if (function != null) {
+ function.accept((T) launch.getBukkitEntity());
+ }
+ // Paper end - launchProjectile consumer
world.addFreshEntity(launch);
return (T) launch.getBukkitEntity();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlamaSpit.java
@@ -0,0 +0,0 @@ public class CraftLlamaSpit extends AbstractProjectile implements LlamaSpit {
return "CraftLlamaSpit";
}
- @Override
- public ProjectileSource getShooter() {
- return (this.getHandle().getOwner() != null) ? (ProjectileSource) this.getHandle().getOwner().getBukkitEntity() : null;
- }
-
- @Override
- public void setShooter(ProjectileSource source) {
- this.getHandle().setOwner((source != null) ? ((CraftLivingEntity) source).getHandle() : null);
- }
+ // Paper - moved to AbstractProjectile
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftProjectile.java
@@ -0,0 +0,0 @@ public abstract class CraftProjectile extends AbstractProjectile implements Proj
super(server, entity);
}
- @Override
- public ProjectileSource getShooter() {
- return this.getHandle().projectileSource;
- }
-
- @Override
- public void setShooter(ProjectileSource shooter) {
- if (shooter instanceof CraftLivingEntity) {
- this.getHandle().setOwner((LivingEntity) ((CraftLivingEntity) shooter).entity);
- } else {
- this.getHandle().setOwner(null);
- }
- this.getHandle().projectileSource = shooter;
- }
+ // Paper - moved to AbstractProjectile
@Override
public net.minecraft.world.entity.projectile.Projectile getHandle() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftShulkerBullet.java
@@ -0,0 +0,0 @@ public class CraftShulkerBullet extends AbstractProjectile implements ShulkerBul
super(server, entity);
}
+ // Paper - moved to AbstractProjectile
+
+ @Override
+ public org.bukkit.entity.Entity getTarget() {
+ return this.getHandle().getTarget() != null ? this.getHandle().getTarget().getBukkitEntity() : null;
+ }
+
@Override
- public ProjectileSource getShooter() {
- return this.getHandle().projectileSource;
+ public void setTarget(org.bukkit.entity.Entity target) {
+ Preconditions.checkState(!this.getHandle().generation, "Cannot set target during world generation");
+
+ this.getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle());
}
@Override
- public void setShooter(ProjectileSource shooter) {
- if (shooter instanceof Entity) {
- this.getHandle().setOwner(((CraftEntity) shooter).getHandle());
- } else {
- this.getHandle().setOwner(null);
+ public org.bukkit.util.Vector getTargetDelta() {
+ net.minecraft.world.entity.projectile.ShulkerBullet bullet = this.getHandle();
+ return new org.bukkit.util.Vector(bullet.targetDeltaX, bullet.targetDeltaY, bullet.targetDeltaZ);
+ }
+
+ @Override
+ public void setTargetDelta(org.bukkit.util.Vector vector) {
+ net.minecraft.world.entity.projectile.ShulkerBullet bullet = this.getHandle();
+ bullet.targetDeltaX = vector.getX();
+ bullet.targetDeltaY = vector.getY();
+ bullet.targetDeltaZ = vector.getZ();
+ }
+
+ @Override
+ public org.bukkit.block.BlockFace getCurrentMovementDirection() {
+ net.minecraft.core.Direction dir = this.getHandle().currentMoveDirection;
+ if (dir == null) {
+ return null; // random dir
}
- this.getHandle().projectileSource = shooter;
+ return org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(dir);
}
@Override
- public org.bukkit.entity.Entity getTarget() {
- return this.getHandle().getTarget() != null ? this.getHandle().getTarget().getBukkitEntity() : null;
+ public void setCurrentMovementDirection(org.bukkit.block.BlockFace movementDirection) {
+ this.getHandle().currentMoveDirection = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(movementDirection);
}
@Override
- public void setTarget(org.bukkit.entity.Entity target) {
- Preconditions.checkState(!this.getHandle().generation, "Cannot set target during world generation");
+ public int getFlightSteps() {
+ return this.getHandle().flightSteps;
+ }
- this.getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle());
+ @Override
+ public void setFlightSteps(int steps) {
+ this.getHandle().flightSteps = steps;
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java
@@ -0,0 +0,0 @@ public class CraftThrownPotion extends CraftThrowableProjectile implements Throw
@Override
public void setItem(ItemStack item) {
Preconditions.checkArgument(item != null, "ItemStack cannot be null");
- Preconditions.checkArgument(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack material must be Material.LINGERING_POTION or Material.SPLASH_POTION but was Material.%s", item.getType());
+ // Preconditions.checkArgument(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack material must be Material.LINGERING_POTION or Material.SPLASH_POTION but was Material.%s", item.getType()); // Paper - Projectile API
+ org.bukkit.inventory.meta.PotionMeta meta = (item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION) ? null : this.getPotionMeta(); // Paper - Projectile API
this.getHandle().setItem(CraftItemStack.asNMSCopy(item));
+ if (meta != null) this.setPotionMeta(meta); // Paper - Projectile API
}
+ // Paper start - Projectile API
+ @Override
+ public org.bukkit.inventory.meta.PotionMeta getPotionMeta() {
+ return (org.bukkit.inventory.meta.PotionMeta) CraftItemStack.getItemMeta(this.getHandle().getItem(), org.bukkit.inventory.ItemType.SPLASH_POTION);
+ }
+
+ @Override
+ public void setPotionMeta(org.bukkit.inventory.meta.PotionMeta meta) {
+ net.minecraft.world.item.ItemStack item = this.getHandle().getItem();
+ CraftItemStack.applyMetaToItem(item, meta);
+ this.getHandle().setItem(item); // Reset item
+ }
+
+ @Override
+ public void splash() {
+ this.getHandle().splash(null);
+ }
+ // Paper end
@Override
public net.minecraft.world.entity.projectile.ThrownPotion getHandle() {
return (net.minecraft.world.entity.projectile.ThrownPotion) this.entity;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTrident.java
@@ -0,0 +0,0 @@ public class CraftTrident extends CraftAbstractArrow implements Trident {
com.google.common.base.Preconditions.checkArgument(loyaltyLevel >= 0 && loyaltyLevel <= 127, "The loyalty level has to be between 0 and 127");
this.getHandle().setLoyalty((byte) loyaltyLevel);
}
+
+ @Override
+ public boolean hasDealtDamage() {
+ return this.getHandle().dealtDamage;
+ }
+
+ @Override
+ public void setHasDealtDamage(boolean hasDealtDamage) {
+ this.getHandle().dealtDamage = hasDealtDamage;
+ }
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -0,0 +0,0 @@ public class CraftEventFactory {
/**
* PotionSplashEvent
*/
- public static PotionSplashEvent callPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, HitResult position, Map<LivingEntity, Double> affectedEntities) {
+ public static PotionSplashEvent callPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult position, Map<LivingEntity, Double> affectedEntities) { // Paper - nullable hitResult
ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity();
Block hitBlock = null;
BlockFace hitFace = null;
- if (position.getType() == HitResult.Type.BLOCK) {
+ if (position != null && position.getType() == HitResult.Type.BLOCK) { // Paper - nullable hitResult
BlockHitResult positionBlock = (BlockHitResult) position;
hitBlock = CraftBlock.at(potion.level(), positionBlock.getBlockPos());
hitFace = CraftBlock.notchToBlockFace(positionBlock.getDirection());
}
org.bukkit.entity.Entity hitEntity = null;
- if (position.getType() == HitResult.Type.ENTITY) {
+ if (position != null && position.getType() == HitResult.Type.ENTITY) { // Paper - nullable hitResult
hitEntity = ((EntityHitResult) position).getEntity().getBukkitEntity();
}
@@ -0,0 +0,0 @@ public class CraftEventFactory {
return event;
}
- public static LingeringPotionSplashEvent callLingeringPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, HitResult position, net.minecraft.world.entity.AreaEffectCloud cloud) {
+ public static LingeringPotionSplashEvent callLingeringPotionSplashEvent(net.minecraft.world.entity.projectile.ThrownPotion potion, @Nullable HitResult position, net.minecraft.world.entity.AreaEffectCloud cloud) { // Paper - nullable hitResult
ThrownPotion thrownPotion = (ThrownPotion) potion.getBukkitEntity();
AreaEffectCloud effectCloud = (AreaEffectCloud) cloud.getBukkitEntity();
Block hitBlock = null;
BlockFace hitFace = null;
- if (position.getType() == HitResult.Type.BLOCK) {
+ if (position != null && position.getType() == HitResult.Type.BLOCK) { // Paper
BlockHitResult positionBlock = (BlockHitResult) position;
hitBlock = CraftBlock.at(potion.level(), positionBlock.getBlockPos());
hitFace = CraftBlock.notchToBlockFace(positionBlock.getDirection());
}
org.bukkit.entity.Entity hitEntity = null;
- if (position.getType() == HitResult.Type.ENTITY) {
+ if (position != null && position.getType() == HitResult.Type.ENTITY) { // Paper
hitEntity = ((EntityHitResult) position).getEntity().getBukkitEntity();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -0,0 +0,0 @@ public final class CraftItemStack extends ItemStack {
public ItemMeta getItemMeta() {
return CraftItemStack.getItemMeta(this.handle);
}
+ // Paper start
+ public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) {
+ final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator();
+ ((CraftMetaItem) itemMeta).applyToItem(tag);
+ itemStack.applyComponents(tag.build());
+ }
public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item) {
+ return getItemMeta(item, null);
+ }
+ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType) {
+ // Paper end
if (!CraftItemStack.hasItemMeta(item)) {
return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item));
}
+ if (metaForType != null) { return ((CraftItemType<?>) metaForType).getItemMeta(item); } // Paper
return ((CraftItemType<?>) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java
+++ b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java
@@ -0,0 +0,0 @@ public class CraftBlockProjectileSource implements BlockProjectileSource {
@Override
public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity) {
+ // Paper start - launchProjectile consumer
+ return this.launchProjectile(projectile, velocity, null);
+ }
+
+ @Override
+ public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity, java.util.function.Consumer<? super T> function) {
+ // Paper end - launchProjectile consumer
Preconditions.checkArgument(this.getBlock().getType() == Material.DISPENSER, "Block is no longer dispenser");
+
// Copied from BlockDispenser.dispense()
BlockSource sourceblock = new BlockSource((ServerLevel) this.dispenserBlock.getLevel(), this.dispenserBlock.getBlockPos(), this.dispenserBlock.getBlockState(), this.dispenserBlock);
// Copied from DispenseBehaviorProjectile
@@ -0,0 +0,0 @@ public class CraftBlockProjectileSource implements BlockProjectileSource {
item = Items.SNOWBALL;
} else if (Egg.class.isAssignableFrom(projectile)) {
item = Items.EGG;
- } else if (EnderPearl.class.isAssignableFrom(projectile)) {
+ } else if (false && EnderPearl.class.isAssignableFrom(projectile)) { // Paper - more projectile API - disallow enderpearl, it is not a projectile item
item = Items.ENDER_PEARL;
} else if (ThrownExpBottle.class.isAssignableFrom(projectile)) {
item = Items.EXPERIENCE_BOTTLE;
@@ -0,0 +0,0 @@ public class CraftBlockProjectileSource implements BlockProjectileSource {
item = Items.TIPPED_ARROW;
} else if (SpectralArrow.class.isAssignableFrom(projectile)) {
item = Items.SPECTRAL_ARROW;
- } else {
+ } else if (org.bukkit.entity.Arrow.class.isAssignableFrom(projectile)) { // Paper - more projectile API - disallow trident
item = Items.ARROW;
}
} else if (Fireball.class.isAssignableFrom(projectile)) {
- if (AbstractWindCharge.class.isAssignableFrom(projectile)) {
+ if (org.bukkit.entity.WindCharge.class.isAssignableFrom(projectile)) { // Paper - more projectile API - only allow wind charge not breeze wind charge
item = Items.WIND_CHARGE;
- } else {
+ } else if (org.bukkit.entity.SmallFireball.class.isAssignableFrom(projectile)) { // Paper - more projectile API - only allow firing fire charges.
item = Items.FIRE_CHARGE;
}
} else if (Firework.class.isAssignableFrom(projectile)) {
item = Items.FIREWORK_ROCKET;
}
- Preconditions.checkArgument(item instanceof ProjectileItem, "Projectile not supported");
+ Preconditions.checkArgument(item instanceof ProjectileItem, "Projectile '%s' not supported", projectile.getSimpleName()); // Paper - more projectile API - include simple name in exception
ItemStack itemstack = new ItemStack(item);
ProjectileItem projectileItem = (ProjectileItem) item;
@@ -0,0 +0,0 @@ public class CraftBlockProjectileSource implements BlockProjectileSource {
Position iposition = dispenseConfig.positionFunction().getDispensePosition(sourceblock, enumdirection);
net.minecraft.world.entity.projectile.Projectile launch = projectileItem.asProjectile(world, iposition, itemstack, enumdirection);
- if (Fireball.class.isAssignableFrom(projectile)) {
+ if (false && Fireball.class.isAssignableFrom(projectile)) { // Paper - more project API - dispensers cannot launch anything but fire charges.
AbstractHurtingProjectile customFireball = null;
if (WitherSkull.class.isAssignableFrom(projectile)) {
launch = customFireball = EntityType.WITHER_SKULL.create(world);
@@ -0,0 +0,0 @@ public class CraftBlockProjectileSource implements BlockProjectileSource {
}
}
- if (launch instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) {
+ if (false && launch instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) { // Paper - more projectile API - this is set by the respective ArrowItem when constructing the projectile
arrow.pickup = net.minecraft.world.entity.projectile.AbstractArrow.Pickup.ALLOWED;
}
launch.projectileSource = this;
@@ -0,0 +0,0 @@ public class CraftBlockProjectileSource implements BlockProjectileSource {
if (velocity != null) {
((T) launch.getBukkitEntity()).setVelocity(velocity);
}
+ // Paper start
+ if (function != null) {
+ function.accept((T) launch.getBukkitEntity());
+ }
+ // Paper end
world.addFreshEntity(launch);
return (T) launch.getBukkitEntity();

View File

@@ -1,62 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brody Beckwith <brody@beckwith.dev>
Date: Fri, 14 Jan 2022 00:41:11 -0500
Subject: [PATCH] Multi Block Change API Implementation
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
@@ -0,0 +0,0 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet<ClientGamePa
}
+ // Paper start - Multi Block Change API
+ public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, it.unimi.dsi.fastutil.shorts.Short2ObjectMap<BlockState> blockChanges) {
+ this.sectionPos = sectionPos;
+ this.positions = blockChanges.keySet().toShortArray();
+ this.states = blockChanges.values().toArray(new BlockState[0]);
+ }
+ // Paper end - Multi Block Change API
+
private void write(FriendlyByteBuf buf) {
buf.writeLong(this.sectionPos.asLong());
buf.writeVarInt(this.positions.length);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.getHandle().connection.send(packet);
}
+ // Paper start
+ @Override
+ public void sendMultiBlockChange(final Map<? extends io.papermc.paper.math.Position, BlockData> blockChanges) {
+ if (this.getHandle().connection == null) return;
+
+ Map<SectionPos, it.unimi.dsi.fastutil.shorts.Short2ObjectMap<net.minecraft.world.level.block.state.BlockState>> sectionMap = new HashMap<>();
+
+ for (Map.Entry<? extends io.papermc.paper.math.Position, BlockData> entry : blockChanges.entrySet()) {
+ BlockData blockData = entry.getValue();
+ BlockPos blockPos = io.papermc.paper.util.MCUtil.toBlockPos(entry.getKey());
+ SectionPos sectionPos = SectionPos.of(blockPos);
+
+ it.unimi.dsi.fastutil.shorts.Short2ObjectMap<net.minecraft.world.level.block.state.BlockState> sectionData = sectionMap.computeIfAbsent(sectionPos, key -> new it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap<>());
+ sectionData.put(SectionPos.sectionRelativePos(blockPos), ((CraftBlockData) blockData).getState());
+ }
+
+ for (Map.Entry<SectionPos, it.unimi.dsi.fastutil.shorts.Short2ObjectMap<net.minecraft.world.level.block.state.BlockState>> entry : sectionMap.entrySet()) {
+ SectionPos sectionPos = entry.getKey();
+ it.unimi.dsi.fastutil.shorts.Short2ObjectMap<net.minecraft.world.level.block.state.BlockState> blockData = entry.getValue();
+
+ net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket packet = new net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket(sectionPos, blockData);
+ this.getHandle().connection.send(packet);
+ }
+ }
+ // Paper end
+
@Override
public void sendBlockChanges(Collection<BlockState> blocks) {
Preconditions.checkArgument(blocks != null, "blocks must not be null");

View File

@@ -1,125 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cryptite <cryptite@gmail.com>
Date: Tue, 21 Sep 2021 18:17:33 -0500
Subject: [PATCH] Multiple Entries with Scoreboards
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
@@ -0,0 +0,0 @@ public class ClientboundSetPlayerTeamPacket implements Packet<ClientGamePacketLi
);
}
+ // Paper start - Multiple Entries with Scoreboards
+ public static ClientboundSetPlayerTeamPacket createMultiplePlayerPacket(PlayerTeam team, Collection<String> players, ClientboundSetPlayerTeamPacket.Action operation) {
+ return new ClientboundSetPlayerTeamPacket(team.getName(), operation == ClientboundSetPlayerTeamPacket.Action.ADD ? 3 : 4, Optional.empty(), players);
+ }
+ // Paper end - Multiple Entries with Scoreboards
private ClientboundSetPlayerTeamPacket(RegistryFriendlyByteBuf buf) {
this.name = buf.readUtf();
this.method = buf.readByte();
diff --git a/src/main/java/net/minecraft/server/ServerScoreboard.java b/src/main/java/net/minecraft/server/ServerScoreboard.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/ServerScoreboard.java
+++ b/src/main/java/net/minecraft/server/ServerScoreboard.java
@@ -0,0 +0,0 @@ public class ServerScoreboard extends Scoreboard {
}
}
+ // Paper start - Multiple Entries with Scoreboards
+ public boolean addPlayersToTeam(java.util.Collection<String> players, PlayerTeam team) {
+ boolean anyAdded = false;
+ for (String playerName : players) {
+ if (super.addPlayerToTeam(playerName, team)) {
+ anyAdded = true;
+ }
+ }
+
+ if (anyAdded) {
+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.ADD));
+ this.setDirty();
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // Paper end - Multiple Entries with Scoreboards
+
@Override
public void removePlayerFromTeam(String scoreHolderName, PlayerTeam team) {
super.removePlayerFromTeam(scoreHolderName, team);
@@ -0,0 +0,0 @@ public class ServerScoreboard extends Scoreboard {
this.setDirty();
}
+ // Paper start - Multiple Entries with Scoreboards
+ public void removePlayersFromTeam(java.util.Collection<String> players, PlayerTeam team) {
+ for (String playerName : players) {
+ super.removePlayerFromTeam(playerName, team);
+ }
+
+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.REMOVE));
+ this.setDirty();
+ }
+ // Paper end - Multiple Entries with Scoreboards
+
@Override
public void onObjectiveAdded(Objective objective) {
super.onObjectiveAdded(objective);
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
@@ -0,0 +0,0 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
scoreboard.board.addPlayerToTeam(entry, this.team);
}
+ // Paper start - Multiple Entries with Scoreboards
+ @Override
+ public void addEntities(java.util.Collection<org.bukkit.entity.Entity> entities) throws IllegalStateException, IllegalArgumentException {
+ this.addEntries(entities.stream().map(entity -> ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()).toList());
+ }
+
+ @Override
+ public void addEntries(java.util.Collection<String> entries) throws IllegalStateException, IllegalArgumentException {
+ Preconditions.checkArgument(entries != null, "Entries cannot be null");
+ CraftScoreboard scoreboard = this.checkState();
+
+ ((net.minecraft.server.ServerScoreboard) scoreboard.board).addPlayersToTeam(entries, this.team);
+ }
+ // Paper end - Multiple Entries with Scoreboards
+
@Override
public boolean removePlayer(OfflinePlayer player) {
Preconditions.checkArgument(player != null, "OfflinePlayer cannot be null");
@@ -0,0 +0,0 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
return true;
}
+ // Paper start - Multiple Entries with Scoreboards
+ @Override
+ public boolean removeEntities(java.util.Collection<org.bukkit.entity.Entity> entities) throws IllegalStateException, IllegalArgumentException {
+ return this.removeEntries(entities.stream().map(entity -> ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()).toList());
+ }
+
+ @Override
+ public boolean removeEntries(java.util.Collection<String> entries) throws IllegalStateException, IllegalArgumentException {
+ Preconditions.checkArgument(entries != null, "Entry cannot be null");
+ CraftScoreboard scoreboard = this.checkState();
+
+ for (String entry : entries) {
+ if (this.team.getPlayers().contains(entry)) {
+ ((net.minecraft.server.ServerScoreboard) scoreboard.board).removePlayersFromTeam(entries, this.team);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ // Paper end - Multiple Entries with Scoreboards
+
@Override
public boolean hasPlayer(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException {
Preconditions.checkArgument(player != null, "OfflinePlayer cannot be null");

View File

@@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 19 Feb 2022 20:15:41 -0800
Subject: [PATCH] Option to have default CustomSpawners in custom worlds
By default, only LevelStem's that specifically match the ResourceKey for
OVERWORLD will have the 5 (currently) impls of CustomSpawner (for
phantoms, wandering traders, etc.). This adds an option to instead of
just looking at the LevelStem key, look at the DimensionType key which
is one level below that. Defaults to off to keep vanilla behavior.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.commandStorage = new CommandStorage(worldpersistentdata);
} else {
ChunkProgressListener worldloadlistener = this.progressListenerFactory.create(this.worldData.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS));
- world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, ImmutableList.of(), true, this.overworld().getRandomSequences(), org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
+ // Paper start - option to use the dimension_type to check if spawners should be added. I imagine mojang will add some datapack-y way of managing this in the future.
+ final List<CustomSpawner> spawners;
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useDimensionTypeForCustomSpawners && this.registryAccess().registryOrThrow(Registries.DIMENSION_TYPE).getResourceKey(worlddimension.type().value()).orElseThrow() == net.minecraft.world.level.dimension.BuiltinDimensionTypes.OVERWORLD) {
+ spawners = list;
+ } else {
+ spawners = Collections.emptyList();
+ }
+ world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, spawners, true, this.overworld().getRandomSequences(), org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
+ // Paper end - option to use the dimension_type to check if spawners should be added
}
worlddata.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified());

View File

@@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Wed, 13 Apr 2022 08:25:42 +0100
Subject: [PATCH] Prevent tile entity copies loading chunks
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
BlockPos blockposition = BlockEntity.getPosFromTag(customdata.getUnsafe());
if (this.player.level().isLoaded(blockposition)) {
- BlockEntity tileentity = this.player.level().getBlockEntity(blockposition);
+ // Paper start - Prevent tile entity copies loading chunks
+ BlockEntity tileentity = null;
+ if (this.player.distanceToSqr(blockposition.getX(), blockposition.getY(), blockposition.getZ()) < 32 * 32 && this.player.serverLevel().isLoadedAndInBounds(blockposition)) {
+ tileentity = this.player.level().getBlockEntity(blockposition);
+ }
+ // Paper end - Prevent tile entity copies loading chunks
if (tileentity != null) {
tileentity.saveToItem(itemstack, this.player.level().registryAccess());

View File

@@ -1,41 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Tue, 22 Feb 2022 14:21:35 -0800
Subject: [PATCH] Put world into worldlist before initing the world
Some parts of legacy conversion will need the overworld
to get the legacy structure data storage
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
worlddata.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified());
+ this.addLevel(world); // Paper - Put world into worldlist before initing the world; move up
this.initWorld(world, worlddata, this.worldData, worldoptions);
- this.addLevel(world);
+ // Paper - Put world into worldlist before initing the world; move up
this.getPlayerList().addWorldborderListener(world);
if (worlddata.getCustomBossEvents() != null) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
return null;
}
+ this.console.addLevel(internal); // Paper - Put world into worldlist before initing the world; move up
this.console.initWorld(internal, worlddata, worlddata, worlddata.worldGenOptions());
internal.setSpawnSettings(true, true);
- this.console.addLevel(internal);
+ // Paper - Put world into worldlist before initing the world; move up
this.getServer().prepareLevels(internal.getChunkSource().chunkMap.progressListener, internal);
internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API

View File

@@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Fri, 7 Jan 2022 11:45:15 +0100
Subject: [PATCH] Reset placed block on exception
diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/item/BlockItem.java
+++ b/src/main/java/net/minecraft/world/item/BlockItem.java
@@ -0,0 +0,0 @@ public class BlockItem extends Item {
if (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem) {
blockstate = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos());
}
+ final org.bukkit.block.BlockState oldBlockstate = blockstate != null ? blockstate : org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos()); // Paper - Reset placed block on exception
// CraftBukkit end
if (iblockdata == null) {
@@ -0,0 +0,0 @@ public class BlockItem extends Item {
if (iblockdata1.is(iblockdata.getBlock())) {
iblockdata1 = this.updateBlockStateFromTag(blockposition, world, itemstack, iblockdata1);
+ // Paper start - Reset placed block on exception
+ try {
this.updateCustomBlockEntityTag(blockposition, world, entityhuman, itemstack, iblockdata1);
BlockItem.updateBlockEntityComponents(world, blockposition, itemstack);
+ } catch (Exception e) {
+ oldBlockstate.update(true, false);
+ if (entityhuman instanceof ServerPlayer player) {
+ org.apache.logging.log4j.LogManager.getLogger().error("Player {} tried placing invalid block", player.getScoreboardName(), e);
+ player.getBukkitEntity().kickPlayer("Packet processing error");
+ return InteractionResult.FAIL;
+ }
+ throw e; // Rethrow exception if not placed by a player
+ }
+ // Paper end - Reset placed block on exception
iblockdata1.getBlock().setPlacedBy(world, blockposition, iblockdata1, entityhuman, itemstack);
// CraftBukkit start
if (blockstate != null) {

View File

@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Mon, 12 Jul 2021 12:28:29 +0100
Subject: [PATCH] Use a CHM for StructureTemplate.Pallete cache
fixes a CME due to this collection being shared across threads
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
@@ -0,0 +0,0 @@ public class StructureTemplate {
public static final class Palette {
private final List<StructureTemplate.StructureBlockInfo> blocks;
- private final Map<Block, List<StructureTemplate.StructureBlockInfo>> cache = Maps.newHashMap();
+ private final Map<Block, List<StructureTemplate.StructureBlockInfo>> cache = Maps.newConcurrentMap(); // Paper - Fix CME due to this collection being shared across threads
Palette(List<StructureTemplate.StructureBlockInfo> infos) {
this.blocks = infos;

View File

@@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Doc <nachito94@msn.com>
Date: Fri, 15 Apr 2022 17:40:30 -0400
Subject: [PATCH] Use username instead of display name in
PlayerList#getPlayerStats
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -0,0 +0,0 @@ public abstract class PlayerList {
// CraftBukkit start
public ServerStatsCounter getPlayerStats(ServerPlayer entityhuman) {
ServerStatsCounter serverstatisticmanager = entityhuman.getStats();
- return serverstatisticmanager == null ? this.getPlayerStats(entityhuman.getUUID(), entityhuman.getDisplayName().getString()) : serverstatisticmanager;
+ return serverstatisticmanager == null ? this.getPlayerStats(entityhuman.getUUID(), entityhuman.getGameProfile().getName()) : serverstatisticmanager; // Paper - use username and not display name
}
public ServerStatsCounter getPlayerStats(UUID uuid, String displayName) {

View File

@@ -1,76 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 1 Jan 2022 05:19:37 -0800
Subject: [PATCH] Validate usernames
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -0,0 +0,0 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
private final String serverId;
private final boolean transferred;
private ServerPlayer player; // CraftBukkit
+ public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding
public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) {
this.state = ServerLoginPacketListenerImpl.State.HELLO;
@@ -0,0 +0,0 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
@Override
public void handleHello(ServerboundHelloPacket packet) {
Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]);
- Validate.validState(StringUtil.isValidPlayerName(packet.name()), "Invalid characters in username", new Object[0]);
+ // Paper start - Validate usernames
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()
+ && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation
+ && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation) {
+ Validate.validState(StringUtil.isReasonablePlayerName(packet.name()), "Invalid characters in username", new Object[0]);
+ }
+ // Paper end - Validate usernames
this.requestedUsername = packet.name();
GameProfile gameprofile = this.server.getSingleplayerProfile();
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -0,0 +0,0 @@ public abstract class PlayerList {
for (int i = 0; i < this.players.size(); ++i) {
entityplayer = (ServerPlayer) this.players.get(i);
- if (entityplayer.getUUID().equals(uuid)) {
+ if (entityplayer.getUUID().equals(uuid) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameprofile.getName()))) { // Paper - validate usernames
list.add(entityplayer);
}
}
diff --git a/src/main/java/net/minecraft/util/StringUtil.java b/src/main/java/net/minecraft/util/StringUtil.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/util/StringUtil.java
+++ b/src/main/java/net/minecraft/util/StringUtil.java
@@ -0,0 +0,0 @@ public class StringUtil {
return name.length() <= 16 && name.chars().filter(c -> c <= 32 || c >= 127).findAny().isEmpty();
}
+ // Paper start - Username validation
+ public static boolean isReasonablePlayerName(final String name) {
+ if (name.isEmpty() || name.length() > 16) {
+ return false;
+ }
+
+ for (int i = 0, len = name.length(); i < len; ++i) {
+ final char c = name.charAt(i);
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_' || c == '.')) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+ // Paper end - Username validation
+
public static String filterText(String string) {
return filterText(string, false);
}

View File

@@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sat, 3 Jul 2021 21:18:28 +0100
Subject: [PATCH] WorldCreator#keepSpawnLoaded
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
}
// If set to not keep spawn in memory (changed from default) then adjust rule accordingly
- if (!creator.keepSpawnInMemory()) {
+ if (creator.keepSpawnLoaded() == net.kyori.adventure.util.TriState.FALSE) { // Paper
worlddata.getGameRules().getRule(GameRules.RULE_SPAWN_CHUNK_RADIUS).set(0, null);
}
ServerLevel internal = (ServerLevel) new ServerLevel(this.console, this.console.executor, worldSession, worlddata, worldKey, worlddimension, this.getServer().progressListenerFactory.create(worlddata.getGameRules().getInt(GameRules.RULE_SPAWN_CHUNK_RADIUS)),

View File

@@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 22 Mar 2022 09:50:40 -0700
Subject: [PATCH] fix player loottables running when mob loot gamerule is false
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -0,0 +0,0 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
}
}
}
+ if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false
// SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule)
this.dropFromLootTable(damageSource, this.lastHurtByPlayerTime > 0);
this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag);
loot.addAll(this.drops);
this.drops.clear(); // SPIGOT-5188: make sure to clear
+ } // Paper - fix player loottables running when mob loot gamerule is false
Component defaultMessage = this.getCombatTracker().getDeathMessage();