More more more more more more more patches
This commit is contained in:
@@ -1,178 +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 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.plugin.Plugin;
|
||||
|
||||
public abstract class ServerCommandSender implements CommandSender {
|
||||
private static PermissibleBase blockPermInst;
|
||||
- private final PermissibleBase perm;
|
||||
+ public final PermissibleBase perm; // Paper
|
||||
private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
||||
|
||||
+ // Paper start
|
||||
+ public ServerCommandSender(final PermissibleBase permissibleBase) {
|
||||
+ this.perm = permissibleBase;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public ServerCommandSender() {
|
||||
if (this instanceof CraftBlockCommandSender) {
|
||||
if (ServerCommandSender.blockPermInst == null) {
|
||||
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");
|
||||
}
|
||||
@@ -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) {
|
||||
item.age = willAge ? 0 : NO_AGE_TIME;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public int getHealth() {
|
||||
+ return item.health;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setHealth(int health) {
|
||||
+ if (health <= 0) {
|
||||
+ item.getItem().onDestroyed(item);
|
||||
+ item.discard();
|
||||
+ } else {
|
||||
+ item.health = health;
|
||||
+ }
|
||||
+ }
|
||||
// Paper End
|
||||
|
||||
@Override
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: SamB440 <sam@islandearth.net>
|
||||
Date: Mon, 15 Nov 2021 18:10:10 +0000
|
||||
Subject: [PATCH] Add PlayerItemFrameChangeEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
||||
@@ -0,0 +0,0 @@ package net.minecraft.world.entity.decoration;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import java.util.OptionalInt;
|
||||
import javax.annotation.Nullable;
|
||||
+import io.papermc.paper.event.player.PlayerItemFrameChangeEvent; // Paper
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -0,0 +0,0 @@ public class ItemFrame extends HangingEntity {
|
||||
return true;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start - call PlayerItemFrameChangeEvent
|
||||
+ if (source.getEntity() instanceof Player player) {
|
||||
+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.REMOVE);
|
||||
+ if (!event.callEvent()) return true; // return true here because you aren't cancelling the damage, just the change
|
||||
+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false);
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.dropItem(source.getEntity(), false);
|
||||
this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ItemFrame extends HangingEntity {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
}
|
||||
-
|
||||
- this.setItem(itemstack);
|
||||
+ // Paper start - call PlayerItemFrameChangeEvent
|
||||
+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemstack.asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE);
|
||||
+ if (!event.callEvent()) return InteractionResult.FAIL;
|
||||
+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()));
|
||||
+ // this.setItem(itemstack);
|
||||
+ // Paper end
|
||||
if (!player.getAbilities().instabuild) {
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
+ // Paper start - call PlayerItemFrameChangeEvent
|
||||
+ var event = new PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), this.getItem().asBukkitCopy(), PlayerItemFrameChangeEvent.ItemFrameChangeAction.ROTATE);
|
||||
+ if (!event.callEvent()) return InteractionResult.FAIL;
|
||||
+ setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false, false);
|
||||
+ // Paper end
|
||||
this.playSound(this.getRotateItemSound(), 1.0F, 1.0F);
|
||||
this.setRotation(this.getRotation() + 1);
|
||||
}
|
||||
@@ -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 - 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 - TameableDeathMessageEvent
|
||||
}
|
||||
|
||||
super.die(damageSource);
|
||||
@@ -1,79 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Noah van der Aa <ndvdaa@gmail.com>
|
||||
Date: Tue, 5 Oct 2021 20:04:21 +0200
|
||||
Subject: [PATCH] Add config option for logging player ip addresses
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
@@ -0,0 +0,0 @@ public class PacketUtils {
|
||||
packet.handle(listener);
|
||||
} catch (Exception exception) {
|
||||
net.minecraft.network.Connection networkmanager = listener.getConnection();
|
||||
+ String playerIP = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "<ip address withheld>"; // Paper
|
||||
if (networkmanager.getPlayer() != null) {
|
||||
- LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getScoreboardName(), networkmanager.getRemoteAddress(), exception);
|
||||
+ LOGGER.error("Error whilst processing packet {} for {}[{}]", packet, networkmanager.getPlayer().getScoreboardName(), playerIP, exception); // Paper
|
||||
} else {
|
||||
- LOGGER.error("Error whilst processing packet {} for connection from {}", packet, networkmanager.getRemoteAddress(), exception);
|
||||
+ LOGGER.error("Error whilst processing packet {} for connection from {}", packet, playerIP, exception); // Paper
|
||||
}
|
||||
net.minecraft.network.chat.Component error = net.minecraft.network.chat.Component.literal("Packet processing error");
|
||||
networkmanager.send(new net.minecraft.network.protocol.game.ClientboundDisconnectPacket(error), net.minecraft.network.PacketSendListener.thenRun(() -> networkmanager.disconnect(error)));
|
||||
diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
@@ -0,0 +0,0 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
buf.release();
|
||||
this.buf = null;
|
||||
|
||||
- LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress());
|
||||
+ LOGGER.debug("Ping: (1.6) from {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? ctx.channel().remoteAddress() : "<ip address withheld>"); // Paper
|
||||
|
||||
InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port);
|
||||
com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java
|
||||
@@ -0,0 +0,0 @@ public class ServerConnectionListener {
|
||||
throw new ReportedException(CrashReport.forThrowable(exception, "Ticking memory connection"));
|
||||
}
|
||||
|
||||
- ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", networkmanager.getRemoteAddress(), exception);
|
||||
+ ServerConnectionListener.LOGGER.warn("Failed to handle packet for {}", io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(networkmanager.getRemoteAddress()) : "<ip address withheld>", exception); // Paper
|
||||
MutableComponent ichatmutablecomponent = Component.literal("Internal server error");
|
||||
|
||||
networkmanager.send(new ClientboundDisconnectPacket(ichatmutablecomponent), PacketSendListener.thenRun(() -> {
|
||||
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,
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
- return this.gameProfile != null ? this.gameProfile + " (" + this.connection.getRemoteAddress() + ")" : String.valueOf(this.connection.getRemoteAddress());
|
||||
+ // Paper start
|
||||
+ String ip = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? String.valueOf(this.connection.getRemoteAddress()) : "<ip address withheld>";
|
||||
+ return this.gameProfile != null ? this.gameProfile + " (" + ip + ")" : String.valueOf(ip);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
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 {
|
||||
String s1 = "local";
|
||||
|
||||
if (connection.getRemoteAddress() != null) {
|
||||
- s1 = connection.getRemoteAddress().toString();
|
||||
+ s1 = io.papermc.paper.configuration.GlobalConfiguration.get().logging.logPlayerIpAddresses ? connection.getRemoteAddress().toString() : "<ip address withheld>"; // Paper
|
||||
}
|
||||
|
||||
// Spigot start - spawn location event
|
||||
@@ -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();
|
||||
@@ -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 {
|
||||
|
||||
public static boolean checkSlimeSpawnRules(EntityType<Slime> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||
if (world.getDifficulty() != Difficulty.PEACEFUL) {
|
||||
- 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
|
||||
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
|
||||
return checkMobSpawnRules(type, world, spawnReason, pos, random);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
+ Validate.notNull(spawnCategory, "SpawnCategory cannot be null");
|
||||
+ Validate.isTrue(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory." + spawnCategory + " does not have a spawn limit.");
|
||||
return this.getSpawnLimitUnsafe(spawnCategory);
|
||||
}
|
||||
public int getSpawnLimitUnsafe(final SpawnCategory spawnCategory) {
|
||||
@@ -1,147 +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 mins and maxes
|
||||
|
||||
|
||||
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/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/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) {
|
||||
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) {
|
||||
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/CraftPowderSnowCauldron.java b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPowderSnowCauldron.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPowderSnowCauldron.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/impl/CraftPowderSnowCauldron.java
|
||||
@@ -0,0 +0,0 @@ public final class CraftPowderSnowCauldron extends org.bukkit.craftbukkit.block.
|
||||
public int getMaximumLevel() {
|
||||
return getMax(CraftPowderSnowCauldron.LEVEL);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public int getMinimumLevel() {
|
||||
+ return getMin(CraftPowderSnowCauldron.LEVEL);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -1,264 +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 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
|
||||
|
||||
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 - 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
|
||||
|
||||
// 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
|
||||
+ if (structureset.placement() instanceof RandomSpreadStructurePlacement randomConfig && holder.unwrapKey().orElseThrow().location().getNamespace().equals(net.minecraft.resources.ResourceLocation.DEFAULT_NAMESPACE)) { // Paper - 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
|
||||
+ case "ancient_cities":
|
||||
+ seed = conf.ancientCitySeed;
|
||||
+ break;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
- structureset = new StructureSet(structureset.structures(), new RandomSpreadStructurePlacement(randomConfig.locateOffset, randomConfig.frequencyReductionMethod, randomConfig.frequency, seed, randomConfig.exclusionZone, randomConfig.spacing(), randomConfig.separation(), randomConfig.spreadType()));
|
||||
+ // Paper start
|
||||
+ 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
|
||||
}).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
|
||||
this.randomState = noiseConfig;
|
||||
this.levelSeed = structureSeed;
|
||||
this.biomeSource = biomeSource;
|
||||
this.concentricRingsSeed = concentricRingSeed;
|
||||
this.possibleStructureSets = structureSets;
|
||||
+ this.conf = conf; // Paper
|
||||
}
|
||||
|
||||
public List<Holder<StructureSet>> possibleStructureSets() {
|
||||
@@ -0,0 +0,0 @@ public class ChunkGeneratorStructureState {
|
||||
HolderSet<Biome> holderset = placement.preferredBiomes();
|
||||
RandomSource randomsource = RandomSource.create();
|
||||
|
||||
+ // Paper start
|
||||
+ if (this.conf.strongholdSeed != null && structureSetEntry.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) {
|
||||
+ randomsource.setSeed(this.conf.strongholdSeed);
|
||||
+ } else {
|
||||
+ // Paper end
|
||||
randomsource.setSeed(this.concentricRingsSeed);
|
||||
+ } // Paper
|
||||
double d0 = randomsource.nextDouble() * 3.141592653589793D * 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 configs
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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
|
||||
public boolean isStructureChunk(ChunkGeneratorStructureState calculator, int chunkX, int chunkZ) {
|
||||
+ // Paper start - add missing structure set 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
|
||||
if (!this.isPlacementChunk(calculator, chunkX, chunkZ)) {
|
||||
return false;
|
||||
- } else if (this.frequency < 1.0F && !this.frequencyReductionMethod.shouldGenerate(calculator.getLevelSeed(), this.salt, chunkX, chunkZ, this.frequency)) {
|
||||
+ } else if (this.frequency < 1.0F && !this.frequencyReductionMethod.shouldGenerate(calculator.getLevelSeed(), this.salt, chunkX, chunkZ, this.frequency, saltOverride)) { // Paper
|
||||
return false;
|
||||
} else {
|
||||
return !this.exclusionZone.isPresent() || !this.exclusionZone.get().isPlacementForbidden(calculator, chunkX, chunkZ);
|
||||
@@ -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 - 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
|
||||
WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
+ if (saltOverride == null) { // Paper
|
||||
worldgenRandom.setLargeFeatureSeed(seed, chunkX, chunkZ);
|
||||
+ // Paper start
|
||||
+ } else {
|
||||
+ worldgenRandom.setLargeFeatureWithSalt(seed, chunkX, chunkZ, saltOverride);
|
||||
+ }
|
||||
+ // Paper end
|
||||
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
|
||||
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
|
||||
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 - 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
|
||||
}
|
||||
|
||||
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
|
||||
+ return this.reducer.shouldGenerate(seed, salt, chunkX, chunkZ, chance, saltOverride); // Paper
|
||||
}
|
||||
|
||||
@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 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.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 );
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: LemonCaramel <admin@caramel.moe>
|
||||
Date: Fri, 16 Jul 2021 00:39:03 +0900
|
||||
Subject: [PATCH] Add more Campfire API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
|
||||
@@ -0,0 +0,0 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
public final int[] cookingProgress;
|
||||
public final int[] cookingTime;
|
||||
private final RecipeManager.CachedCheck<Container, CampfireCookingRecipe> quickCheck;
|
||||
+ public final boolean[] stopCooking; // Paper
|
||||
|
||||
public CampfireBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(BlockEntityType.CAMPFIRE, pos, state);
|
||||
@@ -0,0 +0,0 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
this.cookingProgress = new int[4];
|
||||
this.cookingTime = new int[4];
|
||||
this.quickCheck = RecipeManager.createCheck(RecipeType.CAMPFIRE_COOKING);
|
||||
+ this.stopCooking = new boolean[4]; // Paper
|
||||
}
|
||||
|
||||
public static void cookTick(Level world, BlockPos pos, BlockState state, CampfireBlockEntity campfire) {
|
||||
@@ -0,0 +0,0 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
|
||||
if (!itemstack.isEmpty()) {
|
||||
flag = true;
|
||||
+ if (!campfire.stopCooking[i]) { // Paper
|
||||
int j = campfire.cookingProgress[i]++;
|
||||
+ } // Paper
|
||||
|
||||
if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) {
|
||||
SimpleContainer inventorysubcontainer = new SimpleContainer(new ItemStack[]{itemstack});
|
||||
@@ -0,0 +0,0 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ if (nbt.contains("Paper.StopCooking", org.bukkit.craftbukkit.util.CraftMagicNumbers.NBT.TAG_BYTE_ARRAY)) {
|
||||
+ byte[] abyte = nbt.getByteArray("Paper.StopCooking");
|
||||
+ boolean[] cookingState = new boolean[4];
|
||||
+ for (int index = 0; index < abyte.length; index++) {
|
||||
+ cookingState[index] = abyte[index] == 1;
|
||||
+ }
|
||||
+ System.arraycopy(cookingState, 0, this.stopCooking, 0, Math.min(this.stopCooking.length, abyte.length));
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
|
||||
ContainerHelper.saveAllItems(nbt, this.items, true);
|
||||
nbt.putIntArray("CookingTimes", this.cookingProgress);
|
||||
nbt.putIntArray("CookingTotalTimes", this.cookingTime);
|
||||
+ // Paper start
|
||||
+ byte[] cookingState = new byte[4];
|
||||
+ for (int index = 0; index < cookingState.length; index++) {
|
||||
+ cookingState[index] = (byte) (this.stopCooking[index] ? 1 : 0);
|
||||
+ }
|
||||
+ nbt.putByteArray("Paper.StopCooking", cookingState);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java
|
||||
@@ -0,0 +0,0 @@ public class CraftCampfire extends CraftBlockEntityState<CampfireBlockEntity> im
|
||||
public void setCookTimeTotal(int index, int cookTimeTotal) {
|
||||
getSnapshot().cookingTime[index] = cookTimeTotal;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void stopCooking() {
|
||||
+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i)
|
||||
+ this.stopCooking(i);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void startCooking() {
|
||||
+ for (int i = 0; i < getSnapshot().stopCooking.length; ++i)
|
||||
+ this.startCooking(i);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean stopCooking(int index) {
|
||||
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
|
||||
+ boolean previous = this.isCookingDisabled(index);
|
||||
+ getSnapshot().stopCooking[index] = true;
|
||||
+ return previous;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean startCooking(int index) {
|
||||
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
|
||||
+ boolean previous = this.isCookingDisabled(index);
|
||||
+ getSnapshot().stopCooking[index] = false;
|
||||
+ return previous;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isCookingDisabled(int index) {
|
||||
+ org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)");
|
||||
+ return getSnapshot().stopCooking[index];
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -1,24 +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 new overload to PersistentDataContainer#has
|
||||
|
||||
Adds the new overload: PersistentDataContainer#has(NamespacedKey key)
|
||||
|
||||
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 {
|
||||
public void clear() {
|
||||
this.customDataTags.clear();
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean has(NamespacedKey key) {
|
||||
+ Validate.notNull(key, "The provided key for the custom value was null");
|
||||
+
|
||||
+ return this.customDataTags.containsKey(key.toString());
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 30 Oct 2020 22:37:16 -0700
|
||||
Subject: [PATCH] Add packet limiter config
|
||||
|
||||
Example config:
|
||||
packet-limiter:
|
||||
kick-message: '&cSent too many packets'
|
||||
limits:
|
||||
all:
|
||||
interval: 7.0
|
||||
max-packet-rate: 500.0
|
||||
ServerboundPlaceRecipePacket:
|
||||
interval: 4.0
|
||||
max-packet-rate: 5.0
|
||||
action: DROP
|
||||
|
||||
all section refers to all incoming packets, the action for all is
|
||||
hard coded to KICK.
|
||||
|
||||
For specific limits, the section name is the class's name,
|
||||
and an action can be defined: DROP or KICK
|
||||
|
||||
If interval or rate are less-than 0, the limit is ignored
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
}
|
||||
// Paper end - allow controlled flushing
|
||||
+ // Paper start - packet limiter
|
||||
+ protected final Object PACKET_LIMIT_LOCK = new Object();
|
||||
+ protected final @Nullable io.papermc.paper.util.IntervalledCounter allPacketCounts = io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.isEnabled() ? new io.papermc.paper.util.IntervalledCounter(
|
||||
+ (long)(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.interval() * 1.0e9)
|
||||
+ ) : null;
|
||||
+ protected final java.util.Map<Class<? extends net.minecraft.network.protocol.Packet<?>>, io.papermc.paper.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>();
|
||||
+
|
||||
+ private boolean stopReadingPackets;
|
||||
+ private void killForPacketSpam() {
|
||||
+ this.sendPacket(new ClientboundDisconnectPacket(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)), PacketSendListener.thenRun(() -> {
|
||||
+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage));
|
||||
+ }));
|
||||
+ this.setReadOnly();
|
||||
+ this.stopReadingPackets = true;
|
||||
+ }
|
||||
+ // Paper end - packet limiter
|
||||
|
||||
public Connection(PacketFlow side) {
|
||||
this.receiving = side;
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||
if (this.channel.isOpen()) {
|
||||
+ // Paper start - packet limiter
|
||||
+ if (this.stopReadingPackets) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (this.allPacketCounts != null ||
|
||||
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) {
|
||||
+ long time = System.nanoTime();
|
||||
+ synchronized (PACKET_LIMIT_LOCK) {
|
||||
+ if (this.allPacketCounts != null) {
|
||||
+ this.allPacketCounts.updateAndAdd(1, time);
|
||||
+ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) {
|
||||
+ this.killForPacketSpam();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (Class<?> check = packet.getClass(); check != Object.class; check = check.getSuperclass()) {
|
||||
+ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit =
|
||||
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check);
|
||||
+ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> {
|
||||
+ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9));
|
||||
+ });
|
||||
+ counter.updateAndAdd(1, time);
|
||||
+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) {
|
||||
+ switch (packetSpecificLimit.action()) {
|
||||
+ case DROP:
|
||||
+ return;
|
||||
+ case KICK:
|
||||
+ this.killForPacketSpam();
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - packet limiter
|
||||
try {
|
||||
Connection.genericsFtw(packet, this.packetListener);
|
||||
} catch (RunningOnDifferentThreadException cancelledpackethandleexception) {
|
||||
@@ -1,39 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: SamB440 <sam@islandearth.net>
|
||||
Date: Wed, 17 Nov 2021 12:31:42 +0000
|
||||
Subject: [PATCH] Add player health update API
|
||||
|
||||
|
||||
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().maxHealthCache = getMaxHealth();
|
||||
}
|
||||
|
||||
- public void sendHealthUpdate() {
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void sendHealthUpdate(final double health, final int foodLevel, final float saturationLevel) {
|
||||
// Paper start - cancellable death event
|
||||
- ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel());
|
||||
+ ClientboundSetHealthPacket packet = new ClientboundSetHealthPacket((float) health, foodLevel, saturationLevel);
|
||||
if (this.getHandle().queueHealthUpdatePacket) {
|
||||
this.getHandle().queuedHealthUpdatePacket = packet;
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
-
|
||||
+
|
||||
+ @Override
|
||||
+ public void sendHealthUpdate() {
|
||||
+ this.sendHealthUpdate(this.getScaledHealth(), this.getHandle().getFoodData().getFoodLevel(), this.getHandle().getFoodData().getSaturationLevel());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void injectScaledMaxHealth(Collection<AttributeInstance> collection, boolean force) {
|
||||
if (!this.scaledHealth && !force) {
|
||||
return;
|
||||
@@ -1,79 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: egg82 <eggys82@gmail.com>
|
||||
Date: Sat, 11 Sep 2021 22:55:14 +0200
|
||||
Subject: [PATCH] Add root/admin user detection
|
||||
|
||||
This patch detects whether or not the server is currently executing as a privileged user and spits out a warning.
|
||||
The warning serves as a sort-of PSA for newer server admins who don't understand the risks of running as root.
|
||||
We've seen plenty of bad/malicious plugins hit markets, and there's been a few close-calls with exploits in the past.
|
||||
Hopefully this helps mitigate some potential damage to servers, even if it is just a warning.
|
||||
|
||||
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.util;
|
||||
+
|
||||
+import com.sun.security.auth.module.NTSystem;
|
||||
+import com.sun.security.auth.module.UnixSystem;
|
||||
+import org.apache.commons.lang.SystemUtils;
|
||||
+
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.util.Set;
|
||||
+
|
||||
+public class ServerEnvironment {
|
||||
+ private static final boolean RUNNING_AS_ROOT_OR_ADMIN;
|
||||
+ private static final String WINDOWS_HIGH_INTEGRITY_LEVEL = "S-1-16-12288";
|
||||
+
|
||||
+ static {
|
||||
+ if (SystemUtils.IS_OS_WINDOWS) {
|
||||
+ RUNNING_AS_ROOT_OR_ADMIN = Set.of(new NTSystem().getGroupIDs()).contains(WINDOWS_HIGH_INTEGRITY_LEVEL);
|
||||
+ } else {
|
||||
+ boolean isRunningAsRoot = false;
|
||||
+ if (new UnixSystem().getUid() == 0) {
|
||||
+ // Due to an OpenJDK bug (https://bugs.openjdk.java.net/browse/JDK-8274721), UnixSystem#getUid incorrectly
|
||||
+ // returns 0 when the user doesn't have a username. Because of this, we'll have to double-check if the user ID is
|
||||
+ // actually 0 by running the id -u command.
|
||||
+ try {
|
||||
+ Process process = new ProcessBuilder("id", "-u").start();
|
||||
+ process.waitFor();
|
||||
+ InputStream inputStream = process.getInputStream();
|
||||
+ isRunningAsRoot = new String(inputStream.readAllBytes()).trim().equals("0");
|
||||
+ } catch (InterruptedException | IOException ignored) {
|
||||
+ isRunningAsRoot = false;
|
||||
+ }
|
||||
+ }
|
||||
+ RUNNING_AS_ROOT_OR_ADMIN = isRunningAsRoot;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static boolean userIsRootOrAdmin() {
|
||||
+ return RUNNING_AS_ROOT_OR_ADMIN;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
DedicatedServer.LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
|
||||
}
|
||||
|
||||
+ // Paper start - detect running as root
|
||||
+ if (io.papermc.paper.util.ServerEnvironment.userIsRootOrAdmin()) {
|
||||
+ DedicatedServer.LOGGER.warn("****************************");
|
||||
+ DedicatedServer.LOGGER.warn("YOU ARE RUNNING THIS SERVER AS AN ADMINISTRATIVE OR ROOT USER. THIS IS NOT ADVISED.");
|
||||
+ DedicatedServer.LOGGER.warn("YOU ARE OPENING YOURSELF UP TO POTENTIAL RISKS WHEN DOING THIS.");
|
||||
+ DedicatedServer.LOGGER.warn("FOR MORE INFORMATION, SEE https://madelinemiller.dev/blog/root-minecraft-server/");
|
||||
+ DedicatedServer.LOGGER.warn("****************************");
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
DedicatedServer.LOGGER.info("Loading properties");
|
||||
DedicatedServerProperties dedicatedserverproperties = this.settings.getProperties();
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MCMDEV <john-m.1@gmx.de>
|
||||
Date: Fri, 24 Sep 2021 17:59:21 +0200
|
||||
Subject: [PATCH] Added getHostname to AsyncPlayerPreLoginEvent
|
||||
|
||||
|
||||
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,
|
||||
|
||||
// Paper start
|
||||
com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitMirror(ServerLoginPacketListenerImpl.this.gameProfile);
|
||||
- AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, profile); // Paper - add rawAddress
|
||||
+ AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, profile, ServerLoginPacketListenerImpl.this.connection.hostname); // Paper - add rawAddress & hostname
|
||||
server.getPluginManager().callEvent(asyncEvent);
|
||||
profile = asyncEvent.getPlayerProfile();
|
||||
profile.complete(true); // Paper - setPlayerProfileAPI
|
||||
@@ -1,129 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger | Martin <admin@minidigger.dev>
|
||||
Date: Wed, 29 Apr 2020 02:10:32 +0200
|
||||
Subject: [PATCH] Allow delegation to vanilla chunk gen
|
||||
|
||||
|
||||
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 new OldCraftChunkData(world.getMinHeight(), world.getMaxHeight(), handle.registryAccess().registryOrThrow(Registries.BIOME), world); // Paper - Anti-Xray - Add parameters
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static final List<net.minecraft.world.level.chunk.ChunkStatus> VANILLA_GEN_STATUSES = List.of(
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.EMPTY,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_STARTS,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.STRUCTURE_REFERENCES,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.BIOMES,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.NOISE,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.SURFACE,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.CARVERS,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.LIQUID_CARVERS,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.FEATURES,
|
||||
+ net.minecraft.world.level.chunk.ChunkStatus.LIGHT
|
||||
+ );
|
||||
+
|
||||
+ @Override
|
||||
+ @Deprecated(forRemoval = true)
|
||||
+ public ChunkGenerator.ChunkData createVanillaChunkData(World world, int x, int z) {
|
||||
+ // do bunch of vanilla shit
|
||||
+ final net.minecraft.server.level.ServerLevel serverLevel = ((CraftWorld) world).getHandle();
|
||||
+ final net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry = serverLevel.getServer().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME);
|
||||
+ final net.minecraft.world.level.chunk.ProtoChunk protoChunk = new net.minecraft.world.level.chunk.ProtoChunk(
|
||||
+ new net.minecraft.world.level.ChunkPos(x, z),
|
||||
+ net.minecraft.world.level.chunk.UpgradeData.EMPTY,
|
||||
+ serverLevel,
|
||||
+ biomeRegistry,
|
||||
+ null
|
||||
+ );
|
||||
+
|
||||
+ final net.minecraft.world.level.chunk.ChunkGenerator chunkGenerator;
|
||||
+ if (serverLevel.chunkSource.getGenerator() instanceof org.bukkit.craftbukkit.generator.CustomChunkGenerator bukkit) {
|
||||
+ chunkGenerator = bukkit.getDelegate();
|
||||
+ } else {
|
||||
+ chunkGenerator = serverLevel.chunkSource.getGenerator();
|
||||
+ }
|
||||
+
|
||||
+ final net.minecraft.world.level.ChunkPos chunkPos = new net.minecraft.world.level.ChunkPos(x, z);
|
||||
+ final net.minecraft.util.thread.ProcessorMailbox<Runnable> mailbox = net.minecraft.util.thread.ProcessorMailbox.create(
|
||||
+ net.minecraft.Util.backgroundExecutor(),
|
||||
+ "CraftServer#createVanillaChunkData(worldName='" + world.getName() + "', x='" + x + "', z='" + z + "')"
|
||||
+ );
|
||||
+ for (final net.minecraft.world.level.chunk.ChunkStatus chunkStatus : VANILLA_GEN_STATUSES) {
|
||||
+ final List<net.minecraft.world.level.chunk.ChunkAccess> chunks = Lists.newArrayList();
|
||||
+ final int statusRange = Math.max(1, chunkStatus.getRange());
|
||||
+
|
||||
+ for (int zz = chunkPos.z - statusRange; zz <= chunkPos.z + statusRange; ++zz) {
|
||||
+ for (int xx = chunkPos.x - statusRange; xx <= chunkPos.x + statusRange; ++xx) {
|
||||
+ if (xx == chunkPos.x && zz == chunkPos.z) {
|
||||
+ chunks.add(protoChunk);
|
||||
+ } else {
|
||||
+ final net.minecraft.core.Holder<net.minecraft.world.level.biome.Biome> biomeHolder = serverLevel.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME).getHolderOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS);
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess chunk = new net.minecraft.world.level.chunk.EmptyLevelChunk(serverLevel, new net.minecraft.world.level.ChunkPos(xx, zz), biomeHolder);
|
||||
+ chunks.add(chunk);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ chunkStatus.generate(
|
||||
+ mailbox::tell,
|
||||
+ serverLevel,
|
||||
+ chunkGenerator,
|
||||
+ serverLevel.getStructureManager(),
|
||||
+ serverLevel.chunkSource.getLightEngine(),
|
||||
+ chunk -> {
|
||||
+ throw new UnsupportedOperationException("Not creating full chunks here");
|
||||
+ },
|
||||
+ chunks,
|
||||
+ true
|
||||
+ ).thenAccept(either -> {
|
||||
+ if (chunkStatus == net.minecraft.world.level.chunk.ChunkStatus.NOISE) {
|
||||
+ either.left().ifPresent(chunk -> net.minecraft.world.level.levelgen.Heightmap.primeHeightmaps(chunk, net.minecraft.world.level.chunk.ChunkStatus.POST_FEATURES));
|
||||
+ }
|
||||
+ }).join();
|
||||
+ }
|
||||
+
|
||||
+ // get empty object
|
||||
+ OldCraftChunkData data = (OldCraftChunkData) this.createChunkData(world);
|
||||
+ // copy over generated sections
|
||||
+ data.getLights().addAll(protoChunk.getLights().toList());
|
||||
+ data.setRawChunkData(protoChunk.getSections());
|
||||
+ // hooray!
|
||||
+ return data;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public BossBar createBossBar(String title, BarColor color, BarStyle style, BarFlag... flags) {
|
||||
return new CraftBossBar(title, color, style, flags);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/generator/OldCraftChunkData.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.material.MaterialData;
|
||||
public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
|
||||
private final int minHeight;
|
||||
private final int maxHeight;
|
||||
- private final LevelChunkSection[] sections;
|
||||
+ private LevelChunkSection[] sections; // Paper
|
||||
private final Registry<net.minecraft.world.level.biome.Biome> biomes;
|
||||
private Set<BlockPos> tiles;
|
||||
private final Set<BlockPos> lights = new HashSet<>();
|
||||
@@ -0,0 +0,0 @@ public final class OldCraftChunkData implements ChunkGenerator.ChunkData {
|
||||
return this.tiles;
|
||||
}
|
||||
|
||||
- Set<BlockPos> getLights() {
|
||||
+ public Set<BlockPos> getLights() { // Paper
|
||||
return this.lights;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public void setRawChunkData(LevelChunkSection[] sections) {
|
||||
+ this.sections = sections;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -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 to change the podium for the EnderDragon
|
||||
|
||||
|
||||
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 = new int[24];
|
||||
private final BinaryHeap openSet = new BinaryHeap();
|
||||
private Explosion explosionSource = new Explosion(null, this, null, null, Double.NaN, Double.NaN, Double.NaN, Float.NaN, true, Explosion.BlockInteraction.DESTROY); // CraftBukkit - reusable source for CraftTNTPrimed.getSource()
|
||||
+ // Paper start - add var for save custom podium
|
||||
+ @Nullable
|
||||
+ private BlockPos podium;
|
||||
+ // Paper end
|
||||
|
||||
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
|
||||
+ public BlockPos getPodium() {
|
||||
+ if (this.podium == null) {
|
||||
+ return EndPodiumFeature.END_PODIUM_LOCATION;
|
||||
+ }
|
||||
+ return this.podium;
|
||||
+ }
|
||||
+
|
||||
+ public void setPodium(@Nullable BlockPos blockPos) {
|
||||
+ this.podium = blockPos;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@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.END_PODIUM_LOCATION);
|
||||
+ BlockPos blockposition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - use custom 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.END_PODIUM_LOCATION);
|
||||
+ BlockPos blockposition = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.getPodium()); // Paper - use custom 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 {
|
||||
public void doServerTick() {
|
||||
++this.time;
|
||||
if (this.targetLocation == null) {
|
||||
- BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.END_PODIUM_LOCATION);
|
||||
+ BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.dragon.getPodium()); // Paper - use custom 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 {
|
||||
|
||||
private void findNewTarget() {
|
||||
if (this.currentPath != null && this.currentPath.isDone()) {
|
||||
- BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, new BlockPos(EndPodiumFeature.END_PODIUM_LOCATION));
|
||||
+ BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - use custom 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 {
|
||||
private void findNewTarget() {
|
||||
if (this.currentPath == null || this.currentPath.isDone()) {
|
||||
int i = this.dragon.findClosestNode();
|
||||
- BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.END_PODIUM_LOCATION);
|
||||
+ BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - use custom podium
|
||||
Player player = this.dragon.level.getNearestPlayer(NEAR_EGG_TARGETING, this.dragon, (double)blockPos.getX(), (double)blockPos.getY(), (double)blockPos.getZ());
|
||||
int j;
|
||||
if (player != null) {
|
||||
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 {
|
||||
@Override
|
||||
public void doServerTick() {
|
||||
if (this.targetLocation == null) {
|
||||
- this.targetLocation = Vec3.atBottomCenterOf(this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.END_PODIUM_LOCATION));
|
||||
+ this.targetLocation = Vec3.atBottomCenterOf(this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium())); // Paper - use custom podium
|
||||
}
|
||||
|
||||
if (this.targetLocation.distanceToSqr(this.dragon.getX(), this.dragon.getY(), this.dragon.getZ()) < 1.0D) {
|
||||
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 {
|
||||
@Override
|
||||
public void doServerTick() {
|
||||
if (!this.firstTick && this.currentPath != null) {
|
||||
- BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, EndPodiumFeature.END_PODIUM_LOCATION);
|
||||
+ BlockPos blockPos = this.dragon.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, this.dragon.getPodium()); // Paper - use custom podium
|
||||
if (!blockPos.closerToCenterThan(this.dragon.position(), 10.0D)) {
|
||||
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
|
||||
+ @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(new net.minecraft.core.BlockPos(location.getX(), location.getY(), location.getZ()));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Mon, 21 Jun 2021 22:12:53 -0400
|
||||
Subject: [PATCH] Always allow item changing in Fireball
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/Fireball.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Fireball extends AbstractHurtingProjectile implements Item
|
||||
}
|
||||
|
||||
public void setItem(ItemStack stack) {
|
||||
- if (!stack.is(Items.FIRE_CHARGE) || stack.hasTag()) {
|
||||
+ if (true || !stack.is(Items.FIRE_CHARGE) || stack.hasTag()) { // Paper - always allow item changing
|
||||
this.getEntityData().set(Fireball.DATA_ITEM_STACK, (ItemStack) Util.make(stack.copy(), (itemstack1) -> {
|
||||
itemstack1.setCount(1);
|
||||
}));
|
||||
@@ -1,53 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 23 Aug 2021 04:50:05 -0700
|
||||
Subject: [PATCH] Always parse protochunk light sources unless it is marked as
|
||||
non-lit
|
||||
|
||||
Chunks not marked as lit will always go through the light engine,
|
||||
so they should always have their block sources parsed.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkSerializer {
|
||||
BelowZeroRetrogen belowzeroretrogen = protochunk.getBelowZeroRetrogen();
|
||||
boolean flag5 = chunkstatus.isOrAfter(ChunkStatus.LIGHT) || belowzeroretrogen != null && belowzeroretrogen.targetStatus().isOrAfter(ChunkStatus.LIGHT);
|
||||
|
||||
- if (!flag && flag5) {
|
||||
- Iterator iterator = BlockPos.betweenClosed(chunkPos.getMinBlockX(), world.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), world.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ()).iterator();
|
||||
+ if (!flag) { // Paper - fix incorrect parsing of blocks that emit light - it should always parse it, unless the chunk is marked as lit
|
||||
+ // Paper start - let's make sure the implementation isn't as slow as possible
|
||||
+ int offX = chunkPos.x << 4;
|
||||
+ int offZ = chunkPos.z << 4;
|
||||
+
|
||||
+ int minChunkSection = io.papermc.paper.util.WorldUtil.getMinSection(world);
|
||||
+ int maxChunkSection = io.papermc.paper.util.WorldUtil.getMaxSection(world);
|
||||
+
|
||||
+ LevelChunkSection[] sections = achunksection;
|
||||
+ for (int sectionY = minChunkSection; sectionY <= maxChunkSection; ++sectionY) {
|
||||
+ LevelChunkSection section = sections[sectionY - minChunkSection];
|
||||
+ if (section == null || section.hasOnlyAir()) {
|
||||
+ // no sources in empty sections
|
||||
+ continue;
|
||||
+ }
|
||||
+ int offY = sectionY << 4;
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
- BlockPos blockposition = (BlockPos) iterator.next();
|
||||
+ for (int index = 0; index < (16 * 16 * 16); ++index) {
|
||||
+ if (section.states.get(index).getLightEmission() <= 0) {
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
- if (((ChunkAccess) object1).getBlockState(blockposition).getLightEmission() != 0) {
|
||||
- protochunk.addLight(blockposition);
|
||||
+ // index = x | (z << 4) | (y << 8)
|
||||
+ protochunk.addLight(new BlockPos(offX | (index & 15), offY | (index >>> 8), offZ | ((index >>> 4) & 15)));
|
||||
}
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 31 Oct 2021 21:34:00 -0700
|
||||
Subject: [PATCH] Async catch modifications to critical entity state
|
||||
|
||||
These used to be here from Spigot, but were dropped with 1.17.
|
||||
Now in 1.17, this state is _even more_ critical than it was before,
|
||||
so these must exist to catch stupid plugins.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
private boolean addEntityUuid(T entity) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper
|
||||
if (!this.knownUuids.add(entity.getUUID())) {
|
||||
PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity);
|
||||
return false;
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
private boolean addEntity(T entity, boolean existing) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper
|
||||
// Paper start - chunk system hooks
|
||||
if (existing) {
|
||||
// I don't want to know why this is a generic type.
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
void startTicking(T entity) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper
|
||||
this.callbacks.onTickingStart(entity);
|
||||
}
|
||||
|
||||
void stopTicking(T entity) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper
|
||||
this.callbacks.onTickingEnd(entity);
|
||||
}
|
||||
|
||||
void startTracking(T entity) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper
|
||||
this.visibleEntityStorage.add(entity);
|
||||
this.callbacks.onTrackingStart(entity);
|
||||
}
|
||||
|
||||
void stopTracking(T entity) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper
|
||||
this.callbacks.onTrackingEnd(entity);
|
||||
this.visibleEntityStorage.remove(entity);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper
|
||||
long i = chunkPos.toLong();
|
||||
|
||||
if (trackingStatus == Visibility.HIDDEN) {
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void ensureChunkQueuedForLoad(long chunkPos) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper
|
||||
PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos);
|
||||
|
||||
if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) {
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
private void requestChunkLoad(long chunkPos) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper
|
||||
this.chunkLoadStatuses.put(chunkPos, PersistentEntitySectionManager.ChunkLoadStatus.PENDING);
|
||||
ChunkPos chunkcoordintpair = new ChunkPos(chunkPos);
|
||||
CompletableFuture completablefuture = this.permanentStorage.loadEntities(chunkcoordintpair);
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
private boolean processChunkUnload(long chunkPos) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper
|
||||
boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> {
|
||||
entityaccess.getPassengersAndSelf().forEach(this::unloadEntity);
|
||||
}, true); // CraftBukkit - add boolean for event call
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
private void processPendingLoads() {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper
|
||||
ChunkEntities<T> chunkentities; // CraftBukkit - decompile error
|
||||
|
||||
while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) {
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper
|
||||
this.processPendingLoads();
|
||||
this.processUnloads();
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void autoSave() {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper
|
||||
this.getAllChunksToSave().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error
|
||||
boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN;
|
||||
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper
|
||||
LongSet longset = this.getAllChunksToSave();
|
||||
|
||||
while (!longset.isEmpty()) {
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
long i = SectionPos.asLong(blockposition);
|
||||
|
||||
if (i != this.currentSectionKey) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper
|
||||
Visibility visibility = this.currentSection.getStatus();
|
||||
|
||||
if (!this.currentSection.remove(this.entity)) {
|
||||
@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
|
||||
|
||||
@Override
|
||||
public void onRemove(Entity.RemovalReason reason) {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper
|
||||
if (!this.currentSection.remove(this.entity)) {
|
||||
PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), reason});
|
||||
}
|
||||
@@ -1,766 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 2 Feb 2020 02:25:10 -0800
|
||||
Subject: [PATCH] Attempt to recalculate regionfile header if it is corrupt
|
||||
|
||||
Instead of trying to relocate the chunk, which is seems to never
|
||||
be the correct choice, so we end up duplicating or swapping chunks,
|
||||
we instead drop the current regionfile header and recalculate -
|
||||
hoping that at least then we don't swap chunks, and maybe recover
|
||||
them all.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.ticks.ProtoChunkTicks;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public class ChunkSerializer {
|
||||
+ // Paper start
|
||||
+ // TODO: Check on update
|
||||
+ public static long getLastWorldSaveTime(CompoundTag chunkData) {
|
||||
+ final int dataVersion = ChunkStorage.getVersion(chunkData);
|
||||
+ if (dataVersion < 2842) { // Level tag is removed after this version
|
||||
+ final CompoundTag levelData = chunkData.getCompound("Level");
|
||||
+ return levelData.getLong("LastUpdate");
|
||||
+ } else {
|
||||
+ return chunkData.getLong("LastUpdate");
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), null); // Paper - Anti-Xray - Add preset block states
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -0,0 +0,0 @@ public class ChunkSerializer {
|
||||
nbttagcompound.putInt("xPos", chunkcoordintpair.x);
|
||||
nbttagcompound.putInt("yPos", chunk.getMinSection());
|
||||
nbttagcompound.putInt("zPos", chunkcoordintpair.z);
|
||||
- nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading
|
||||
+ nbttagcompound.putLong("LastUpdate", asyncsavedata != null ? asyncsavedata.worldTime : world.getGameTime()); // Paper - async chunk unloading // Paper - diff on change
|
||||
nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime());
|
||||
nbttagcompound.putString("Status", chunk.getStatus().getName());
|
||||
BlendingData blendingdata = chunk.getBlendingData();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
|
||||
this.fixerUpper = dataFixer;
|
||||
// Paper start - async chunk io
|
||||
// remove IO worker
|
||||
- this.regionFileCache = new RegionFileStorage(directory, dsync); // Paper - nuke IOWorker
|
||||
+ this.regionFileCache = new RegionFileStorage(directory, dsync, true); // Paper - nuke IOWorker // Paper
|
||||
// Paper end - async chunk io
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionBitmap.java
|
||||
@@ -0,0 +0,0 @@ import java.util.BitSet;
|
||||
public class RegionBitmap {
|
||||
private final BitSet used = new BitSet();
|
||||
|
||||
+ // Paper start
|
||||
+ public final void copyFrom(RegionBitmap other) {
|
||||
+ BitSet thisBitset = this.used;
|
||||
+ BitSet otherBitset = other.used;
|
||||
+
|
||||
+ for (int i = 0; i < Math.max(thisBitset.size(), otherBitset.size()); ++i) {
|
||||
+ thisBitset.set(i, otherBitset.get(i));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public final boolean tryAllocate(int from, int length) {
|
||||
+ BitSet bitset = this.used;
|
||||
+ int firstSet = bitset.nextSetBit(from);
|
||||
+ if (firstSet > 0 && firstSet < (from + length)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ bitset.set(from, from + length);
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void force(int start, int size) {
|
||||
this.used.set(start, start + size);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper
|
||||
public final Path regionFile; // Paper
|
||||
|
||||
+ // Paper start - try to recover from RegionFile header corruption
|
||||
+ private static long roundToSectors(long bytes) {
|
||||
+ long sectors = bytes >>> 12; // 4096 = 2^12
|
||||
+ long remainingBytes = bytes & 4095;
|
||||
+ long sign = -remainingBytes; // sign is 1 if nonzero
|
||||
+ return sectors + (sign >>> 63);
|
||||
+ }
|
||||
+
|
||||
+ private static final CompoundTag OVERSIZED_COMPOUND = new CompoundTag();
|
||||
+
|
||||
+ private CompoundTag attemptRead(long sector, int chunkDataLength, long fileLength) throws IOException {
|
||||
+ try {
|
||||
+ if (chunkDataLength < 0) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ long offset = sector * 4096L + 4L; // offset for chunk data
|
||||
+
|
||||
+ if ((offset + chunkDataLength) > fileLength) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ByteBuffer chunkData = ByteBuffer.allocate(chunkDataLength);
|
||||
+ if (chunkDataLength != this.file.read(chunkData, offset)) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ((java.nio.Buffer)chunkData).flip();
|
||||
+
|
||||
+ byte compressionType = chunkData.get();
|
||||
+ if (compressionType < 0) { // compressionType & 128 != 0
|
||||
+ // oversized chunk
|
||||
+ return OVERSIZED_COMPOUND;
|
||||
+ }
|
||||
+
|
||||
+ RegionFileVersion compression = RegionFileVersion.fromId(compressionType);
|
||||
+ if (compression == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ InputStream input = compression.wrap(new ByteArrayInputStream(chunkData.array(), chunkData.position(), chunkDataLength - chunkData.position()));
|
||||
+
|
||||
+ return NbtIo.read(new DataInputStream(input));
|
||||
+ } catch (Exception ex) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private int getLength(long sector) throws IOException {
|
||||
+ ByteBuffer length = ByteBuffer.allocate(4);
|
||||
+ if (4 != this.file.read(length, sector * 4096L)) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return length.getInt(0);
|
||||
+ }
|
||||
+
|
||||
+ private void backupRegionFile() {
|
||||
+ Path backup = this.regionFile.getParent().resolve(this.regionFile.getFileName() + "." + new java.util.Random().nextLong() + ".backup");
|
||||
+ this.backupRegionFile(backup);
|
||||
+ }
|
||||
+
|
||||
+ private void backupRegionFile(Path to) {
|
||||
+ try {
|
||||
+ this.file.force(true);
|
||||
+ LOGGER.warn("Backing up regionfile \"" + this.regionFile.toAbsolutePath() + "\" to " + to.toAbsolutePath());
|
||||
+ java.nio.file.Files.copy(this.regionFile, to, java.nio.file.StandardCopyOption.COPY_ATTRIBUTES);
|
||||
+ LOGGER.warn("Backed up the regionfile to " + to.toAbsolutePath());
|
||||
+ } catch (IOException ex) {
|
||||
+ LOGGER.error("Failed to backup to " + to.toAbsolutePath(), ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static boolean inSameRegionfile(ChunkPos first, ChunkPos second) {
|
||||
+ return (first.x & ~31) == (second.x & ~31) && (first.z & ~31) == (second.z & ~31);
|
||||
+ }
|
||||
+
|
||||
+ // note: only call for CHUNK regionfiles
|
||||
+ boolean recalculateHeader() throws IOException {
|
||||
+ if (!this.canRecalcHeader) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ ChunkPos ourLowerLeftPosition = RegionFileStorage.getRegionFileCoordinates(this.regionFile);
|
||||
+ if (ourLowerLeftPosition == null) {
|
||||
+ LOGGER.error("Unable to get chunk location of regionfile " + this.regionFile.toAbsolutePath() + ", cannot recover header");
|
||||
+ return false;
|
||||
+ }
|
||||
+ synchronized (this) {
|
||||
+ LOGGER.warn("Corrupt regionfile header detected! Attempting to re-calculate header offsets for regionfile " + this.regionFile.toAbsolutePath(), new Throwable());
|
||||
+
|
||||
+ // try to backup file so maybe it could be sent to us for further investigation
|
||||
+
|
||||
+ this.backupRegionFile();
|
||||
+ CompoundTag[] compounds = new CompoundTag[32 * 32]; // only in the regionfile (i.e exclude mojang/aikar oversized data)
|
||||
+ int[] rawLengths = new int[32 * 32]; // length of chunk data including 4 byte length field, bytes
|
||||
+ int[] sectorOffsets = new int[32 * 32]; // in sectors
|
||||
+ boolean[] hasAikarOversized = new boolean[32 * 32];
|
||||
+
|
||||
+ long fileLength = this.file.size();
|
||||
+ long totalSectors = roundToSectors(fileLength);
|
||||
+
|
||||
+ // search the regionfile from start to finish for the most up-to-date chunk data
|
||||
+
|
||||
+ for (long i = 2, maxSector = Math.min((long)(Integer.MAX_VALUE >>> 8), totalSectors); i < maxSector; ++i) { // first two sectors are header, skip
|
||||
+ int chunkDataLength = this.getLength(i);
|
||||
+ CompoundTag compound = this.attemptRead(i, chunkDataLength, fileLength);
|
||||
+ if (compound == null || compound == OVERSIZED_COMPOUND) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(compound);
|
||||
+ if (!inSameRegionfile(ourLowerLeftPosition, chunkPos)) {
|
||||
+ LOGGER.error("Ignoring absolute chunk " + chunkPos + " in regionfile as it is not contained in the bounds of the regionfile '" + this.regionFile.toAbsolutePath() + "'. It should be in regionfile (" + (chunkPos.x >> 5) + "," + (chunkPos.z >> 5) + ")");
|
||||
+ continue;
|
||||
+ }
|
||||
+ int location = (chunkPos.x & 31) | ((chunkPos.z & 31) << 5);
|
||||
+
|
||||
+ CompoundTag otherCompound = compounds[location];
|
||||
+
|
||||
+ if (otherCompound != null && ChunkSerializer.getLastWorldSaveTime(otherCompound) > ChunkSerializer.getLastWorldSaveTime(compound)) {
|
||||
+ continue; // don't overwrite newer data.
|
||||
+ }
|
||||
+
|
||||
+ // aikar oversized?
|
||||
+ Path aikarOversizedFile = this.getOversizedFile(chunkPos.x, chunkPos.z);
|
||||
+ boolean isAikarOversized = false;
|
||||
+ if (Files.exists(aikarOversizedFile)) {
|
||||
+ try {
|
||||
+ CompoundTag aikarOversizedCompound = this.getOversizedData(chunkPos.x, chunkPos.z);
|
||||
+ if (ChunkSerializer.getLastWorldSaveTime(compound) == ChunkSerializer.getLastWorldSaveTime(aikarOversizedCompound)) {
|
||||
+ // best we got for an id. hope it's good enough
|
||||
+ isAikarOversized = true;
|
||||
+ }
|
||||
+ } catch (Exception ex) {
|
||||
+ LOGGER.error("Failed to read aikar oversized data for absolute chunk (" + chunkPos.x + "," + chunkPos.z + ") in regionfile " + this.regionFile.toAbsolutePath() + ", oversized data for this chunk will be lost", ex);
|
||||
+ // fall through, if we can't read aikar oversized we can't risk corrupting chunk data
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ hasAikarOversized[location] = isAikarOversized;
|
||||
+ compounds[location] = compound;
|
||||
+ rawLengths[location] = chunkDataLength + 4;
|
||||
+ sectorOffsets[location] = (int)i;
|
||||
+
|
||||
+ int chunkSectorLength = (int)roundToSectors(rawLengths[location]);
|
||||
+ i += chunkSectorLength;
|
||||
+ --i; // gets incremented next iteration
|
||||
+ }
|
||||
+
|
||||
+ // forge style oversized data is already handled by the local search, and aikar data we just hope
|
||||
+ // we get it right as aikar data has no identifiers we could use to try and find its corresponding
|
||||
+ // local data compound
|
||||
+
|
||||
+ java.nio.file.Path containingFolder = this.externalFileDir;
|
||||
+ Path[] regionFiles = Files.list(containingFolder).toArray(Path[]::new);
|
||||
+ boolean[] oversized = new boolean[32 * 32];
|
||||
+ RegionFileVersion[] oversizedCompressionTypes = new RegionFileVersion[32 * 32];
|
||||
+
|
||||
+ if (regionFiles != null) {
|
||||
+ int lowerXBound = ourLowerLeftPosition.x; // inclusive
|
||||
+ int lowerZBound = ourLowerLeftPosition.z; // inclusive
|
||||
+ int upperXBound = lowerXBound + 32 - 1; // inclusive
|
||||
+ int upperZBound = lowerZBound + 32 - 1; // inclusive
|
||||
+
|
||||
+ // read mojang oversized data
|
||||
+ for (Path regionFile : regionFiles) {
|
||||
+ ChunkPos oversizedCoords = getOversizedChunkPair(regionFile);
|
||||
+ if (oversizedCoords == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if ((oversizedCoords.x < lowerXBound || oversizedCoords.x > upperXBound) || (oversizedCoords.z < lowerZBound || oversizedCoords.z > upperZBound)) {
|
||||
+ continue; // not in our regionfile
|
||||
+ }
|
||||
+
|
||||
+ // ensure oversized data is valid & is newer than data in the regionfile
|
||||
+
|
||||
+ int location = (oversizedCoords.x & 31) | ((oversizedCoords.z & 31) << 5);
|
||||
+
|
||||
+ byte[] chunkData;
|
||||
+ try {
|
||||
+ chunkData = Files.readAllBytes(regionFile);
|
||||
+ } catch (Exception ex) {
|
||||
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", data will be lost", ex);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ CompoundTag compound = null;
|
||||
+
|
||||
+ // We do not know the compression type, as it's stored in the regionfile. So we need to try all of them
|
||||
+ RegionFileVersion compression = null;
|
||||
+ for (RegionFileVersion compressionType : RegionFileVersion.VERSIONS.values()) {
|
||||
+ try {
|
||||
+ DataInputStream in = new DataInputStream(compressionType.wrap(new ByteArrayInputStream(chunkData))); // typical java
|
||||
+ compound = NbtIo.read((java.io.DataInput)in);
|
||||
+ compression = compressionType;
|
||||
+ break; // reaches here iff readNBT does not throw
|
||||
+ } catch (Exception ex) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (compound == null) {
|
||||
+ LOGGER.error("Failed to read oversized chunk data in file " + regionFile.toAbsolutePath() + ", it's corrupt. Its data will be lost");
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (!ChunkSerializer.getChunkCoordinate(compound).equals(oversizedCoords)) {
|
||||
+ LOGGER.error("Can't use oversized chunk stored in " + regionFile.toAbsolutePath() + ", got absolute chunkpos: " + ChunkSerializer.getChunkCoordinate(compound) + ", expected " + oversizedCoords);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (compounds[location] == null || ChunkSerializer.getLastWorldSaveTime(compound) > ChunkSerializer.getLastWorldSaveTime(compounds[location])) {
|
||||
+ oversized[location] = true;
|
||||
+ oversizedCompressionTypes[location] = compression;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // now we need to calculate a new offset header
|
||||
+
|
||||
+ int[] calculatedOffsets = new int[32 * 32];
|
||||
+ RegionBitmap newSectorAllocations = new RegionBitmap();
|
||||
+ newSectorAllocations.force(0, 2); // make space for header
|
||||
+
|
||||
+ // allocate sectors for normal chunks
|
||||
+
|
||||
+ for (int chunkX = 0; chunkX < 32; ++chunkX) {
|
||||
+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) {
|
||||
+ int location = chunkX | (chunkZ << 5);
|
||||
+
|
||||
+ if (oversized[location]) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ int rawLength = rawLengths[location]; // bytes
|
||||
+ int sectorOffset = sectorOffsets[location]; // sectors
|
||||
+ int sectorLength = (int)roundToSectors(rawLength);
|
||||
+
|
||||
+ if (newSectorAllocations.tryAllocate(sectorOffset, sectorLength)) {
|
||||
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
|
||||
+ } else {
|
||||
+ LOGGER.error("Failed to allocate space for local chunk (overlapping data??) at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath() + ", chunk will be regenerated");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // allocate sectors for oversized chunks
|
||||
+
|
||||
+ for (int chunkX = 0; chunkX < 32; ++chunkX) {
|
||||
+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) {
|
||||
+ int location = chunkX | (chunkZ << 5);
|
||||
+
|
||||
+ if (!oversized[location]) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ int sectorOffset = newSectorAllocations.allocate(1);
|
||||
+ int sectorLength = 1;
|
||||
+
|
||||
+ try {
|
||||
+ this.file.write(this.createExternalStub(oversizedCompressionTypes[location]), sectorOffset * 4096);
|
||||
+ // only allocate in the new offsets if the write succeeds
|
||||
+ calculatedOffsets[location] = sectorOffset << 8 | (sectorLength > 255 ? 255 : sectorLength); // support forge style oversized
|
||||
+ } catch (IOException ex) {
|
||||
+ newSectorAllocations.free(sectorOffset, sectorLength);
|
||||
+ LOGGER.error("Failed to write new oversized chunk data holder, local chunk at (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath() + " will be regenerated");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // rewrite aikar oversized data
|
||||
+
|
||||
+ this.oversizedCount = 0;
|
||||
+ for (int chunkX = 0; chunkX < 32; ++chunkX) {
|
||||
+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) {
|
||||
+ int location = chunkX | (chunkZ << 5);
|
||||
+ int isAikarOversized = hasAikarOversized[location] ? 1 : 0;
|
||||
+
|
||||
+ this.oversizedCount += isAikarOversized;
|
||||
+ this.oversized[location] = (byte)isAikarOversized;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (this.oversizedCount > 0) {
|
||||
+ try {
|
||||
+ this.writeOversizedMeta();
|
||||
+ } catch (Exception ex) {
|
||||
+ LOGGER.error("Failed to write aikar oversized chunk meta, all aikar style oversized chunk data will be lost for regionfile " + this.regionFile.toAbsolutePath(), ex);
|
||||
+ Files.deleteIfExists(this.getOversizedMetaFile());
|
||||
+ }
|
||||
+ } else {
|
||||
+ Files.deleteIfExists(this.getOversizedMetaFile());
|
||||
+ }
|
||||
+
|
||||
+ this.usedSectors.copyFrom(newSectorAllocations);
|
||||
+
|
||||
+ // before we overwrite the old sectors, print a summary of the chunks that got changed.
|
||||
+
|
||||
+ LOGGER.info("Starting summary of changes for regionfile " + this.regionFile.toAbsolutePath());
|
||||
+
|
||||
+ for (int chunkX = 0; chunkX < 32; ++chunkX) {
|
||||
+ for (int chunkZ = 0; chunkZ < 32; ++chunkZ) {
|
||||
+ int location = chunkX | (chunkZ << 5);
|
||||
+
|
||||
+ int oldOffset = this.offsets.get(location);
|
||||
+ int newOffset = calculatedOffsets[location];
|
||||
+
|
||||
+ if (oldOffset == newOffset) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ this.offsets.put(location, newOffset); // overwrite incorrect offset
|
||||
+
|
||||
+ if (oldOffset == 0) {
|
||||
+ // found lost data
|
||||
+ LOGGER.info("Found missing data for local chunk (" + chunkX + "," + chunkZ + ") in regionfile " + this.regionFile.toAbsolutePath());
|
||||
+ } else if (newOffset == 0) {
|
||||
+ LOGGER.warn("Data for local chunk (" + chunkX + "," + chunkZ + ") could not be recovered in regionfile " + this.regionFile.toAbsolutePath() + ", it will be regenerated");
|
||||
+ } else {
|
||||
+ LOGGER.info("Local chunk (" + chunkX + "," + chunkZ + ") changed to point to newer data or correct chunk in regionfile " + this.regionFile.toAbsolutePath());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ LOGGER.info("End of change summary for regionfile " + this.regionFile.toAbsolutePath());
|
||||
+
|
||||
+ // simply destroy the timestamp header, it's not used
|
||||
+
|
||||
+ for (int i = 0; i < 32 * 32; ++i) {
|
||||
+ this.timestamps.put(i, calculatedOffsets[i] != 0 ? (int)System.currentTimeMillis() : 0); // write a valid timestamp for valid chunks, I do not want to find out whatever dumb program actually checks this
|
||||
+ }
|
||||
+
|
||||
+ // write new header
|
||||
+ try {
|
||||
+ this.flush();
|
||||
+ this.file.force(true); // try to ensure it goes through...
|
||||
+ LOGGER.info("Successfully wrote new header to disk for regionfile " + this.regionFile.toAbsolutePath());
|
||||
+ } catch (IOException ex) {
|
||||
+ LOGGER.error("Failed to write new header to disk for regionfile " + this.regionFile.toAbsolutePath(), ex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ final boolean canRecalcHeader; // final forces compile fail on new constructor
|
||||
+ // Paper end
|
||||
+
|
||||
// Paper start - Cache chunk status
|
||||
private final net.minecraft.world.level.chunk.ChunkStatus[] statuses = new net.minecraft.world.level.chunk.ChunkStatus[32 * 32];
|
||||
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
public RegionFile(Path file, Path directory, boolean dsync) throws IOException {
|
||||
this(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync);
|
||||
}
|
||||
+ // Paper start - add can recalc flag
|
||||
+ public RegionFile(Path file, Path directory, boolean dsync, boolean canRecalcHeader) throws IOException {
|
||||
+ this(file, directory, RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader);
|
||||
+ }
|
||||
+ // Paper end - add can recalc flag
|
||||
|
||||
public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException {
|
||||
+ // Paper start - add can recalc flag
|
||||
+ this(file, directory, outputChunkStreamVersion, dsync, false);
|
||||
+ }
|
||||
+ public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync, boolean canRecalcHeader) throws IOException {
|
||||
+ this.canRecalcHeader = canRecalcHeader;
|
||||
+ // Paper end - add can recalc flag
|
||||
this.header = ByteBuffer.allocateDirect(8192);
|
||||
this.regionFile = file; // Paper
|
||||
initOversizedState(); // Paper
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
RegionFile.LOGGER.warn("Region file {} has truncated header: {}", file, i);
|
||||
}
|
||||
|
||||
- long j = Files.size(file);
|
||||
+ final long j = Files.size(file); final long regionFileSize = j; // Paper - recalculate header on header corruption
|
||||
|
||||
- for (int k = 0; k < 1024; ++k) {
|
||||
- int l = this.offsets.get(k);
|
||||
+ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption
|
||||
+ boolean hasBackedUp = false; // Paper - recalculate header on header corruption
|
||||
+ for (int k = 0; k < 1024; ++k) { final int headerLocation = k; // Paper - we expect this to be the header location
|
||||
+ final int l = this.offsets.get(k);
|
||||
|
||||
if (l != 0) {
|
||||
- int i1 = RegionFile.getSectorNumber(l);
|
||||
- int j1 = RegionFile.getNumSectors(l);
|
||||
+ final int i1 = RegionFile.getSectorNumber(l); final int offset = i1; // Paper - we expect this to be offset in file in sectors
|
||||
+ int j1 = RegionFile.getNumSectors(l); final int sectorLength; // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments
|
||||
// Spigot start
|
||||
if (j1 == 255) {
|
||||
// We're maxed out, so we need to read the proper length from the section
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
j1 = (realLen.getInt(0) + 4) / 4096 + 1;
|
||||
}
|
||||
// Spigot end
|
||||
+ sectorLength = j1; // Paper - diff on change, we expect this to be sector length of region
|
||||
|
||||
if (i1 < 2) {
|
||||
RegionFile.LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", new Object[]{file, k, i1});
|
||||
- this.offsets.put(k, 0);
|
||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if (j1 == 0) {
|
||||
RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", file, k);
|
||||
- this.offsets.put(k, 0);
|
||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else if ((long) i1 * 4096L > j) {
|
||||
RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", new Object[]{file, k, i1});
|
||||
- this.offsets.put(k, 0);
|
||||
+ //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
|
||||
} else {
|
||||
- this.usedSectors.force(i1, j1);
|
||||
+ //this.usedSectors.force(i1, j1); // Paper - move this down so we can check if it fails to allocate
|
||||
+ }
|
||||
+ // Paper start - recalculate header on header corruption
|
||||
+ if (offset < 2 || sectorLength <= 0 || ((long)offset * 4096L) > regionFileSize) {
|
||||
+ if (canRecalcHeader) {
|
||||
+ LOGGER.error("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() + "! Recalculating header...");
|
||||
+ needsHeaderRecalc = true;
|
||||
+ break;
|
||||
+ } else {
|
||||
+ // location = chunkX | (chunkZ << 5);
|
||||
+ LOGGER.error("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() +
|
||||
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
|
||||
+ if (!hasBackedUp) {
|
||||
+ hasBackedUp = true;
|
||||
+ this.backupRegionFile();
|
||||
+ }
|
||||
+ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too
|
||||
+ this.offsets.put(headerLocation, 0); // delete the entry from header
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ boolean failedToAllocate = !this.usedSectors.tryAllocate(offset, sectorLength);
|
||||
+ if (failedToAllocate) {
|
||||
+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.regionFile.toAbsolutePath());
|
||||
}
|
||||
+ if (failedToAllocate & !canRecalcHeader) {
|
||||
+ // location = chunkX | (chunkZ << 5);
|
||||
+ LOGGER.error("Detected invalid header for regionfile " + this.regionFile.toAbsolutePath() +
|
||||
+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header");
|
||||
+ if (!hasBackedUp) {
|
||||
+ hasBackedUp = true;
|
||||
+ this.backupRegionFile();
|
||||
+ }
|
||||
+ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too
|
||||
+ this.offsets.put(headerLocation, 0); // delete the entry from header
|
||||
+ continue;
|
||||
+ }
|
||||
+ needsHeaderRecalc |= failedToAllocate;
|
||||
+ // Paper end - recalculate header on header corruption
|
||||
}
|
||||
}
|
||||
+ // Paper start - recalculate header on header corruption
|
||||
+ // we move the recalc here so comparison to old header is correct when logging to console
|
||||
+ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues
|
||||
+ LOGGER.error("Recalculating regionfile " + this.regionFile.toAbsolutePath() + ", header gave erroneous offsets & locations");
|
||||
+ this.recalculateHeader();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Path getExternalChunkPath(ChunkPos chunkPos) {
|
||||
- String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc";
|
||||
+ String s = "c." + chunkPos.x + "." + chunkPos.z + ".mcc"; // Paper - diff on change
|
||||
|
||||
return this.externalFileDir.resolve(s);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static ChunkPos getOversizedChunkPair(Path file) {
|
||||
+ String fileName = file.getFileName().toString();
|
||||
+
|
||||
+ if (!fileName.startsWith("c.") || !fileName.endsWith(".mcc")) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ String[] split = fileName.split("\\.");
|
||||
+
|
||||
+ if (split.length != 4) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ int x = Integer.parseInt(split[1]);
|
||||
+ int z = Integer.parseInt(split[2]);
|
||||
+
|
||||
+ return new ChunkPos(x, z);
|
||||
+ } catch (NumberFormatException ex) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Nullable
|
||||
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException {
|
||||
int i = this.getOffset(pos);
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error
|
||||
if (bytebuffer.remaining() < 5) {
|
||||
RegionFile.LOGGER.error("Chunk {} header is truncated: expected {} but read {}", new Object[]{pos, l, bytebuffer.remaining()});
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
int i1 = bytebuffer.getInt();
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
|
||||
if (i1 == 0) {
|
||||
RegionFile.LOGGER.warn("Chunk {} is allocated, but stream is missing", pos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
int j1 = i1 - 1;
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
if (RegionFile.isExternalStreamChunk(b0)) {
|
||||
if (j1 != 0) {
|
||||
RegionFile.LOGGER.warn("Chunk has both internal and external streams");
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
}
|
||||
|
||||
- return this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createExternalChunkInputStream(pos, RegionFile.getExternalChunkVersion(b0));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
} else if (j1 > bytebuffer.remaining()) {
|
||||
RegionFile.LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", new Object[]{pos, j1, bytebuffer.remaining()});
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else if (j1 < 0) {
|
||||
RegionFile.LOGGER.error("Declared size {} of chunk {} is negative", i1, pos);
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ if (this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
return null;
|
||||
} else {
|
||||
- return this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
|
||||
+ // Paper start - recalculate header on regionfile corruption
|
||||
+ final DataInputStream ret = this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
|
||||
+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) {
|
||||
+ return this.getChunkDataInputStream(pos);
|
||||
+ }
|
||||
+ return ret;
|
||||
+ // Paper end - recalculate header on regionfile corruption
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
}
|
||||
|
||||
private ByteBuffer createExternalStub() {
|
||||
+ // Paper start - add version param
|
||||
+ return this.createExternalStub(this.version);
|
||||
+ }
|
||||
+ private ByteBuffer createExternalStub(RegionFileVersion version) {
|
||||
+ // Paper end - add version param
|
||||
ByteBuffer bytebuffer = ByteBuffer.allocate(5);
|
||||
|
||||
bytebuffer.putInt(1);
|
||||
- bytebuffer.put((byte) (this.version.getId() | 128));
|
||||
+ bytebuffer.put((byte) (version.getId() | 128)); // Paper - replace with version param
|
||||
((java.nio.Buffer) bytebuffer).flip(); // CraftBukkit - decompile error
|
||||
return bytebuffer;
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
private final Path folder;
|
||||
private final boolean sync;
|
||||
|
||||
+ private final boolean isChunkData; // Paper
|
||||
+
|
||||
protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor
|
||||
+ // Paper start - add isChunkData param
|
||||
+ this(directory, dsync, false);
|
||||
+ }
|
||||
+ RegionFileStorage(Path directory, boolean dsync, boolean isChunkData) {
|
||||
+ this.isChunkData = isChunkData;
|
||||
+ // Paper end - add isChunkData param
|
||||
this.folder = directory;
|
||||
this.sync = dsync;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
FileUtil.createDirectoriesSafe(this.folder);
|
||||
Path path = this.folder;
|
||||
int j = chunkcoordintpair.getRegionX();
|
||||
- Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca");
|
||||
+ Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change
|
||||
if (existingOnly && !java.nio.file.Files.exists(path1)) return null; // CraftBukkit
|
||||
- RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
|
||||
+ RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header
|
||||
|
||||
this.regionCache.putAndMoveToFirst(i, regionfile1);
|
||||
// Paper start
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
if (regionfile == null) {
|
||||
return null;
|
||||
}
|
||||
+ // Paper start - Add regionfile parameter
|
||||
+ return this.read(pos, regionfile);
|
||||
+ }
|
||||
+ public CompoundTag read(ChunkPos pos, RegionFile regionfile) throws IOException {
|
||||
+ // We add the regionfile parameter to avoid the potential deadlock (on fileLock) if we went back to obtain a regionfile
|
||||
+ // if we decide to re-read
|
||||
+ // Paper end
|
||||
// CraftBukkit end
|
||||
try { // Paper
|
||||
DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos);
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
try {
|
||||
if (datainputstream != null) {
|
||||
nbttagcompound = NbtIo.read((DataInput) datainputstream);
|
||||
+ // Paper start - recover from corrupt regionfile header
|
||||
+ if (this.isChunkData) {
|
||||
+ ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound);
|
||||
+ if (!chunkPos.equals(pos)) {
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + chunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionfile.regionFile.toAbsolutePath());
|
||||
+ if (regionfile.recalculateHeader()) {
|
||||
+ regionfile.fileLock.lock(); // otherwise we will unlock twice and only lock once.
|
||||
+ return this.read(pos, regionfile);
|
||||
+ }
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + regionfile.regionFile.toAbsolutePath());
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - recover from corrupt regionfile header
|
||||
break label43;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
|
||||
@@ -0,0 +0,0 @@ import javax.annotation.Nullable;
|
||||
import net.minecraft.util.FastBufferedInputStream;
|
||||
|
||||
public class RegionFileVersion {
|
||||
- private static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>();
|
||||
+ public static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>(); // Paper - private -> public
|
||||
public static final RegionFileVersion VERSION_GZIP = register(new RegionFileVersion(1, (stream) -> {
|
||||
return new FastBufferedInputStream(new GZIPInputStream(stream));
|
||||
}, (stream) -> {
|
||||
@@ -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.getBukkit(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 org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.Axolotl;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
-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);
|
||||
@@ -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
|
||||
@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
|
||||
+ if (!hasSetFarWarned) {
|
||||
Util.logAndPauseIfInIde("Detected setBlock in a far chunk [" + i + ", " + j + "], pos: " + pos + ", status: " + this.generatingStatus + (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
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: stonar96 <minecraft.stonar96@gmail.com>
|
||||
Date: Sun, 12 Sep 2021 00:14:21 +0200
|
||||
Subject: [PATCH] Check requirement before suggesting root nodes
|
||||
|
||||
Child nodes are handled by CommandDispatcher#parse checking
|
||||
requirements.
|
||||
|
||||
Vanilla clients only send ServerboundCommandSuggestionPacket when
|
||||
encountering a command node with ASK_SERVER suggestions, however a
|
||||
modified client can send this packet whenever it wants.
|
||||
|
||||
diff --git a/src/main/java/com/mojang/brigadier/CommandDispatcher.java b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
+++ b/src/main/java/com/mojang/brigadier/CommandDispatcher.java
|
||||
@@ -0,0 +0,0 @@ public class CommandDispatcher<S> {
|
||||
int i = 0;
|
||||
for (final CommandNode<S> node : parent.getChildren()) {
|
||||
CompletableFuture<Suggestions> future = Suggestions.empty();
|
||||
+ // Paper start - Don't suggest if the requirement isn't met
|
||||
+ if (parent != this.root || node.canUse(context.getSource())) {
|
||||
try {
|
||||
- if (node.canUse(parse.getContext().getSource())) future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit
|
||||
+ future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); // CraftBukkit
|
||||
} catch (final CommandSyntaxException ignored) {
|
||||
}
|
||||
+ }
|
||||
+ // Paper end
|
||||
futures[i++] = future;
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Tue, 31 Aug 2021 17:05:27 +0200
|
||||
Subject: [PATCH] Configurable feature seeds
|
||||
|
||||
Co-authored-by: Thonk <30448663+ExcessiveAmountsOfZombies@users.noreply.github.com>
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
@@ -0,0 +0,0 @@ public class TimingsExport extends Thread {
|
||||
JSONObject object = new JSONObject();
|
||||
for (String key : config.getKeys(false)) {
|
||||
String fullKey = (parentKey != null ? parentKey + "." + key : key);
|
||||
- if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) {
|
||||
+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld") || key.equals("feature-seeds")) {
|
||||
continue;
|
||||
}
|
||||
final Object val = config.get(key);
|
||||
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 {
|
||||
return (String) optional.orElseGet(placedfeature::toString);
|
||||
};
|
||||
|
||||
- seededrandom.setFeatureSeed(i, l1, l);
|
||||
+ // Paper start - change populationSeed used in random
|
||||
+ long featurePopulationSeed = i;
|
||||
+ final long configFeatureSeed = generatoraccessseed.getMinecraftWorld().paperConfig().featureSeeds.features.getLong(placedfeature.feature());
|
||||
+ if (configFeatureSeed != -1) {
|
||||
+ featurePopulationSeed = seededrandom.setDecorationSeed(configFeatureSeed, blockposition.getX(), blockposition.getZ()); // See seededrandom.setDecorationSeed from above
|
||||
+ }
|
||||
+ seededrandom.setFeatureSeed(featurePopulationSeed, l1, l);
|
||||
+ // Paper end
|
||||
|
||||
try {
|
||||
generatoraccessseed.setCurrentlyGenerating(supplier1);
|
||||
@@ -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 >= 0 ? world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel : dimensionType.monsterSpawnBlockLightLimit(); // Paper
|
||||
if (i < 15 && world.getBrightness(LightLayer.BLOCK, pos) > i) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -1,53 +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/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 VibrationList
|
||||
this.listener = listener;
|
||||
});
|
||||
}
|
||||
+ if (nbt.contains(PAPER_LISTENER_RANGE_NBT_KEY)) this.listener.listenerRange = nbt.getInt(PAPER_LISTENER_RANGE_NBT_KEY); // Paper
|
||||
|
||||
}
|
||||
|
||||
+ private static final String PAPER_LISTENER_RANGE_NBT_KEY = "Paper.ListenerRange"; // Paper
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
@@ -0,0 +0,0 @@ public class SculkSensorBlockEntity extends BlockEntity implements VibrationList
|
||||
VibrationListener.codec(this).encodeStart(NbtOps.INSTANCE, this.listener).resultOrPartial(LOGGER::error).ifPresent((listenerNbt) -> {
|
||||
nbt.put("listener", listenerNbt);
|
||||
});
|
||||
+ if (this.listener.listenerRange != ((SculkSensorBlock) net.minecraft.world.level.block.Blocks.SCULK_SENSOR).getListenerRange()) nbt.putInt(PAPER_LISTENER_RANGE_NBT_KEY, this.listener.listenerRange); // Paper - only save if it's different from the default
|
||||
}
|
||||
|
||||
public VibrationListener getListener() {
|
||||
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 extends CraftBlockEntityState<SculkSensorBlockEnti
|
||||
Preconditions.checkArgument(0 <= lastVibrationFrequency && lastVibrationFrequency <= 15, "Vibration frequency must be between 0-15");
|
||||
getSnapshot().lastVibrationFrequency = lastVibrationFrequency;
|
||||
}
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public int getListenerRange() {
|
||||
+ return this.getSnapshot().getListener().listenerRange;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setListenerRange(int range) {
|
||||
+ Preconditions.checkArgument(range > 0, "Vibration listener range must be greater than 0");
|
||||
+ this.getSnapshot().getListener().listenerRange = range;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 4 Apr 2020 17:00:20 -0700
|
||||
Subject: [PATCH] Consolidate flush calls for entity tracker packets
|
||||
|
||||
Most server packets seem to be sent from here, so try to avoid
|
||||
expensive flush calls from them.
|
||||
|
||||
This change was motivated due to local testing:
|
||||
|
||||
- My server spawn has 130 cows in it (for testing a prev. patch)
|
||||
- Try to let 200 players join spawn
|
||||
|
||||
Without this change, I could only get 20 players on before they
|
||||
all started timing out due to the load put on the Netty I/O threads.
|
||||
|
||||
With this change I could get all 200 on at 0ms ping.
|
||||
|
||||
(one of the primary issues is that my CPU is kinda trash, and having
|
||||
4 extra threads at 100% is just too much for it).
|
||||
|
||||
So in general this patch should reduce Netty I/O thread load.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
|
||||
gameprofilerfiller.pop();
|
||||
// Paper end - use set of chunks requiring updates, rather than iterating every single one loaded
|
||||
+ // Paper start - controlled flush for entity tracker packets
|
||||
+ List<net.minecraft.network.Connection> disabledFlushes = new java.util.ArrayList<>(this.level.players.size());
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ net.minecraft.server.network.ServerGamePacketListenerImpl connection = player.connection;
|
||||
+ if (connection != null) {
|
||||
+ connection.connection.disableAutomaticFlush();
|
||||
+ disabledFlushes.add(connection.connection);
|
||||
+ }
|
||||
+ }
|
||||
+ try { // Paper end - controlled flush for entity tracker packets
|
||||
this.chunkMap.tick();
|
||||
+ // Paper start - controlled flush for entity tracker packets
|
||||
+ } finally {
|
||||
+ for (net.minecraft.network.Connection networkManager : disabledFlushes) {
|
||||
+ networkManager.enableAutomaticFlush();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - controlled flush for entity tracker packets
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,239 +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
|
||||
|
||||
|
||||
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 net.minecraft.world.item.ItemStack;
|
||||
+import net.minecraft.world.item.crafting.Ingredient;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
+import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
+
|
||||
+public record PaperPotionMix(ItemStack result, Ingredient input, Ingredient ingredient) {
|
||||
+
|
||||
+ public PaperPotionMix(PotionMix potionMix) {
|
||||
+ this(CraftItemStack.asNMSCopy(potionMix.getResult()), CraftRecipe.toIngredient(potionMix.getInput(), true), CraftRecipe.toIngredient(potionMix.getIngredient(), 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.registryAccess());
|
||||
+ net.minecraft.world.item.alchemy.PotionBrewing.reload(); // Paper
|
||||
new io.papermc.paper.event.server.ServerResourcesReloadedEvent(cause).callEvent(); // Paper
|
||||
// Paper start
|
||||
if (Thread.currentThread() != this.serverThread) {
|
||||
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 {
|
||||
}
|
||||
|
||||
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);
|
||||
+ return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || PotionBrewing.isCustomInput(stack); // Paper
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
public static final int BREWING_TIME_SECONDS = 20;
|
||||
private static final List<PotionBrewing.Mix<Potion>> POTION_MIXES = Lists.newArrayList();
|
||||
private static final List<PotionBrewing.Mix<Item>> CONTAINER_MIXES = Lists.newArrayList();
|
||||
+ private static final it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<org.bukkit.NamespacedKey, io.papermc.paper.potion.PaperPotionMix> CUSTOM_MIXES = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // Paper
|
||||
private static final List<Ingredient> ALLOWED_CONTAINERS = Lists.newArrayList();
|
||||
private static final Predicate<ItemStack> ALLOWED_CONTAINER = (stack) -> {
|
||||
for(Ingredient ingredient : ALLOWED_CONTAINERS) {
|
||||
@@ -0,0 +0,0 @@ public class PotionBrewing {
|
||||
};
|
||||
|
||||
public static boolean isIngredient(ItemStack stack) {
|
||||
- return isContainerIngredient(stack) || isPotionIngredient(stack);
|
||||
+ return isContainerIngredient(stack) || isPotionIngredient(stack) || isCustomIngredient(stack); // Paper
|
||||
}
|
||||
|
||||
protected static boolean isContainerIngredient(ItemStack stack) {
|
||||
@@ -0,0 +0,0 @@ public class PotionBrewing {
|
||||
}
|
||||
|
||||
public static boolean hasMix(ItemStack input, ItemStack ingredient) {
|
||||
+ // Paper start
|
||||
+ if (hasCustomMix(input, ingredient)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (!ALLOWED_CONTAINER.test(input)) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public class PotionBrewing {
|
||||
|
||||
public static ItemStack mix(ItemStack ingredient, ItemStack input) {
|
||||
if (!input.isEmpty()) {
|
||||
+ // Paper start
|
||||
+ for (var mix : CUSTOM_MIXES.values()) {
|
||||
+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) {
|
||||
+ return mix.result().copy();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
Potion potion = PotionUtils.getPotion(input);
|
||||
Item item = input.getItem();
|
||||
int i = 0;
|
||||
@@ -0,0 +0,0 @@ public class PotionBrewing {
|
||||
return input;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static boolean isCustomIngredient(ItemStack stack) {
|
||||
+ for (var mix : CUSTOM_MIXES.values()) {
|
||||
+ if (mix.ingredient().test(stack)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ public static boolean isCustomInput(ItemStack stack) {
|
||||
+ for (var mix : CUSTOM_MIXES.values()) {
|
||||
+ if (mix.input().test(stack)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean hasCustomMix(ItemStack input, ItemStack ingredient) {
|
||||
+ for (var mix : CUSTOM_MIXES.values()) {
|
||||
+ if (mix.input().test(input) && mix.ingredient().test(ingredient)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ public static void addPotionMix(io.papermc.paper.potion.PotionMix mix) {
|
||||
+ if (CUSTOM_MIXES.containsKey(mix.getKey())) {
|
||||
+ throw new IllegalArgumentException("Duplicate recipe ignored with ID " + mix.getKey());
|
||||
+ }
|
||||
+ CUSTOM_MIXES.putAndMoveToFirst(mix.getKey(), new io.papermc.paper.potion.PaperPotionMix(mix));
|
||||
+ }
|
||||
+
|
||||
+ public static boolean removePotionMix(org.bukkit.NamespacedKey key) {
|
||||
+ return CUSTOM_MIXES.remove(key) != null;
|
||||
+ }
|
||||
+
|
||||
+ public static void reload() {
|
||||
+ POTION_MIXES.clear();
|
||||
+ CONTAINER_MIXES.clear();
|
||||
+ ALLOWED_CONTAINERS.clear();
|
||||
+ CUSTOM_MIXES.clear();
|
||||
+ bootStrap();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static void bootStrap() {
|
||||
addContainer(Items.POTION);
|
||||
addContainer(Items.SPLASH_POTION);
|
||||
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) {
|
||||
- return slot == 3 ? PotionBrewing.isIngredient(stack) : (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 == 3 ? PotionBrewing.isIngredient(stack) : (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) || PotionBrewing.isCustomInput(stack)) && this.getItem(slot).isEmpty()); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
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 CraftPotionBrewer potionBrewer = new CraftPotionBrewer(); // Paper
|
||||
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
|
||||
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
|
||||
Enchantments.SHARPNESS.getClass();
|
||||
org.bukkit.enchantments.Enchantment.stopAcceptingRegistrations();
|
||||
|
||||
- Potion.setPotionBrewer(new CraftPotionBrewer());
|
||||
+ Potion.setPotionBrewer(potionBrewer); // Paper
|
||||
MobEffects.BLINDNESS.getClass();
|
||||
PotionEffectType.stopAcceptingRegistrations();
|
||||
// Ugly hack :(
|
||||
@@ -0,0 +0,0 @@ public final class CraftServer implements Server {
|
||||
return datapackManager;
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public CraftPotionBrewer 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) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java
|
||||
@@ -0,0 +0,0 @@ public class CraftPotionBrewer implements PotionBrewer {
|
||||
public PotionEffect createEffect(PotionEffectType potion, int duration, int amplifier) {
|
||||
return new PotionEffect(potion, potion.isInstant() ? 1 : (int) (duration * potion.getDurationModifier()), amplifier);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void addPotionMix(io.papermc.paper.potion.PotionMix potionMix) {
|
||||
+ net.minecraft.world.item.alchemy.PotionBrewing.addPotionMix(potionMix);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void removePotionMix(org.bukkit.NamespacedKey key) {
|
||||
+ net.minecraft.world.item.alchemy.PotionBrewing.removePotionMix(key);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void resetPotionMixes() {
|
||||
+ net.minecraft.world.item.alchemy.PotionBrewing.reload();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -1,343 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 11 Mar 2021 20:05:44 -0800
|
||||
Subject: [PATCH] Custom table implementation for blockstate state lookups
|
||||
|
||||
Testing some redstone intensive machines showed to bring about a 10%
|
||||
improvement.
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java b/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/util/table/ZeroCollidingReferenceStateTable.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.util.table;
|
||||
+
|
||||
+import com.google.common.collect.Table;
|
||||
+import net.minecraft.world.level.block.state.StateHolder;
|
||||
+import net.minecraft.world.level.block.state.properties.Property;
|
||||
+import java.util.Collection;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+
|
||||
+public final class ZeroCollidingReferenceStateTable {
|
||||
+
|
||||
+ // upper 32 bits: starting index
|
||||
+ // lower 32 bits: bitset for contained ids
|
||||
+ protected final long[] this_index_table;
|
||||
+ protected final Comparable<?>[] this_table;
|
||||
+ protected final StateHolder<?, ?> this_state;
|
||||
+
|
||||
+ protected long[] index_table;
|
||||
+ protected StateHolder<?, ?>[][] value_table;
|
||||
+
|
||||
+ public ZeroCollidingReferenceStateTable(final StateHolder<?, ?> state, final Map<Property<?>, Comparable<?>> this_map) {
|
||||
+ this.this_state = state;
|
||||
+ this.this_index_table = this.create_table(this_map.keySet());
|
||||
+
|
||||
+ int max_id = -1;
|
||||
+ for (final Property<?> property : this_map.keySet()) {
|
||||
+ final int id = lookup_vindex(property, this.this_index_table);
|
||||
+ if (id > max_id) {
|
||||
+ max_id = id;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.this_table = new Comparable[max_id + 1];
|
||||
+ for (final Map.Entry<Property<?>, Comparable<?>> entry : this_map.entrySet()) {
|
||||
+ this.this_table[lookup_vindex(entry.getKey(), this.this_index_table)] = entry.getValue();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void loadInTable(final Table<Property<?>, Comparable<?>, StateHolder<?, ?>> table,
|
||||
+ final Map<Property<?>, Comparable<?>> this_map) {
|
||||
+ final Set<Property<?>> combined = new HashSet<>(table.rowKeySet());
|
||||
+ combined.addAll(this_map.keySet());
|
||||
+
|
||||
+ this.index_table = this.create_table(combined);
|
||||
+
|
||||
+ int max_id = -1;
|
||||
+ for (final Property<?> property : combined) {
|
||||
+ final int id = lookup_vindex(property, this.index_table);
|
||||
+ if (id > max_id) {
|
||||
+ max_id = id;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.value_table = new StateHolder[max_id + 1][];
|
||||
+
|
||||
+ final Map<Property<?>, Map<Comparable<?>, StateHolder<?, ?>>> map = table.rowMap();
|
||||
+ for (final Property<?> property : map.keySet()) {
|
||||
+ final Map<Comparable<?>, StateHolder<?, ?>> propertyMap = map.get(property);
|
||||
+
|
||||
+ final int id = lookup_vindex(property, this.index_table);
|
||||
+ final StateHolder<?, ?>[] states = this.value_table[id] = new StateHolder[property.getPossibleValues().size()];
|
||||
+
|
||||
+ for (final Map.Entry<Comparable<?>, StateHolder<?, ?>> entry : propertyMap.entrySet()) {
|
||||
+ if (entry.getValue() == null) {
|
||||
+ // TODO what
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ states[((Property)property).getIdFor(entry.getKey())] = entry.getValue();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ for (final Map.Entry<Property<?>, Comparable<?>> entry : this_map.entrySet()) {
|
||||
+ final Property<?> property = entry.getKey();
|
||||
+ final int index = lookup_vindex(property, this.index_table);
|
||||
+
|
||||
+ if (this.value_table[index] == null) {
|
||||
+ this.value_table[index] = new StateHolder[property.getPossibleValues().size()];
|
||||
+ }
|
||||
+
|
||||
+ this.value_table[index][((Property)property).getIdFor(entry.getValue())] = this.this_state;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ protected long[] create_table(final Collection<Property<?>> collection) {
|
||||
+ int max_id = -1;
|
||||
+ for (final Property<?> property : collection) {
|
||||
+ final int id = property.getId();
|
||||
+ if (id > max_id) {
|
||||
+ max_id = id;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final long[] ret = new long[((max_id + 1) + 31) >>> 5]; // ceil((max_id + 1) / 32)
|
||||
+
|
||||
+ for (final Property<?> property : collection) {
|
||||
+ final int id = property.getId();
|
||||
+
|
||||
+ ret[id >>> 5] |= (1L << (id & 31));
|
||||
+ }
|
||||
+
|
||||
+ int total = 0;
|
||||
+ for (int i = 1, len = ret.length; i < len; ++i) {
|
||||
+ ret[i] |= (long)(total += Long.bitCount(ret[i - 1] & 0xFFFFFFFFL)) << 32;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ public Comparable<?> get(final Property<?> state) {
|
||||
+ final Comparable<?>[] table = this.this_table;
|
||||
+ final int index = lookup_vindex(state, this.this_index_table);
|
||||
+
|
||||
+ if (index < 0 || index >= table.length) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ return table[index];
|
||||
+ }
|
||||
+
|
||||
+ public StateHolder<?, ?> get(final Property<?> property, final Comparable<?> with) {
|
||||
+ final int withId = ((Property)property).getIdFor(with);
|
||||
+ if (withId < 0) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final int index = lookup_vindex(property, this.index_table);
|
||||
+ final StateHolder<?, ?>[][] table = this.value_table;
|
||||
+ if (index < 0 || index >= table.length) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final StateHolder<?, ?>[] values = table[index];
|
||||
+
|
||||
+ if (withId >= values.length) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return values[withId];
|
||||
+ }
|
||||
+
|
||||
+ protected static int lookup_vindex(final Property<?> property, final long[] index_table) {
|
||||
+ final int id = property.getId();
|
||||
+ final long bitset_mask = (1L << (id & 31));
|
||||
+ final long lower_mask = bitset_mask - 1;
|
||||
+ final int index = id >>> 5;
|
||||
+ if (index >= index_table.length) {
|
||||
+ return -1;
|
||||
+ }
|
||||
+ final long index_value = index_table[index];
|
||||
+ final long contains_check = ((index_value & bitset_mask) - 1) >> (Long.SIZE - 1); // -1L if doesn't contain
|
||||
+
|
||||
+ // index = total bits set in lower table values (upper 32 bits of index_value) plus total bits set in lower indices below id
|
||||
+ // contains_check is 0 if the bitset had id set, else it's -1: so index is unaffected if contains_check == 0,
|
||||
+ // otherwise it comes out as -1.
|
||||
+ return (int)(((index_value >>> 32) + Long.bitCount(index_value & lower_mask)) | contains_check);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
|
||||
@@ -0,0 +0,0 @@ public abstract class StateHolder<O, S> {
|
||||
private final ImmutableMap<Property<?>, Comparable<?>> values;
|
||||
private Table<Property<?>, Comparable<?>, S> neighbours;
|
||||
protected final MapCodec<S> propertiesCodec;
|
||||
+ protected final io.papermc.paper.util.table.ZeroCollidingReferenceStateTable optimisedTable; // Paper - optimise state lookup
|
||||
|
||||
protected StateHolder(O owner, ImmutableMap<Property<?>, Comparable<?>> entries, MapCodec<S> codec) {
|
||||
this.owner = owner;
|
||||
this.values = entries;
|
||||
this.propertiesCodec = codec;
|
||||
+ this.optimisedTable = new io.papermc.paper.util.table.ZeroCollidingReferenceStateTable(this, entries); // Paper - optimise state lookup
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>> S cycle(Property<T> property) {
|
||||
@@ -0,0 +0,0 @@ public abstract class StateHolder<O, S> {
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>> boolean hasProperty(Property<T> property) {
|
||||
- return this.values.containsKey(property);
|
||||
+ return this.optimisedTable.get(property) != null; // Paper - optimise state lookup
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>> T getValue(Property<T> property) {
|
||||
- Comparable<?> comparable = this.values.get(property);
|
||||
+ Comparable<?> comparable = this.optimisedTable.get(property); // Paper - optimise state lookup
|
||||
if (comparable == null) {
|
||||
throw new IllegalArgumentException("Cannot get property " + property + " as it does not exist in " + this.owner);
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public abstract class StateHolder<O, S> {
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>> Optional<T> getOptionalValue(Property<T> property) {
|
||||
- Comparable<?> comparable = this.values.get(property);
|
||||
+ Comparable<?> comparable = this.optimisedTable.get(property); // Paper - optimise state lookup
|
||||
return comparable == null ? Optional.empty() : Optional.of(property.getValueClass().cast(comparable));
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>, V extends T> S setValue(Property<T> property, V value) {
|
||||
- Comparable<?> comparable = this.values.get(property);
|
||||
- if (comparable == null) {
|
||||
- throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + this.owner);
|
||||
- } else if (comparable == value) {
|
||||
- return (S)this;
|
||||
- } else {
|
||||
- S object = this.neighbours.get(property, value);
|
||||
- if (object == null) {
|
||||
- throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value");
|
||||
- } else {
|
||||
- return object;
|
||||
- }
|
||||
+ // Paper start - optimise state lookup
|
||||
+ final S ret = (S)this.optimisedTable.get(property, value);
|
||||
+ if (ret == null) {
|
||||
+ throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on " + this.owner + ", it is not an allowed value");
|
||||
}
|
||||
+ return ret;
|
||||
+ // Paper end - optimise state lookup
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>, V extends T> S trySetValue(Property<T> property, V value) {
|
||||
@@ -0,0 +0,0 @@ public abstract class StateHolder<O, S> {
|
||||
}
|
||||
}
|
||||
|
||||
- this.neighbours = (Table<Property<?>, Comparable<?>, S>)(table.isEmpty() ? table : ArrayTable.create(table));
|
||||
+ this.neighbours = (Table<Property<?>, Comparable<?>, S>)(table.isEmpty() ? table : ArrayTable.create(table)); this.optimisedTable.loadInTable((Table)this.neighbours, this.values); // Paper - optimise state lookup
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/BooleanProperty.java
|
||||
@@ -0,0 +0,0 @@ import java.util.Optional;
|
||||
public class BooleanProperty extends Property<Boolean> {
|
||||
private final ImmutableSet<Boolean> values = ImmutableSet.of(true, false);
|
||||
|
||||
+ // Paper start - optimise iblockdata state lookup
|
||||
+ @Override
|
||||
+ public final int getIdFor(final Boolean value) {
|
||||
+ return value.booleanValue() ? 1 : 0;
|
||||
+ }
|
||||
+ // Paper end - optimise iblockdata state lookup
|
||||
+
|
||||
protected BooleanProperty(String name) {
|
||||
super(name, Boolean.class);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/EnumProperty.java
|
||||
@@ -0,0 +0,0 @@ public class EnumProperty<T extends Enum<T> & StringRepresentable> extends Prope
|
||||
private final ImmutableSet<T> values;
|
||||
private final Map<String, T> names = Maps.newHashMap();
|
||||
|
||||
+ // Paper start - optimise iblockdata state lookup
|
||||
+ private int[] idLookupTable;
|
||||
+
|
||||
+ @Override
|
||||
+ public final int getIdFor(final T value) {
|
||||
+ return this.idLookupTable[value.ordinal()];
|
||||
+ }
|
||||
+ // Paper end - optimise iblockdata state lookup
|
||||
+
|
||||
protected EnumProperty(String name, Class<T> type, Collection<T> values) {
|
||||
super(name, type);
|
||||
this.values = ImmutableSet.copyOf(values);
|
||||
@@ -0,0 +0,0 @@ public class EnumProperty<T extends Enum<T> & StringRepresentable> extends Prope
|
||||
this.names.put(string, enum_);
|
||||
}
|
||||
|
||||
+ // Paper start - optimise iblockdata state lookup
|
||||
+ int id = 0;
|
||||
+ this.idLookupTable = new int[type.getEnumConstants().length];
|
||||
+ java.util.Arrays.fill(this.idLookupTable, -1);
|
||||
+ for (final T value : this.getPossibleValues()) {
|
||||
+ this.idLookupTable[value.ordinal()] = id++;
|
||||
+ }
|
||||
+ // Paper end - optimise iblockdata state lookup
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/IntegerProperty.java
|
||||
@@ -0,0 +0,0 @@ public class IntegerProperty extends Property<Integer> {
|
||||
public final int min;
|
||||
public final int max;
|
||||
|
||||
+ // Paper start - optimise iblockdata state lookup
|
||||
+ @Override
|
||||
+ public final int getIdFor(final Integer value) {
|
||||
+ final int val = value.intValue();
|
||||
+ final int ret = val - this.min;
|
||||
+
|
||||
+ return ret | ((this.max - ret) >> 31);
|
||||
+ }
|
||||
+ // Paper end - optimise iblockdata state lookup
|
||||
+
|
||||
protected IntegerProperty(String name, int min, int max) {
|
||||
super(name, Integer.class);
|
||||
if (min < 0) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/state/properties/Property.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Property<T extends Comparable<T>> {
|
||||
}, this::getName);
|
||||
private final Codec<Property.Value<T>> valueCodec = this.codec.xmap(this::value, Property.Value::value);
|
||||
|
||||
+ // Paper start - optimise iblockdata state lookup
|
||||
+ private static final java.util.concurrent.atomic.AtomicInteger ID_GENERATOR = new java.util.concurrent.atomic.AtomicInteger();
|
||||
+ private final int id = ID_GENERATOR.getAndIncrement();
|
||||
+
|
||||
+ public final int getId() {
|
||||
+ return this.id;
|
||||
+ }
|
||||
+
|
||||
+ public abstract int getIdFor(final T value);
|
||||
+ // Paper end - optimise state lookup
|
||||
+
|
||||
protected Property(String name, Class<T> type) {
|
||||
this.clazz = type;
|
||||
this.name = name;
|
||||
@@ -1,295 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 26 Mar 2020 21:59:32 -0700
|
||||
Subject: [PATCH] Detail more information in watchdog dumps
|
||||
|
||||
- Dump position, world, velocity, and uuid for currently ticking entities
|
||||
- Dump player name, player uuid, position, and world for packet handling
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener)
|
||||
|| loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT
|
||||
|| Connection.joinAttemptsThisTick++ < MAX_PER_TICK) {
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener);
|
||||
+ try { // Paper end - detailed watchdog information
|
||||
tickablepacketlistener.tick();
|
||||
+ } finally { // Paper start - detailed watchdog information
|
||||
+ net.minecraft.network.protocol.PacketUtils.packetProcessing.pop();
|
||||
+ } // Paper end - detailed watchdog information
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java
|
||||
@@ -0,0 +0,0 @@ public class PacketUtils {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ public static final java.util.concurrent.ConcurrentLinkedDeque<PacketListener> packetProcessing = new java.util.concurrent.ConcurrentLinkedDeque<>();
|
||||
+ static final java.util.concurrent.atomic.AtomicLong totalMainThreadPacketsProcessed = new java.util.concurrent.atomic.AtomicLong();
|
||||
+
|
||||
+ public static long getTotalProcessedPackets() {
|
||||
+ return totalMainThreadPacketsProcessed.get();
|
||||
+ }
|
||||
+
|
||||
+ public static java.util.List<PacketListener> getCurrentPacketProcessors() {
|
||||
+ java.util.List<PacketListener> ret = new java.util.ArrayList<>(4);
|
||||
+ for (PacketListener listener : packetProcessing) {
|
||||
+ ret.add(listener);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
+
|
||||
public PacketUtils() {}
|
||||
|
||||
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T listener, ServerLevel world) throws RunningOnDifferentThreadException {
|
||||
@@ -0,0 +0,0 @@ public class PacketUtils {
|
||||
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T listener, BlockableEventLoop<?> engine) throws RunningOnDifferentThreadException {
|
||||
if (!engine.isSameThread()) {
|
||||
engine.executeIfPossible(() -> {
|
||||
+ packetProcessing.push(listener); // Paper - detailed watchdog information
|
||||
+ try { // Paper - detailed watchdog information
|
||||
if (MinecraftServer.getServer().hasStopped() || (listener instanceof ServerGamePacketListenerImpl && ((ServerGamePacketListenerImpl) listener).processedDisconnect)) return; // CraftBukkit, MC-142590
|
||||
if (listener.getConnection().isConnected()) {
|
||||
co.aikar.timings.Timing timing = co.aikar.timings.MinecraftTimings.getPacketTiming(packet); // Paper - timings
|
||||
@@ -0,0 +0,0 @@ public class PacketUtils {
|
||||
} else {
|
||||
PacketUtils.LOGGER.debug("Ignoring packet due to disconnection: {}", packet);
|
||||
}
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ } finally {
|
||||
+ totalMainThreadPacketsProcessed.getAndIncrement();
|
||||
+ packetProcessing.pop();
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
|
||||
});
|
||||
throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD;
|
||||
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 {
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start - log detailed entity tick information
|
||||
+ // TODO replace with varhandle
|
||||
+ static final java.util.concurrent.atomic.AtomicReference<Entity> currentlyTickingEntity = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
+
|
||||
+ public static List<Entity> getCurrentlyTickingEntities() {
|
||||
+ Entity ticking = currentlyTickingEntity.get();
|
||||
+ List<Entity> ret = java.util.Arrays.asList(ticking == null ? new Entity[0] : new Entity[] { ticking });
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Paper end - log detailed entity tick information
|
||||
+
|
||||
public void tickNonPassenger(Entity entity) {
|
||||
+ // Paper start - log detailed entity tick information
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread("Cannot tick an entity off-main");
|
||||
+ try {
|
||||
+ if (currentlyTickingEntity.get() == null) {
|
||||
+ currentlyTickingEntity.lazySet(entity);
|
||||
+ }
|
||||
+ // Paper end - log detailed entity tick information
|
||||
++TimingHistory.entityTicks; // Paper - timings
|
||||
// Spigot start
|
||||
co.aikar.timings.Timing timer; // Paper
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
this.tickPassenger(entity, entity1);
|
||||
}
|
||||
// } finally { timer.stopTiming(); } // Paper - timings - move up
|
||||
-
|
||||
+ // Paper start - log detailed entity tick information
|
||||
+ } finally {
|
||||
+ if (currentlyTickingEntity.get() == entity) {
|
||||
+ currentlyTickingEntity.lazySet(null);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - log detailed entity tick information
|
||||
}
|
||||
|
||||
private void tickPassenger(Entity vehicle, Entity passenger) {
|
||||
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 Nameable, EntityAccess, CommandSource {
|
||||
return this.onGround;
|
||||
}
|
||||
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ public final Object posLock = new Object(); // Paper - log detailed entity tick information
|
||||
+
|
||||
+ private Vec3 moveVector;
|
||||
+ private double moveStartX;
|
||||
+ private double moveStartY;
|
||||
+ private double moveStartZ;
|
||||
+
|
||||
+ public final Vec3 getMoveVector() {
|
||||
+ return this.moveVector;
|
||||
+ }
|
||||
+
|
||||
+ public final double getMoveStartX() {
|
||||
+ return this.moveStartX;
|
||||
+ }
|
||||
+
|
||||
+ public final double getMoveStartY() {
|
||||
+ return this.moveStartY;
|
||||
+ }
|
||||
+
|
||||
+ public final double getMoveStartZ() {
|
||||
+ return this.moveStartZ;
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
+
|
||||
public void move(MoverType movementType, Vec3 movement) {
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ io.papermc.paper.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||
+ synchronized (this.posLock) {
|
||||
+ this.moveStartX = this.getX();
|
||||
+ this.moveStartY = this.getY();
|
||||
+ this.moveStartZ = this.getZ();
|
||||
+ this.moveVector = movement;
|
||||
+ }
|
||||
+ try {
|
||||
+ // Paper end - detailed watchdog information
|
||||
if (this.noPhysics) {
|
||||
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
this.level.getProfiler().pop();
|
||||
}
|
||||
}
|
||||
+ // Paper start - detailed watchdog information
|
||||
+ } finally {
|
||||
+ synchronized (this.posLock) { // Paper
|
||||
+ this.moveVector = null;
|
||||
+ } // Paper
|
||||
+ }
|
||||
+ // Paper end - detailed watchdog information
|
||||
}
|
||||
|
||||
protected boolean isHorizontalCollisionMinor(Vec3 adjustedMovement) {
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public void setDeltaMovement(Vec3 velocity) {
|
||||
+ synchronized (this.posLock) { // Paper
|
||||
this.deltaMovement = velocity;
|
||||
+ } // Paper
|
||||
}
|
||||
|
||||
public void addDeltaMovement(Vec3 velocity) {
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
// Paper end - fix MC-4
|
||||
if (this.position.x != x || this.position.y != y || this.position.z != z) {
|
||||
+ synchronized (this.posLock) { // Paper
|
||||
this.position = new Vec3(x, y, z);
|
||||
+ } // Paper
|
||||
int i = Mth.floor(x);
|
||||
int j = Mth.floor(y);
|
||||
int k = Mth.floor(z);
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
private volatile long lastTick;
|
||||
private volatile boolean stopping;
|
||||
|
||||
+ // Paper start - log detailed tick information
|
||||
+ private void dumpEntity(net.minecraft.world.entity.Entity entity) {
|
||||
+ Logger log = Bukkit.getServer().getLogger();
|
||||
+ double posX, posY, posZ;
|
||||
+ net.minecraft.world.phys.Vec3 mot;
|
||||
+ double moveStartX, moveStartY, moveStartZ;
|
||||
+ net.minecraft.world.phys.Vec3 moveVec;
|
||||
+ synchronized (entity.posLock) {
|
||||
+ posX = entity.getX();
|
||||
+ posY = entity.getY();
|
||||
+ posZ = entity.getZ();
|
||||
+ mot = entity.getDeltaMovement();
|
||||
+ moveStartX = entity.getMoveStartX();
|
||||
+ moveStartY = entity.getMoveStartY();
|
||||
+ moveStartZ = entity.getMoveStartZ();
|
||||
+ moveVec = entity.getMoveVector();
|
||||
+ }
|
||||
+
|
||||
+ String entityType = net.minecraft.world.entity.EntityType.getKey(entity.getType()).toString();
|
||||
+ java.util.UUID entityUUID = entity.getUUID();
|
||||
+ net.minecraft.world.level.Level world = entity.level;
|
||||
+
|
||||
+ log.log(Level.SEVERE, "Ticking entity: " + entityType + ", entity class: " + entity.getClass().getName());
|
||||
+ log.log(Level.SEVERE, "Entity status: removed: " + entity.isRemoved() + ", valid: " + entity.valid + ", alive: " + entity.isAlive() + ", is passenger: " + entity.isPassenger());
|
||||
+ log.log(Level.SEVERE, "Entity UUID: " + entityUUID);
|
||||
+ log.log(Level.SEVERE, "Position: world: '" + (world == null ? "unknown world?" : world.getWorld().getName()) + "' at location (" + posX + ", " + posY + ", " + posZ + ")");
|
||||
+ log.log(Level.SEVERE, "Velocity: " + (mot == null ? "unknown velocity" : mot.toString()) + " (in blocks per tick)");
|
||||
+ log.log(Level.SEVERE, "Entity AABB: " + entity.getBoundingBox());
|
||||
+ if (moveVec != null) {
|
||||
+ log.log(Level.SEVERE, "Move call information: ");
|
||||
+ log.log(Level.SEVERE, "Start position: (" + moveStartX + ", " + moveStartY + ", " + moveStartZ + ")");
|
||||
+ log.log(Level.SEVERE, "Move vector: " + moveVec.toString());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void dumpTickingInfo() {
|
||||
+ Logger log = Bukkit.getServer().getLogger();
|
||||
+
|
||||
+ // ticking entities
|
||||
+ for (net.minecraft.world.entity.Entity entity : net.minecraft.server.level.ServerLevel.getCurrentlyTickingEntities()) {
|
||||
+ this.dumpEntity(entity);
|
||||
+ net.minecraft.world.entity.Entity vehicle = entity.getVehicle();
|
||||
+ if (vehicle != null) {
|
||||
+ log.log(Level.SEVERE, "Detailing vehicle for above entity:");
|
||||
+ this.dumpEntity(vehicle);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // packet processors
|
||||
+ for (net.minecraft.network.PacketListener packetListener : net.minecraft.network.protocol.PacketUtils.getCurrentPacketProcessors()) {
|
||||
+ if (packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl) {
|
||||
+ net.minecraft.server.level.ServerPlayer player = ((net.minecraft.server.network.ServerGamePacketListenerImpl)packetListener).player;
|
||||
+ long totalPackets = net.minecraft.network.protocol.PacketUtils.getTotalProcessedPackets();
|
||||
+ if (player == null) {
|
||||
+ log.log(Level.SEVERE, "Handling packet for player connection or ticking player connection (null player): " + packetListener);
|
||||
+ log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets);
|
||||
+ } else {
|
||||
+ this.dumpEntity(player);
|
||||
+ net.minecraft.world.entity.Entity vehicle = player.getVehicle();
|
||||
+ if (vehicle != null) {
|
||||
+ log.log(Level.SEVERE, "Detailing vehicle for above entity:");
|
||||
+ this.dumpEntity(vehicle);
|
||||
+ }
|
||||
+ log.log(Level.SEVERE, "Total packets processed on the main thread for all players: " + totalPackets);
|
||||
+ }
|
||||
+ } else {
|
||||
+ log.log(Level.SEVERE, "Handling packet for connection: " + packetListener);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - log detailed tick information
|
||||
+
|
||||
private WatchdogThread(long timeoutTime, boolean restart)
|
||||
{
|
||||
super( "Paper Watchdog Thread" );
|
||||
@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system
|
||||
+ this.dumpTickingInfo(); // Paper - log detailed tick information
|
||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
||||
log.log( Level.SEVERE, "------------------------------" );
|
||||
//
|
||||
@@ -1,34 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sat, 18 Jul 2020 16:03:57 -0700
|
||||
Subject: [PATCH] Distance manager tick timings
|
||||
|
||||
Recently this has been taking up more time, so add a timings to
|
||||
really figure out how much.
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
@@ -0,0 +0,0 @@ public final class MinecraftTimings {
|
||||
|
||||
public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update");
|
||||
public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate");
|
||||
+ public static final Timing distanceManagerTick = Timings.ofSafe("Distance Manager Tick"); // Paper - add timings for distance manager
|
||||
|
||||
public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks");
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
+++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java
|
||||
@@ -0,0 +0,0 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
|
||||
public boolean processTicketUpdates() {
|
||||
+ co.aikar.timings.MinecraftTimings.distanceManagerTick.startTiming(); try { // Paper - add timings for distance manager
|
||||
return this.processTicketUpdates(true, true, null);
|
||||
+ } finally { co.aikar.timings.MinecraftTimings.distanceManagerTick.stopTiming(); } // Paper - add timings for distance manager
|
||||
}
|
||||
|
||||
private static final ThreadLocal<List<ChunkProgressionTask>> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>();
|
||||
@@ -1,22 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 7 Mar 2021 13:15:04 -0800
|
||||
Subject: [PATCH] Do not run raytrace logic for AIR
|
||||
|
||||
Saves approx. 5% for the raytrace call, as most (expensive)
|
||||
raytracing tends to go through air and returning early is an
|
||||
easy win. The remaining problems with this function
|
||||
are mostly with the block getting itself.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -0,0 +0,0 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||
return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), new BlockPos(raytrace1.getTo()));
|
||||
}
|
||||
// Paper end
|
||||
+ if (iblockdata.isAir()) return null; // Paper - optimise air cases
|
||||
FluidState fluid = iblockdata.getFluidState(); // Paper - don't need to go to world state again
|
||||
Vec3 vec3d = raytrace1.getFrom();
|
||||
Vec3 vec3d1 = raytrace1.getTo();
|
||||
@@ -1,45 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Tue, 7 Dec 2021 19:34:23 -0500
|
||||
Subject: [PATCH] Dolphin API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java
|
||||
@@ -0,0 +0,0 @@ public class CraftDolphin extends CraftWaterMob implements Dolphin {
|
||||
public EntityType getType() {
|
||||
return EntityType.DOLPHIN;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public int getMoistness() {
|
||||
+ return this.getHandle().getMoistnessLevel();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMoistness(int moistness) {
|
||||
+ this.getHandle().setMoisntessLevel(moistness);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setHasFish(boolean hasFish) {
|
||||
+ this.getHandle().setGotFish(hasFish);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasFish() {
|
||||
+ return this.getHandle().gotFish();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.Location getTreasureLocation() {
|
||||
+ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level, this.getHandle().getTreasurePos());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setTreasureLocation(org.bukkit.Location location) {
|
||||
+ this.getHandle().setTreasurePos(io.papermc.paper.util.MCUtil.toBlockPosition(location));
|
||||
+ }
|
||||
}
|
||||
@@ -1,25 +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 implements ServerPlayerConnection, Tic
|
||||
} else {
|
||||
Entity entity = this.player.getRootVehicle();
|
||||
|
||||
+ // Paper start
|
||||
+ if (this.awaitingPositionFromClient != null || this.player.isImmobile() || entity.isRemoved()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
if (entity != this.player && entity.getControllingPassenger() == this.player && entity == this.lastVehicle) {
|
||||
ServerLevel worldserver = this.player.getLevel();
|
||||
double d0 = entity.getX();final double fromX = d0; // Paper - OBFHELPER
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Noah van der Aa <ndvdaa@gmail.com>
|
||||
Date: Tue, 14 Sep 2021 16:24:45 +0200
|
||||
Subject: [PATCH] Don't log debug logging being disabled
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
@@ -0,0 +0,0 @@ public class SpigotConfig
|
||||
Bukkit.getLogger().info( "Debug logging is enabled" );
|
||||
} else
|
||||
{
|
||||
- Bukkit.getLogger().info( "Debug logging is disabled" );
|
||||
+ // Bukkit.getLogger().info( "Debug logging is disabled" ); // Paper - Don't log if debug logging isn't enabled.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 28 Aug 2020 12:33:47 -0700
|
||||
Subject: [PATCH] Don't lookup fluid state when raytracing
|
||||
|
||||
Just use the iblockdata already retrieved, removes a getType call.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||
@@ -0,0 +0,0 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||
return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), new BlockPos(raytrace1.getTo()));
|
||||
}
|
||||
// Paper end
|
||||
- FluidState fluid = this.getFluidState(blockposition);
|
||||
+ FluidState fluid = iblockdata.getFluidState(); // Paper - don't need to go to world state again
|
||||
Vec3 vec3d = raytrace1.getFrom();
|
||||
Vec3 vec3d1 = raytrace1.getTo();
|
||||
VoxelShape voxelshape = raytrace1.getBlockShape(iblockdata, this, blockposition);
|
||||
@@ -1,21 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 11 Apr 2021 02:58:48 -0700
|
||||
Subject: [PATCH] Don't read neighbour chunk data off disk when converting
|
||||
chunks
|
||||
|
||||
Lighting is purged on update anyways, so let's not add more
|
||||
into the conversion process
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean check(ServerChunkCache cps, int x, int z) {
|
||||
+ if (true) return true; // Paper - this isn't even needed anymore, light is purged updating to 1.14+, why are we holding up the conversion process reading chunk data off disk - return true, we need to set light populated to true so the converter recognizes the chunk as being "full"
|
||||
ChunkPos pos = new ChunkPos(x, z);
|
||||
if (cps != null) {
|
||||
//com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); // Paper - this function is now MT-Safe
|
||||
@@ -1,23 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: stonar96 <minecraft.stonar96@gmail.com>
|
||||
Date: Sun, 12 Sep 2021 00:14:21 +0200
|
||||
Subject: [PATCH] Don't respond to ServerboundCommandSuggestionPacket when
|
||||
tab-complete is disabled
|
||||
|
||||
|
||||
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 implements ServerPlayerConnection, Tic
|
||||
}
|
||||
// Paper end
|
||||
// CraftBukkit end
|
||||
+ // Paper start - Don't suggest if tab-complete is disabled
|
||||
+ if (org.spigotmc.SpigotConfig.tabComplete < 0) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Don't suggest if tab-complete is disabled
|
||||
// Paper start - async tab completion
|
||||
TAB_COMPLETE_EXECUTOR.execute(() -> {
|
||||
StringReader stringreader = new StringReader(packet.getCommand());
|
||||
@@ -1,24 +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 Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
protected boolean addPassenger(Entity entity) { // CraftBukkit
|
||||
+ // Paper start
|
||||
+ if (entity.level != this.level) {
|
||||
+ LOGGER.error("Entity passenger world must match, cannot add " + entity + " as passenger to " + this, new Throwable());
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (entity == this) throw new IllegalArgumentException("Entities cannot become a passenger of themselves"); // Paper - issue 572
|
||||
if (entity.getVehicle() != this) {
|
||||
throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)");
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Tue, 28 Sep 2021 09:47:47 +0200
|
||||
Subject: [PATCH] Ensure valid vehicle status
|
||||
|
||||
|
||||
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 Player {
|
||||
}
|
||||
}
|
||||
|
||||
- if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger()) {
|
||||
+ if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger() && !entity.isRemoved()) { // Paper
|
||||
// CraftBukkit end
|
||||
CompoundTag nbttagcompound2 = new CompoundTag();
|
||||
CompoundTag nbttagcompound3 = new CompoundTag();
|
||||
@@ -1,39 +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 {
|
||||
entity.setRot(location.getYaw(), location.getPitch());
|
||||
return !entity.valid && entity.level.addFreshEntity(entity, reason);
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isInPowderedSnow() {
|
||||
+ return getHandle().isInPowderSnow || getHandle().wasInPowderSnow; // depending on the location in the entity "tick" either could be needed.
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -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
|
||||
this.executeMidTickTasks(); // Paper - execute chunk tasks mid tick
|
||||
return true;
|
||||
} else {
|
||||
+ boolean ret = false; // Paper - force execution of all worlds, do not just bias the first
|
||||
if (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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Apr 2020 04:20:44 -0700
|
||||
Subject: [PATCH] Execute chunk tasks mid-tick
|
||||
|
||||
This will help the server load chunks if tick times are high.
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
@@ -0,0 +0,0 @@ public final class MinecraftTimings {
|
||||
public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update");
|
||||
public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate");
|
||||
|
||||
+ public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks");
|
||||
+
|
||||
private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
|
||||
|
||||
private MinecraftTimings() {}
|
||||
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
|
||||
|
||||
private boolean pollTaskInternal() {
|
||||
if (super.pollTask()) {
|
||||
+ this.executeMidTickTasks(); // Paper - execute chunk tasks mid tick
|
||||
return true;
|
||||
} else {
|
||||
if (this.haveTime()) {
|
||||
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
+
|
||||
+ // Paper start - execute chunk tasks mid tick
|
||||
+ static final long CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME = 25L * 1000L; // 25us
|
||||
+ static final long MAX_CHUNK_EXEC_TIME = 1000L; // 1us
|
||||
+
|
||||
+ static final long TASK_EXECUTION_FAILURE_BACKOFF = 5L * 1000L; // 5us
|
||||
+
|
||||
+ private static long lastMidTickExecute;
|
||||
+ private static long lastMidTickExecuteFailure;
|
||||
+
|
||||
+ private boolean tickMidTickTasks() {
|
||||
+ // give all worlds a fair chance at by targetting them all.
|
||||
+ // if we execute too many tasks, that's fine - we have logic to correctly handle overuse of allocated time.
|
||||
+ boolean executed = false;
|
||||
+ for (ServerLevel world : this.getAllLevels()) {
|
||||
+ long currTime = System.nanoTime();
|
||||
+ if (currTime - world.lastMidTickExecuteFailure <= TASK_EXECUTION_FAILURE_BACKOFF) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!world.getChunkSource().pollTask()) {
|
||||
+ // we need to back off if this fails
|
||||
+ world.lastMidTickExecuteFailure = currTime;
|
||||
+ } else {
|
||||
+ executed = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return executed;
|
||||
+ }
|
||||
+
|
||||
+ public final void executeMidTickTasks() {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("mid tick chunk task execution");
|
||||
+ long startTime = System.nanoTime();
|
||||
+ if ((startTime - lastMidTickExecute) <= CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME || (startTime - lastMidTickExecuteFailure) <= TASK_EXECUTION_FAILURE_BACKOFF) {
|
||||
+ // it's shown to be bad to constantly hit the queue (chunk loads slow to a crawl), even if no tasks are executed.
|
||||
+ // so, backoff to prevent this
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ co.aikar.timings.MinecraftTimings.midTickChunkTasks.startTiming();
|
||||
+ try {
|
||||
+ for (;;) {
|
||||
+ boolean moreTasks = this.tickMidTickTasks();
|
||||
+ long currTime = System.nanoTime();
|
||||
+ long diff = currTime - startTime;
|
||||
+
|
||||
+ if (!moreTasks || diff >= MAX_CHUNK_EXEC_TIME) {
|
||||
+ if (!moreTasks) {
|
||||
+ lastMidTickExecuteFailure = currTime;
|
||||
+ }
|
||||
+
|
||||
+ // note: negative values reduce the time
|
||||
+ long overuse = diff - MAX_CHUNK_EXEC_TIME;
|
||||
+ if (overuse >= (10L * 1000L * 1000L)) { // 10ms
|
||||
+ // make sure something like a GC or dumb plugin doesn't screw us over...
|
||||
+ overuse = 10L * 1000L * 1000L; // 10ms
|
||||
+ }
|
||||
+
|
||||
+ double overuseCount = (double)overuse/(double)MAX_CHUNK_EXEC_TIME;
|
||||
+ long extraSleep = (long)Math.round(overuseCount*CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME);
|
||||
+
|
||||
+ lastMidTickExecute = currTime + extraSleep;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ } finally {
|
||||
+ co.aikar.timings.MinecraftTimings.midTickChunkTasks.stopTiming();
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - execute chunk tasks mid tick
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
iterator1 = shuffled.iterator();
|
||||
}
|
||||
|
||||
+ int chunksTicked = 0; // Paper
|
||||
try {
|
||||
while (iterator1.hasNext()) {
|
||||
LevelChunk chunk1 = iterator1.next();
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
|
||||
if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - the chunk is known ticking
|
||||
this.level.tickChunk(chunk1, k);
|
||||
+ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper
|
||||
}
|
||||
}
|
||||
// Paper start - optimise chunk tick iteration
|
||||
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 {
|
||||
private final StructureManager structureManager;
|
||||
private final StructureCheck structureCheck;
|
||||
private final boolean tickTime;
|
||||
+ public long lastMidTickExecuteFailure; // Paper - execute chunk tasks mid tick
|
||||
|
||||
// CraftBukkit start
|
||||
public final LevelStorageSource.LevelStorageAccess convertable;
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
if (fluid1.is(fluid)) {
|
||||
fluid1.tick(this, pos);
|
||||
}
|
||||
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
if (iblockdata.is(block)) {
|
||||
iblockdata.tick(this, pos, this.random);
|
||||
}
|
||||
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick
|
||||
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// Spigot end
|
||||
} else if (this.shouldTickBlocksAt(tickingblockentity.getPos())) {
|
||||
tickingblockentity.tick();
|
||||
+ // Paper start - execute chunk tasks during tick
|
||||
+ if ((this.tileTickPosition & 7) == 0) {
|
||||
+ MinecraftServer.getServer().executeMidTickTasks();
|
||||
+ }
|
||||
+ // Paper end - execute chunk tasks during tick
|
||||
}
|
||||
}
|
||||
this.blockEntityTickers.removeAll(toRemove);
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) {
|
||||
try {
|
||||
tickConsumer.accept(entity);
|
||||
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick
|
||||
} catch (Throwable throwable) {
|
||||
if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
||||
// Paper start - Prevent tile entity and entity crashes
|
||||
@@ -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";
|
||||
@@ -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
|
||||
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.SimpleContainer(CraftItemStack.asNMSCopy(stack)), world).isPresent();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Furnace getHolder() {
|
||||
return (Furnace) inventory.getOwner();
|
||||
@@ -1,139 +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
|
||||
if (biomeProvider == null && gen != null) {
|
||||
biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
|
||||
}
|
||||
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
|
||||
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.biome.BiomeSource biomeSource = serverCache.getGenerator().getBiomeSource();
|
||||
+ final net.minecraft.world.level.biome.Climate.Sampler sampler = serverCache.randomState().sampler();
|
||||
+ final net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry = this.getHandle().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.BIOME);
|
||||
+
|
||||
+ final List<Biome> possibleBiomes = biomeSource.possibleBiomes().stream()
|
||||
+ .map(biome -> CraftBlock.biomeBaseToBiome(biomeRegistry, biome))
|
||||
+ .toList();
|
||||
+ return new BiomeProvider() {
|
||||
+ @Override
|
||||
+ public Biome getBiome(final org.bukkit.generator.WorldInfo worldInfo, final int x, final int y, final int z) {
|
||||
+ return CraftBlock.biomeBaseToBiome(biomeRegistry, biomeSource.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(ServerLevelData 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 net.minecraft.core.Registry<net.minecraft.world.level.biome.Biome> biomeRegistry = CraftWorldInfo.this.registryAccess.registryOrThrow(net.minecraft.core.registries.Registries.BIOME);
|
||||
+ final java.util.List<org.bukkit.block.Biome> possibleBiomes = CraftWorldInfo.this.vanillaChunkGenerator.getBiomeSource().possibleBiomes().stream()
|
||||
+ .map(biome -> org.bukkit.craftbukkit.block.CraftBlock.biomeBaseToBiome(biomeRegistry, 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.CraftBlock.biomeBaseToBiome(biomeRegistry,
|
||||
+ 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
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Sun, 24 Oct 2021 15:49:35 +0200
|
||||
Subject: [PATCH] Fix Bukkit NamespacedKey shenanigans
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
|
||||
@@ -0,0 +0,0 @@ public class PaperContainerEntityLootableInventory implements PaperLootableEntit
|
||||
|
||||
@Override
|
||||
public org.bukkit.loot.LootTable getLootTable() {
|
||||
- return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
|
||||
+ return entity.getLootTable() != null && !entity.getLootTable().getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
|
||||
@@ -0,0 +0,0 @@ public class PaperTileEntityLootableInventory implements PaperLootableBlockInven
|
||||
|
||||
@Override
|
||||
public org.bukkit.loot.LootTable getLootTable() {
|
||||
- return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
|
||||
+ return tileEntityLootable.lootTable != null && !tileEntityLootable.lootTable.getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java
|
||||
@@ -0,0 +0,0 @@ public final class CraftNamespacedKey {
|
||||
return null;
|
||||
}
|
||||
ResourceLocation minecraft = ResourceLocation.tryParse(string);
|
||||
- return (minecraft == null) ? null : CraftNamespacedKey.fromMinecraft(minecraft);
|
||||
+ return (minecraft == null || minecraft.getPath().isEmpty()) ? null : CraftNamespacedKey.fromMinecraft(minecraft); // Paper - Bukkit's parser does not match Vanilla for empty paths
|
||||
}
|
||||
|
||||
public static NamespacedKey fromString(String string) {
|
||||
@@ -1,43 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Thu, 9 Dec 2021 00:08:11 -0800
|
||||
Subject: [PATCH] Fix ChunkSnapshot#isSectionEmpty(int) and optimize
|
||||
PalettedContainer copying by not using codecs
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
||||
@@ -0,0 +0,0 @@ public class CraftChunk implements Chunk {
|
||||
PalettedContainerRO<Holder<net.minecraft.world.level.biome.Biome>>[] biome = (includeBiome || includeBiomeTempRain) ? new PalettedContainer[cs.length] : null;
|
||||
|
||||
Registry<net.minecraft.world.level.biome.Biome> iregistry = this.worldServer.registryAccess().registryOrThrow(Registries.BIOME);
|
||||
- Codec<PalettedContainerRO<Holder<net.minecraft.world.level.biome.Biome>>> biomeCodec = PalettedContainer.codecRO(iregistry.asHolderIdMap(), iregistry.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, iregistry.getHolderOrThrow(Biomes.PLAINS));
|
||||
|
||||
for (int i = 0; i < cs.length; i++) {
|
||||
- CompoundTag data = new CompoundTag();
|
||||
|
||||
- data.put("block_states", ChunkSerializer.BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, cs[i].getStates()).get().left().get());
|
||||
- sectionBlockIDs[i] = ChunkSerializer.BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, data.getCompound("block_states")).get().left().get();
|
||||
+ // Paper start
|
||||
+ sectionEmpty[i] = cs[i].hasOnlyAir(); // Paper - fix sectionEmpty array not being filled
|
||||
+ if (!sectionEmpty[i]) {
|
||||
+ sectionBlockIDs[i] = cs[i].getStates().copy(); // Paper - use copy instead of round tripping with codecs
|
||||
+ } else {
|
||||
+ sectionBlockIDs[i] = CraftChunk.emptyBlockIDs; // Paper - use cached instance for empty block sections
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
LevelLightEngine lightengine = chunk.level.getLightEngine();
|
||||
DataLayer skyLightArray = lightengine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(x, i, z));
|
||||
@@ -0,0 +0,0 @@ public class CraftChunk implements Chunk {
|
||||
}
|
||||
|
||||
if (biome != null) {
|
||||
- data.put("biomes", biomeCodec.encodeStart(NbtOps.INSTANCE, cs[i].getBiomes()).get().left().get());
|
||||
- biome[i] = biomeCodec.parse(NbtOps.INSTANCE, data.getCompound("biomes")).get().left().get();
|
||||
+ biome[i] = ((PalettedContainer<Holder<net.minecraft.world.level.biome.Biome>>) cs[i].getBiomes()).copy(); // Paper - use copy instead of round tripping with codecs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Tue, 7 Sep 2021 21:29:38 +0100
|
||||
Subject: [PATCH] Fix CocaoDecorator causing a crash when trying to generate
|
||||
without logs
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/treedecorators/CocoaDecorator.java
|
||||
@@ -0,0 +0,0 @@ public class CocoaDecorator extends TreeDecorator {
|
||||
|
||||
@Override
|
||||
public void place(TreeDecorator.Context generator) {
|
||||
+ if (generator.logs().isEmpty()) return; // Paper
|
||||
RandomSource randomSource = generator.random();
|
||||
if (!(randomSource.nextFloat() >= this.probability)) {
|
||||
List<BlockPos> list = generator.logs();
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Mon, 4 Oct 2021 22:31:51 -0700
|
||||
Subject: [PATCH] Fix CraftCriteria defaults map
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftCriteria.java
|
||||
@@ -0,0 +0,0 @@ public final class CraftCriteria implements Criteria {
|
||||
}
|
||||
|
||||
static CraftCriteria getFromNMS(Objective objective) {
|
||||
- return CraftCriteria.DEFAULTS.get(objective.getCriteria().getName());
|
||||
+ return java.util.Objects.requireNonNullElseGet(CraftCriteria.DEFAULTS.get(objective.getCriteria().getName()), () -> new CraftCriteria(objective.getCriteria())); // Paper
|
||||
}
|
||||
|
||||
public static CraftCriteria getFromBukkit(String name) {
|
||||
@@ -1,23 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
|
||||
Date: Thu, 23 Dec 2021 23:59:12 -0500
|
||||
Subject: [PATCH] Fix Entity Position Desync
|
||||
|
||||
If entities were teleported in the first tick it would not be send to the client.
|
||||
|
||||
This excludes hanging entities, as this fix caused problematic behavior due to them having their own
|
||||
position field.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
boolean flag2 = flag1 || this.tickCount % 60 == 0;
|
||||
boolean flag3 = Math.abs(i - this.yRotp) >= 1 || Math.abs(j - this.xRotp) >= 1;
|
||||
|
||||
- if (this.tickCount > 0 || this.entity instanceof AbstractArrow) {
|
||||
+ if (!(this.entity instanceof net.minecraft.world.entity.decoration.HangingEntity) || this.tickCount > 0 || this.entity instanceof AbstractArrow) { // Paper - Always update position
|
||||
long k = this.positionCodec.encodeX(vec3d);
|
||||
long l = this.positionCodec.encodeY(vec3d);
|
||||
long i1 = this.positionCodec.encodeZ(vec3d);
|
||||
@@ -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
|
||||
world.setBlock(blockposition2, Blocks.BARRIER.defaultBlockState(), 20);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +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)).requiresAirAbove() || 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 - TODO any way to cancel the game event?
|
||||
world.blockEvent(pos, this, 0, 0);
|
||||
world.gameEvent(entity, GameEvent.NOTE_BLOCK_PLAY, pos);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class NoteBlock extends Block {
|
||||
|
||||
@Override
|
||||
public boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
|
||||
+ // Paper start - move NotePlayEvent call to fix instrument/note changes
|
||||
+ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(world, pos, state.getValue(INSTRUMENT), state.getValue(NOTE));
|
||||
+ if (event.isCancelled()) return false;
|
||||
+ // Paper end
|
||||
NoteBlockInstrument blockpropertyinstrument = (NoteBlockInstrument) state.getValue(NoteBlock.INSTRUMENT);
|
||||
float f;
|
||||
|
||||
if (blockpropertyinstrument.isTunable()) {
|
||||
- int k = (Integer) state.getValue(NoteBlock.NOTE);
|
||||
+ int k = event.getNote().getId(); // Paper
|
||||
|
||||
f = (float) Math.pow(2.0D, (double) (k - 12) / 12.0D);
|
||||
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 = blockpropertyinstrument.getSoundEvent();
|
||||
}
|
||||
|
||||
- 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());
|
||||
+ world.playSeededSound((Player) null, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, org.bukkit.craftbukkit.block.data.CraftBlockData.toNMS(event.getInstrument(), NoteBlockInstrument.class).getSoundEvent(), SoundSource.RECORDS, 3.0F, f, world.random.nextLong()); // Paper
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Fri, 3 Dec 2021 17:09:24 -0800
|
||||
Subject: [PATCH] Fix Spigot growth modifiers
|
||||
|
||||
Fixes kelp modifier changing growth for other crops
|
||||
Also add growth modifiers for glow berries
|
||||
Also fix above-mentioned modifiers from having the reverse effect
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Co-authored-by: Noah van der Aa <ndvdaa@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/CaveVinesBlock.java
|
||||
@@ -0,0 +0,0 @@ public class CaveVinesBlock extends GrowingPlantHeadBlock implements Bonemealabl
|
||||
|
||||
@Override
|
||||
protected BlockState getGrowIntoState(BlockState state, RandomSource random) {
|
||||
- return (BlockState) super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, random.nextFloat() < 0.11F);
|
||||
+ // Paper start
|
||||
+ return this.getGrowIntoState(state, random, null);
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) {
|
||||
+ final boolean value = random.nextFloat() < (level != null ? (0.11F * (level.spigotConfig.glowBerryModifier / 100.0F)) : 0.11F);
|
||||
+ return (BlockState) super.getGrowIntoState(state, random).setValue(CaveVinesBlock.BERRIES, value);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public ItemStack getCloneItemStack(BlockGetter world, BlockPos pos, BlockState state) {
|
||||
return new ItemStack(Items.GLOW_BERRIES);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
|
||||
@@ -0,0 +0,0 @@ public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements
|
||||
BlockPos blockposition1 = pos.relative(this.growthDirection);
|
||||
|
||||
if (this.canGrowInto(world.getBlockState(blockposition1))) {
|
||||
- org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random)); // CraftBukkit
|
||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random, world)); // CraftBukkit // Paper
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) {
|
||||
+ return this.getGrowIntoState(state, random);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
protected BlockState getGrowIntoState(BlockState state, RandomSource random) {
|
||||
return (BlockState) state.cycle(GrowingPlantHeadBlock.AGE);
|
||||
}
|
||||
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 twistingVinesModifier;
|
||||
public int weepingVinesModifier;
|
||||
public int caveVinesModifier;
|
||||
+ public int glowBerryModifier; // Paper
|
||||
private int getAndValidateGrowth(String crop)
|
||||
{
|
||||
int modifier = this.getInt( "growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100 );
|
||||
@@ -0,0 +0,0 @@ public class SpigotWorldConfig
|
||||
this.twistingVinesModifier = this.getAndValidateGrowth( "TwistingVines" );
|
||||
this.weepingVinesModifier = this.getAndValidateGrowth( "WeepingVines" );
|
||||
this.caveVinesModifier = this.getAndValidateGrowth( "CaveVines" );
|
||||
+ this.glowBerryModifier = this.getAndValidateGrowth("GlowBerry"); // Paper
|
||||
}
|
||||
|
||||
public double itemMerge;
|
||||
@@ -1,19 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Tue, 12 Apr 2022 16:36:15 -0700
|
||||
Subject: [PATCH] Fix StructureGrowEvent species for RED_MUSHROOM
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java
|
||||
@@ -0,0 +0,0 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock {
|
||||
return false;
|
||||
} else {
|
||||
world.removeBlock(pos, false);
|
||||
- SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? TreeType.BROWN_MUSHROOM : TreeType.BROWN_MUSHROOM; // CraftBukkit
|
||||
+ SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? TreeType.BROWN_MUSHROOM : TreeType.RED_MUSHROOM; // CraftBukkit // Paper
|
||||
if (((ConfiguredFeature) ((Holder) optional.get()).value()).place(world, world.getChunkSource().getGenerator(), random, pos)) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -1,49 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sat, 21 Aug 2021 21:54:16 -0700
|
||||
Subject: [PATCH] Fix bees aging inside hives
|
||||
|
||||
Fixes bees incorrectly being aged up due to upstream's
|
||||
resetting the ticks inside hive on a failed release
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
|
||||
@@ -0,0 +0,0 @@ public class BeehiveBlockEntity extends BlockEntity {
|
||||
|
||||
for (Iterator iterator = bees.iterator(); iterator.hasNext(); ++tileentitybeehive_hivebee.ticksInHive) {
|
||||
tileentitybeehive_hivebee = (BeehiveBlockEntity.BeeData) iterator.next();
|
||||
- if (tileentitybeehive_hivebee.ticksInHive > tileentitybeehive_hivebee.minOccupationTicks) {
|
||||
+ if (tileentitybeehive_hivebee.exitTickCounter > tileentitybeehive_hivebee.minOccupationTicks) { // Paper - use exitTickCounter
|
||||
BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus = tileentitybeehive_hivebee.entityData.getBoolean("HasNectar") ? BeehiveBlockEntity.BeeReleaseStatus.HONEY_DELIVERED : BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED;
|
||||
|
||||
if (BeehiveBlockEntity.releaseOccupant(world, pos, state, tileentitybeehive_hivebee, (List) null, tileentitybeehive_releasestatus, flowerPos)) {
|
||||
@@ -0,0 +0,0 @@ public class BeehiveBlockEntity extends BlockEntity {
|
||||
iterator.remove();
|
||||
// CraftBukkit start
|
||||
} else {
|
||||
- tileentitybeehive_hivebee.ticksInHive = tileentitybeehive_hivebee.minOccupationTicks / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable
|
||||
+ tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.minOccupationTicks / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - use exitTickCounter to keep actual bee life
|
||||
// CraftBukkit end
|
||||
}
|
||||
}
|
||||
+ tileentitybeehive_hivebee.exitTickCounter++; // Paper
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
@@ -0,0 +0,0 @@ public class BeehiveBlockEntity extends BlockEntity {
|
||||
|
||||
final CompoundTag entityData;
|
||||
int ticksInHive;
|
||||
+ int exitTickCounter; // Paper - separate counter for checking if bee should exit to reduce exit attempts
|
||||
final int minOccupationTicks;
|
||||
|
||||
BeeData(CompoundTag entityData, int ticksInHive, int minOccupationTicks) {
|
||||
BeehiveBlockEntity.removeIgnoredBeeTags(entityData);
|
||||
this.entityData = entityData;
|
||||
this.ticksInHive = ticksInHive;
|
||||
+ this.exitTickCounter = ticksInHive; // Paper
|
||||
this.minOccupationTicks = minOccupationTicks;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +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/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 {
|
||||
blockstate.update(true, false);
|
||||
|
||||
if (this instanceof SolidBucketItem) {
|
||||
+ ((ServerPlayer) entityhuman).connection.send(new net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket(world, blockposition.below())); // Paper - update block below
|
||||
((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541
|
||||
}
|
||||
return InteractionResult.FAIL;
|
||||
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 {
|
||||
int oldCount = this.getCount();
|
||||
ServerLevel world = (ServerLevel) itemactioncontext.getLevel();
|
||||
|
||||
- if (!(this.getItem() instanceof BucketItem || this.getItem() instanceof SolidBucketItem)) { // if not bucket
|
||||
+ if (!(this.getItem() instanceof BucketItem/* || this.getItem() instanceof SolidBucketItem*/)) { // if not bucket // Paper - capture block states for snow buckets
|
||||
world.captureBlockStates = true;
|
||||
// special case bonemeal
|
||||
if (this.getItem() == Items.BONE_MEAL) {
|
||||
@@ -0,0 +0,0 @@ public final class ItemStack {
|
||||
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 - don't call event twice for snow buckets
|
||||
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, enumhand, blocks.get(0), blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+ @Override
|
||||
+ public void preOnHit(HitResult hitResult) {
|
||||
+ super.preOnHit(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());
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
private boolean shouldFall() {
|
||||
return this.inGround && this.level.noCollision((new AABB(this.position(), this.position())).inflate(0.06D));
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 22 Aug 2021 15:21:57 -0700
|
||||
Subject: [PATCH] Fix entity type tags suggestions in selectors
|
||||
|
||||
This would really be better as a client fix because just to fix it
|
||||
all EntityArguments have been told to ask the server for completions
|
||||
when if this was fixed on the client, that wouldn't be needed.
|
||||
|
||||
Mojira Issue: https://bugs.mojang.com/browse/MC-235045
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -0,0 +0,0 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
|
||||
return this.source.getBukkitSender(this);
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Paper start - override getSelectedEntities
|
||||
+ @Override
|
||||
+ public Collection<String> getSelectedEntities() {
|
||||
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) {
|
||||
+ double pickDistance = player.gameMode.getGameModeForPlayer().isCreative() ? 5.0F : 4.5F;
|
||||
+ Vec3 min = player.getEyePosition(1.0F);
|
||||
+ Vec3 viewVector = player.getViewVector(1.0F);
|
||||
+ Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance);
|
||||
+ net.minecraft.world.phys.AABB aabb = player.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D);
|
||||
+ pickDistance = player.gameMode.getGameModeForPlayer().isCreative() ? 6.0F : pickDistance;
|
||||
+ net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(player, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance);
|
||||
+ return hitResult != null ? java.util.Collections.singletonList(hitResult.getEntity().getStringUUID()) : SharedSuggestionProvider.super.getSelectedEntities();
|
||||
+ }
|
||||
+ return SharedSuggestionProvider.super.getSelectedEntities();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -0,0 +0,0 @@ public class Commands {
|
||||
private void fillUsableCommands(CommandNode<CommandSourceStack> tree, CommandNode<SharedSuggestionProvider> result, CommandSourceStack source, Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> resultNodes) {
|
||||
Iterator iterator = tree.getChildren().iterator();
|
||||
|
||||
+ boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments
|
||||
while (iterator.hasNext()) {
|
||||
CommandNode<CommandSourceStack> commandnode2 = (CommandNode) iterator.next();
|
||||
// Paper start
|
||||
@@ -0,0 +0,0 @@ public class Commands {
|
||||
|
||||
if (requiredargumentbuilder.getSuggestionsProvider() != null) {
|
||||
requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider()));
|
||||
+ // Paper start - tell clients to ask server for suggestions for EntityArguments
|
||||
+ registeredAskServerSuggestionsForTree = requiredargumentbuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER;
|
||||
+ } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredargumentbuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) {
|
||||
+ requiredargumentbuilder.suggests(requiredargumentbuilder.getType()::listSuggestions);
|
||||
+ registeredAskServerSuggestionsForTree = true; // You can only
|
||||
+ // Paper end - tell clients to ask server for suggestions for EntityArguments
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
|
||||
+++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java
|
||||
@@ -0,0 +0,0 @@ public class EntityArgument implements ArgumentType<EntitySelector> {
|
||||
StringReader stringreader = new StringReader(suggestionsbuilder.getInput());
|
||||
|
||||
stringreader.setCursor(suggestionsbuilder.getStart());
|
||||
- EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2));
|
||||
+ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2), true); // Paper
|
||||
|
||||
try {
|
||||
argumentparserselector.parse();
|
||||
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
|
||||
@@ -0,0 +0,0 @@ public class EntitySelectorParser {
|
||||
private boolean hasScores;
|
||||
private boolean hasAdvancements;
|
||||
private boolean usesSelectors;
|
||||
+ public boolean parsingEntityArgumentSuggestions; // Paper - track when parsing EntityArgument suggestions
|
||||
|
||||
public EntitySelectorParser(StringReader reader) {
|
||||
this(reader, true);
|
||||
}
|
||||
|
||||
public EntitySelectorParser(StringReader reader, boolean atAllowed) {
|
||||
+ // Paper start
|
||||
+ this(reader, atAllowed, false);
|
||||
+ }
|
||||
+ public EntitySelectorParser(StringReader reader, boolean atAllowed, boolean parsingEntityArgumentSuggestions) {
|
||||
+ this.parsingEntityArgumentSuggestions = parsingEntityArgumentSuggestions;
|
||||
+ // Paper end
|
||||
this.distance = MinMaxBounds.Doubles.ANY;
|
||||
this.level = MinMaxBounds.Ints.ANY;
|
||||
this.rotX = WrappedMinMaxBounds.ANY;
|
||||
diff --git a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
+++ b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java
|
||||
@@ -0,0 +0,0 @@ public class EntitySelectorOptions {
|
||||
public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType((entity) -> {
|
||||
return Component.translatable("argument.entity.options.type.invalid", entity);
|
||||
});
|
||||
+ // Paper start
|
||||
+ public static final DynamicCommandExceptionType ERROR_ENTITY_TAG_INVALID = new DynamicCommandExceptionType((object) -> {
|
||||
+ return io.papermc.paper.adventure.PaperAdventure
|
||||
+ .asVanilla(net.kyori.adventure.text.Component
|
||||
+ .text("Invalid or unknown entity type tag '" + object + "'")
|
||||
+ .hoverEvent(net.kyori.adventure.text.event.HoverEvent
|
||||
+ .showText(net.kyori.adventure.text.Component
|
||||
+ .text("You can disable this error in 'paper.yml'")
|
||||
+ )
|
||||
+ )
|
||||
+ );
|
||||
+ });
|
||||
+ // Paper end
|
||||
|
||||
private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate<EntitySelectorParser> condition, Component description) {
|
||||
OPTIONS.put(id, new EntitySelectorOptions.Option(handler, condition, description));
|
||||
@@ -0,0 +0,0 @@ public class EntitySelectorOptions {
|
||||
|
||||
if (reader.isTag()) {
|
||||
TagKey<EntityType<?>> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(reader.getReader()));
|
||||
+ // Paper start - throw error if invalid entity tag (only on suggestions to keep cmd success behavior)
|
||||
+ if (reader.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getTag(tagKey).isEmpty()) {
|
||||
+ reader.getReader().setCursor(i);
|
||||
+ throw ERROR_ENTITY_TAG_INVALID.createWithContext(reader.getReader(), tagKey);
|
||||
+ }
|
||||
+ // Paper end
|
||||
reader.addPredicate((entity) -> {
|
||||
return entity.getType().is(tagKey) != bl;
|
||||
});
|
||||
@@ -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/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 {
|
||||
// Paper end
|
||||
} else if (FallingBlock.class.isAssignableFrom(clazz)) {
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
- entity = FallingBlockEntity.fall(world, pos, this.getHandle().getBlockState(pos));
|
||||
+ entity = new FallingBlockEntity(world, x, y, z, this.getHandle().getBlockState(pos)); // Paper
|
||||
} else if (Projectile.class.isAssignableFrom(clazz)) {
|
||||
if (Snowball.class.isAssignableFrom(clazz)) {
|
||||
entity = new net.minecraft.world.entity.projectile.Snowball(world, x, y, z);
|
||||
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 {
|
||||
Validate.notNull(material, "Material cannot be null");
|
||||
Validate.isTrue(material.isBlock(), "Material must be a block");
|
||||
|
||||
- FallingBlockEntity entity = FallingBlockEntity.fall(world, new BlockPos(location.getX(), location.getY(), location.getZ()), CraftMagicNumbers.getBlock(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(), CraftMagicNumbers.getBlock(material).defaultBlockState()); // Paper
|
||||
+ entity.time = 1;
|
||||
+
|
||||
+ this.world.addFreshEntity(entity, SpawnReason.CUSTOM);
|
||||
+ // Paper end
|
||||
return (FallingBlock) entity.getBukkitEntity();
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
Validate.notNull(location, "Location cannot be null");
|
||||
Validate.notNull(data, "BlockData cannot be null");
|
||||
|
||||
- FallingBlockEntity entity = FallingBlockEntity.fall(world, new BlockPos(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
|
||||
return (FallingBlock) entity.getBukkitEntity();
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Thu, 2 Sep 2021 00:24:06 -0700
|
||||
Subject: [PATCH] Fix merchant inventory not closing on entity removal
|
||||
|
||||
|
||||
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 {
|
||||
// Spigot end
|
||||
// Spigot Start
|
||||
if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message
|
||||
+ // Paper start
|
||||
+ if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) {
|
||||
+ merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED);
|
||||
+ }
|
||||
+ // Paper end
|
||||
for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) {
|
||||
h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
|
||||
}
|
||||
@@ -1,76 +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
|
||||
|
||||
Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
|
||||
|
||||
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.level.getBlockState(blockposition1).is(Blocks.GRASS_BLOCK)) {
|
||||
// CraftBukkit
|
||||
- if (!CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.AIR.defaultBlockState(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)).isCancelled()) {
|
||||
+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition1, Blocks.DIRT.defaultBlockState(), !this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)).isCancelled()) { // 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/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()).isCancelled()) {
|
||||
+ if (CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock()).isCancelled()) { // Paper
|
||||
continue;
|
||||
}
|
||||
// CraftBukkit end
|
||||
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 {
|
||||
BlockState iblockdata = this.level.getBlockState(blockposition);
|
||||
Block block = iblockdata.getBlock();
|
||||
|
||||
- if (block instanceof LeavesBlock && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState()).isCancelled()) { // CraftBukkit
|
||||
+ if (block instanceof LeavesBlock && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock()).isCancelled()) { // CraftBukkit // Paper
|
||||
flag = this.level.destroyBlock(blockposition, true, this) || flag;
|
||||
}
|
||||
}
|
||||
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 (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState()).isCancelled()) {
|
||||
+ // Paper start
|
||||
+ BlockState afterState = world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? net.minecraft.world.level.block.Blocks.AIR.defaultBlockState() : ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1));
|
||||
+ org.bukkit.event.entity.EntityChangeBlockEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, afterState);
|
||||
+ if (event.isCancelled()) {
|
||||
+ // Paper end
|
||||
continue;
|
||||
}
|
||||
// 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 (!world.isClientSide && projectile.mayInteract(world, blockposition) && projectile instanceof ThrownTrident && projectile.getDeltaMovement().length() > 0.6D) {
|
||||
// CraftBukkit start
|
||||
- if (CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, Blocks.AIR.defaultBlockState()).isCancelled()) {
|
||||
+ if (CraftEventFactory.callEntityChangeBlockEvent(projectile, blockposition, state.getFluidState().createLegacyBlock()).isCancelled()) { // Paper
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -1,51 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Tue, 30 Nov 2021 12:01:56 -0800
|
||||
Subject: [PATCH] Fix removing recipes from RecipeIterator
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.item.crafting.RecipeManager byName
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.inventory.Recipe;
|
||||
public class RecipeIterator implements Iterator<Recipe> {
|
||||
private final Iterator<Map.Entry<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, net.minecraft.world.item.crafting.Recipe<?>>>> recipes;
|
||||
private Iterator<net.minecraft.world.item.crafting.Recipe<?>> current;
|
||||
+ private Recipe currentRecipe; // Paper - fix removing recipes
|
||||
|
||||
public RecipeIterator() {
|
||||
this.recipes = MinecraftServer.getServer().getRecipeManager().recipes.entrySet().iterator();
|
||||
@@ -0,0 +0,0 @@ public class RecipeIterator implements Iterator<Recipe> {
|
||||
public Recipe next() {
|
||||
if (this.current == null || !this.current.hasNext()) {
|
||||
this.current = this.recipes.next().getValue().values().iterator();
|
||||
- return this.next();
|
||||
+ // Paper start - fix removing recipes
|
||||
+ this.currentRecipe = this.next();
|
||||
+ return this.currentRecipe;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
- return this.current.next().toBukkitRecipe();
|
||||
+ // Paper start - fix removing recipes
|
||||
+ this.currentRecipe = this.current.next().toBukkitRecipe();
|
||||
+ return this.currentRecipe;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class RecipeIterator implements Iterator<Recipe> {
|
||||
throw new IllegalStateException("next() not yet called");
|
||||
}
|
||||
|
||||
+ // Paper start - fix removing recipes
|
||||
+ if (this.currentRecipe instanceof org.bukkit.Keyed keyed) {
|
||||
+ MinecraftServer.getServer().getRecipeManager().byName.remove(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(keyed.getKey()));
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.current.remove();
|
||||
}
|
||||
}
|
||||
@@ -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 - don't disable saving
|
||||
}
|
||||
|
||||
handle.getChunkSource().close(save);
|
||||
@@ -1,71 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bjarne Koll <git@lynxplay.dev>
|
||||
Date: Sat, 6 Nov 2021 23:15:20 +0100
|
||||
Subject: [PATCH] Fix setPatternColor on tropical fish bucket meta
|
||||
|
||||
Prior to this commit, the tropical fish bucket meta would set the body
|
||||
color to the previous metas pattern colour when updating the pattern
|
||||
colour.
|
||||
|
||||
This commit hence simply fixes this by using the proper body colour
|
||||
value when updating the pattern color.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java
|
||||
@@ -0,0 +0,0 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB
|
||||
if (this.variant == null) {
|
||||
this.variant = 0;
|
||||
}
|
||||
- this.variant = CraftTropicalFish.getData(color, this.getPatternColor(), this.getPattern());
|
||||
+ this.variant = CraftTropicalFish.getData(color, this.getBodyColor(), this.getPattern()); // Paper - properly set tropical fish pattern color without mutating body color
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/io/papermc/paper/inventory/CraftMetaTropicalFishBucketTest.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.inventory;
|
||||
+
|
||||
+import org.bukkit.DyeColor;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.entity.TropicalFish;
|
||||
+import org.bukkit.inventory.ItemStack;
|
||||
+import org.bukkit.inventory.meta.TropicalFishBucketMeta;
|
||||
+import org.bukkit.support.AbstractTestingBase;
|
||||
+import org.junit.Assert;
|
||||
+import org.junit.Test;
|
||||
+
|
||||
+public class CraftMetaTropicalFishBucketTest extends AbstractTestingBase {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testAllCombinations() {
|
||||
+ final var rawMeta = new ItemStack(Material.TROPICAL_FISH_BUCKET).getItemMeta();
|
||||
+ Assert.assertTrue("Meta was not a tropical fish bucket", rawMeta instanceof TropicalFishBucketMeta);
|
||||
+
|
||||
+ final var meta = (TropicalFishBucketMeta) rawMeta;
|
||||
+
|
||||
+ for (final var bodyColor : DyeColor.values()) {
|
||||
+ for (final var pattern : TropicalFish.Pattern.values()) {
|
||||
+ for (final var patternColor : DyeColor.values()) {
|
||||
+ meta.setBodyColor(bodyColor);
|
||||
+ Assert.assertEquals("Body color did not match post body color!", bodyColor, meta.getBodyColor());
|
||||
+
|
||||
+ meta.setPattern(pattern);
|
||||
+ Assert.assertEquals("Pattern did not match post pattern!", pattern, meta.getPattern());
|
||||
+ Assert.assertEquals("Body color did not match post pattern!", bodyColor, meta.getBodyColor());
|
||||
+
|
||||
+ meta.setPatternColor(patternColor);
|
||||
+ Assert.assertEquals("Pattern did not match post pattern color!", pattern, meta.getPattern());
|
||||
+ Assert.assertEquals("Body color did not match post pattern color!", bodyColor, meta.getBodyColor());
|
||||
+ Assert.assertEquals("Pattern color did not match post pattern color!", patternColor, meta.getPatternColor());
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
@@ -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 - 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 iblockdata1 = (BlockState) ((BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(MovingPistonBlock.FACING, enumdirection)).setValue(MovingPistonBlock.TYPE, this.isSticky ? PistonType.STICKY : PistonType.DEFAULT);
|
||||
|
||||
+ // Paper start - 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
|
||||
world.setBlock(pos, iblockdata1, 20);
|
||||
world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, iblockdata1, (BlockState) this.defaultBlockState().setValue(PistonBaseBlock.FACING, Direction.from3DDataValue(data & 7)), enumdirection, false, true)); // Paper - diff on change
|
||||
world.blockUpdated(pos, iblockdata1.getBlock());
|
||||
@@ -0,0 +0,0 @@ public class PistonBaseBlock extends DirectionalBlock {
|
||||
if (type == 1 && !iblockdata2.isAir() && PistonBaseBlock.isPushable(iblockdata2, world, blockposition1, enumdirection.getOpposite(), false, enumdirection) && (iblockdata2.getPistonPushReaction() == PushReaction.NORMAL || iblockdata2.is(Blocks.PISTON) || iblockdata2.is(Blocks.STICKY_PISTON))) {
|
||||
this.moveBlocks(world, pos, enumdirection, false);
|
||||
} else {
|
||||
+ // Paper start - 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
|
||||
world.removeBlock(pos.relative(enumdirection), false);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +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<CatVariant> {
|
||||
});
|
||||
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 deadlock
|
||||
this.setVariant((CatVariant) BuiltInRegistries.CAT_VARIANT.getOrThrow(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
|
||||
+ 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
|
||||
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
|
||||
|
||||
for(Map.Entry<Structure, LongSet> entry : map.entrySet()) {
|
||||
@@ -0,0 +0,0 @@ public class StructureManager {
|
||||
}
|
||||
|
||||
public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey<Structure> structureTag) {
|
||||
+ // Paper start
|
||||
+ return this.getStructureWithPieceAt(pos, structureTag, null);
|
||||
+ }
|
||||
+ public StructureStart getStructureWithPieceAt(BlockPos pos, TagKey<Structure> structureTag, @Nullable ServerLevelAccessor levelAccessor) {
|
||||
+ // Paper end
|
||||
Registry<Structure> registry = this.registryAccess().registryOrThrow(Registries.STRUCTURE);
|
||||
|
||||
for(StructureStart structureStart : this.startsForStructure(new ChunkPos(pos), (structure) -> {
|
||||
return registry.getHolder(registry.getId(structure)).map((reference) -> {
|
||||
return reference.is(structureTag);
|
||||
}).orElse(false);
|
||||
- })) {
|
||||
+ }, levelAccessor)) { // Paper
|
||||
if (this.structureHasPieceAt(pos, structureStart)) {
|
||||
return structureStart;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Sun, 19 Dec 2021 21:11:20 +0100
|
||||
Subject: [PATCH] Fix tripwire state inconsistency
|
||||
|
||||
This patch prevents updating and re-setting the tripwire when being removed in certain conditions
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
|
||||
@@ -0,0 +0,0 @@ public class TripWireBlock extends Block {
|
||||
@Override
|
||||
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) {
|
||||
if (!moved && !state.is(newState.getBlock())) {
|
||||
- this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true));
|
||||
+ this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true), true); // Paper - fix state inconsistency
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class TripWireBlock extends Block {
|
||||
}
|
||||
|
||||
private void updateSource(Level world, BlockPos pos, BlockState state) {
|
||||
+ // Paper start - fix state inconsistency
|
||||
+ this.updateSource(world, pos, state, false);
|
||||
+ }
|
||||
+
|
||||
+ private void updateSource(Level world, BlockPos pos, BlockState state, boolean beingRemoved) {
|
||||
+ // Paper end
|
||||
Direction[] aenumdirection = new Direction[]{Direction.SOUTH, Direction.WEST};
|
||||
int i = aenumdirection.length;
|
||||
int j = 0;
|
||||
@@ -0,0 +0,0 @@ public class TripWireBlock extends Block {
|
||||
|
||||
if (iblockdata1.is((Block) this.hook)) {
|
||||
if (iblockdata1.getValue(TripWireHookBlock.FACING) == enumdirection.getOpposite()) {
|
||||
- this.hook.calculateState(world, blockposition1, iblockdata1, false, true, k, state);
|
||||
+ this.hook.calculateState(world, blockposition1, iblockdata1, false, true, k, state, beingRemoved); // Paper - fix state inconsistency
|
||||
}
|
||||
} else if (iblockdata1.is((Block) this)) {
|
||||
++k;
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
@@ -0,0 +0,0 @@ public class TripWireHookBlock extends Block {
|
||||
}
|
||||
|
||||
public void calculateState(Level world, BlockPos pos, BlockState state, boolean beingRemoved, boolean flag1, int i, @Nullable BlockState iblockdata1) {
|
||||
+ // Paper start - fix tripwire inconsistency
|
||||
+ this.calculateState(world, pos, state, beingRemoved, flag1, i, iblockdata1, false);
|
||||
+ }
|
||||
+
|
||||
+ public void calculateState(Level world, BlockPos pos, BlockState state, boolean beingRemoved, boolean flag1, int i, @Nullable BlockState iblockdata1, boolean tripWireBeingRemoved) {
|
||||
+ // Paper end
|
||||
Direction enumdirection = (Direction) state.getValue(TripWireHookBlock.FACING);
|
||||
boolean flag2 = (Boolean) state.getValue(TripWireHookBlock.ATTACHED);
|
||||
boolean flag3 = (Boolean) state.getValue(TripWireHookBlock.POWERED);
|
||||
@@ -0,0 +0,0 @@ public class TripWireHookBlock extends Block {
|
||||
boolean flag7 = (Boolean) iblockdata2.getValue(TripWireBlock.POWERED);
|
||||
|
||||
flag5 |= flag6 && flag7;
|
||||
+ if (k != i || !tripWireBeingRemoved || !flag6) // Paper - don't update the tripwire again if being removed and not disarmed
|
||||
aiblockdata[k] = iblockdata2;
|
||||
if (k == i) {
|
||||
world.scheduleTick(pos, (Block) this, 10);
|
||||
@@ -1,405 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Wed, 6 Oct 2021 20:50:48 -0700
|
||||
Subject: [PATCH] Fix upstreams block state factories
|
||||
|
||||
Sometimes, blocks are changed and then logic is called before the associated
|
||||
tile entity is removed. When this happens, the factories were relying on the
|
||||
block at the position, not the tile entity. This change prioritizes using the
|
||||
tile entity type to determine the block state factory and falls back on
|
||||
the material type of the block at that location.
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.level.block.entity.BlockEntityType validBlocks
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -0,0 +0,0 @@ public abstract class BlockEntity {
|
||||
// Paper end
|
||||
if (this.level == null) return null;
|
||||
org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
|
||||
- if (block.getType() == org.bukkit.Material.AIR) return null;
|
||||
+ // if (block.getType() == org.bukkit.Material.AIR) return null; // Paper - actually get the tile entity if it still exists
|
||||
org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper
|
||||
if (state instanceof InventoryHolder) return (InventoryHolder) state;
|
||||
return null;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.World;
|
||||
import org.bukkit.block.TileState;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
|
||||
-public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockState implements TileState {
|
||||
+public abstract class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockState implements TileState { // Paper - revert upstream's revert of the block state changes
|
||||
|
||||
private final T tileEntity;
|
||||
private final T snapshot;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BellBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
+import net.minecraft.world.level.block.entity.BlockEntityType; // Paper
|
||||
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.CampfireBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.ChestBlockEntity;
|
||||
@@ -0,0 +0,0 @@ public final class CraftBlockStates {
|
||||
private static final BlockStateFactory<?> DEFAULT_FACTORY = new BlockStateFactory<CraftBlockState>(CraftBlockState.class) {
|
||||
@Override
|
||||
public CraftBlockState createBlockState(World world, BlockPos blockPosition, net.minecraft.world.level.block.state.BlockState blockData, BlockEntity tileEntity) {
|
||||
- // SPIGOT-6754, SPIGOT-6817: Restore previous behaviour for tile entities with removed blocks (loot generation post-destroy)
|
||||
- if (tileEntity != null) {
|
||||
- // block with unhandled TileEntity:
|
||||
- return new CraftBlockEntityState<>(world, tileEntity);
|
||||
- }
|
||||
+ // Paper - revert upstream's revert of the block state changes. Block entities that have already had the block type set to AIR are still valid, upstream decided to ignore them
|
||||
Preconditions.checkState(tileEntity == null, "Unexpected BlockState for %s", CraftMagicNumbers.getMaterial(blockData.getBlock()));
|
||||
return new CraftBlockState(world, blockPosition, blockData);
|
||||
}
|
||||
};
|
||||
+ // Paper start
|
||||
+ private static final Map<BlockEntityType<?>, BlockStateFactory<?>> FACTORIES_BY_BLOCK_ENTITY_TYPE = new HashMap<>();
|
||||
+ private static void register(BlockEntityType<?> type, BlockStateFactory<?> factory) {
|
||||
+ FACTORIES_BY_BLOCK_ENTITY_TYPE.put(type, factory);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
static {
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.ACACIA_SIGN,
|
||||
- Material.ACACIA_WALL_SIGN,
|
||||
- Material.BAMBOO_SIGN,
|
||||
- Material.BAMBOO_WALL_SIGN,
|
||||
- Material.BIRCH_SIGN,
|
||||
- Material.BIRCH_WALL_SIGN,
|
||||
- Material.CRIMSON_SIGN,
|
||||
- Material.CRIMSON_WALL_SIGN,
|
||||
- Material.DARK_OAK_SIGN,
|
||||
- Material.DARK_OAK_WALL_SIGN,
|
||||
- Material.JUNGLE_SIGN,
|
||||
- Material.JUNGLE_WALL_SIGN,
|
||||
- Material.MANGROVE_SIGN,
|
||||
- Material.MANGROVE_WALL_SIGN,
|
||||
- Material.OAK_SIGN,
|
||||
- Material.OAK_WALL_SIGN,
|
||||
- Material.SPRUCE_SIGN,
|
||||
- Material.SPRUCE_WALL_SIGN,
|
||||
- Material.WARPED_SIGN,
|
||||
- Material.WARPED_WALL_SIGN
|
||||
- ), CraftSign.class, CraftSign::new, SignBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.ACACIA_HANGING_SIGN,
|
||||
- Material.ACACIA_WALL_HANGING_SIGN,
|
||||
- Material.BAMBOO_HANGING_SIGN,
|
||||
- Material.BAMBOO_WALL_HANGING_SIGN,
|
||||
- Material.BIRCH_HANGING_SIGN,
|
||||
- Material.BIRCH_WALL_HANGING_SIGN,
|
||||
- Material.CRIMSON_HANGING_SIGN,
|
||||
- Material.CRIMSON_WALL_HANGING_SIGN,
|
||||
- Material.DARK_OAK_HANGING_SIGN,
|
||||
- Material.DARK_OAK_WALL_HANGING_SIGN,
|
||||
- Material.JUNGLE_HANGING_SIGN,
|
||||
- Material.JUNGLE_WALL_HANGING_SIGN,
|
||||
- Material.MANGROVE_HANGING_SIGN,
|
||||
- Material.MANGROVE_WALL_HANGING_SIGN,
|
||||
- Material.OAK_HANGING_SIGN,
|
||||
- Material.OAK_WALL_HANGING_SIGN,
|
||||
- Material.SPRUCE_HANGING_SIGN,
|
||||
- Material.SPRUCE_WALL_HANGING_SIGN,
|
||||
- Material.WARPED_HANGING_SIGN,
|
||||
- Material.WARPED_WALL_HANGING_SIGN
|
||||
- ), CraftHangingSign.class, CraftHangingSign::new, HangingSignBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.CREEPER_HEAD,
|
||||
- Material.CREEPER_WALL_HEAD,
|
||||
- Material.DRAGON_HEAD,
|
||||
- Material.DRAGON_WALL_HEAD,
|
||||
- Material.PIGLIN_HEAD,
|
||||
- Material.PIGLIN_WALL_HEAD,
|
||||
- Material.PLAYER_HEAD,
|
||||
- Material.PLAYER_WALL_HEAD,
|
||||
- Material.SKELETON_SKULL,
|
||||
- Material.SKELETON_WALL_SKULL,
|
||||
- Material.WITHER_SKELETON_SKULL,
|
||||
- Material.WITHER_SKELETON_WALL_SKULL,
|
||||
- Material.ZOMBIE_HEAD,
|
||||
- Material.ZOMBIE_WALL_HEAD
|
||||
- ), CraftSkull.class, CraftSkull::new, SkullBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.COMMAND_BLOCK,
|
||||
- Material.REPEATING_COMMAND_BLOCK,
|
||||
- Material.CHAIN_COMMAND_BLOCK
|
||||
- ), CraftCommandBlock.class, CraftCommandBlock::new, CommandBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.BLACK_BANNER,
|
||||
- Material.BLACK_WALL_BANNER,
|
||||
- Material.BLUE_BANNER,
|
||||
- Material.BLUE_WALL_BANNER,
|
||||
- Material.BROWN_BANNER,
|
||||
- Material.BROWN_WALL_BANNER,
|
||||
- Material.CYAN_BANNER,
|
||||
- Material.CYAN_WALL_BANNER,
|
||||
- Material.GRAY_BANNER,
|
||||
- Material.GRAY_WALL_BANNER,
|
||||
- Material.GREEN_BANNER,
|
||||
- Material.GREEN_WALL_BANNER,
|
||||
- Material.LIGHT_BLUE_BANNER,
|
||||
- Material.LIGHT_BLUE_WALL_BANNER,
|
||||
- Material.LIGHT_GRAY_BANNER,
|
||||
- Material.LIGHT_GRAY_WALL_BANNER,
|
||||
- Material.LIME_BANNER,
|
||||
- Material.LIME_WALL_BANNER,
|
||||
- Material.MAGENTA_BANNER,
|
||||
- Material.MAGENTA_WALL_BANNER,
|
||||
- Material.ORANGE_BANNER,
|
||||
- Material.ORANGE_WALL_BANNER,
|
||||
- Material.PINK_BANNER,
|
||||
- Material.PINK_WALL_BANNER,
|
||||
- Material.PURPLE_BANNER,
|
||||
- Material.PURPLE_WALL_BANNER,
|
||||
- Material.RED_BANNER,
|
||||
- Material.RED_WALL_BANNER,
|
||||
- Material.WHITE_BANNER,
|
||||
- Material.WHITE_WALL_BANNER,
|
||||
- Material.YELLOW_BANNER,
|
||||
- Material.YELLOW_WALL_BANNER
|
||||
- ), CraftBanner.class, CraftBanner::new, BannerBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.SHULKER_BOX,
|
||||
- Material.WHITE_SHULKER_BOX,
|
||||
- Material.ORANGE_SHULKER_BOX,
|
||||
- Material.MAGENTA_SHULKER_BOX,
|
||||
- Material.LIGHT_BLUE_SHULKER_BOX,
|
||||
- Material.YELLOW_SHULKER_BOX,
|
||||
- Material.LIME_SHULKER_BOX,
|
||||
- Material.PINK_SHULKER_BOX,
|
||||
- Material.GRAY_SHULKER_BOX,
|
||||
- Material.LIGHT_GRAY_SHULKER_BOX,
|
||||
- Material.CYAN_SHULKER_BOX,
|
||||
- Material.PURPLE_SHULKER_BOX,
|
||||
- Material.BLUE_SHULKER_BOX,
|
||||
- Material.BROWN_SHULKER_BOX,
|
||||
- Material.GREEN_SHULKER_BOX,
|
||||
- Material.RED_SHULKER_BOX,
|
||||
- Material.BLACK_SHULKER_BOX
|
||||
- ), CraftShulkerBox.class, CraftShulkerBox::new, ShulkerBoxBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.BLACK_BED,
|
||||
- Material.BLUE_BED,
|
||||
- Material.BROWN_BED,
|
||||
- Material.CYAN_BED,
|
||||
- Material.GRAY_BED,
|
||||
- Material.GREEN_BED,
|
||||
- Material.LIGHT_BLUE_BED,
|
||||
- Material.LIGHT_GRAY_BED,
|
||||
- Material.LIME_BED,
|
||||
- Material.MAGENTA_BED,
|
||||
- Material.ORANGE_BED,
|
||||
- Material.PINK_BED,
|
||||
- Material.PURPLE_BED,
|
||||
- Material.RED_BED,
|
||||
- Material.WHITE_BED,
|
||||
- Material.YELLOW_BED
|
||||
- ), CraftBed.class, CraftBed::new, BedBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.BEEHIVE,
|
||||
- Material.BEE_NEST
|
||||
- ), CraftBeehive.class, CraftBeehive::new, BeehiveBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(
|
||||
- Arrays.asList(
|
||||
- Material.CAMPFIRE,
|
||||
- Material.SOUL_CAMPFIRE
|
||||
- ), CraftCampfire.class, CraftCampfire::new, CampfireBlockEntity::new
|
||||
- );
|
||||
-
|
||||
- register(Material.BARREL, CraftBarrel.class, CraftBarrel::new, BarrelBlockEntity::new);
|
||||
- register(Material.BEACON, CraftBeacon.class, CraftBeacon::new, BeaconBlockEntity::new);
|
||||
- register(Material.BELL, CraftBell.class, CraftBell::new, BellBlockEntity::new);
|
||||
- register(Material.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new, BlastFurnaceBlockEntity::new);
|
||||
- register(Material.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new, BrewingStandBlockEntity::new);
|
||||
- register(Material.CHEST, CraftChest.class, CraftChest::new, ChestBlockEntity::new);
|
||||
- register(Material.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new, ChiseledBookShelfBlockEntity::new);
|
||||
- register(Material.COMPARATOR, CraftComparator.class, CraftComparator::new, ComparatorBlockEntity::new);
|
||||
- register(Material.CONDUIT, CraftConduit.class, CraftConduit::new, ConduitBlockEntity::new);
|
||||
- register(Material.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new, DaylightDetectorBlockEntity::new);
|
||||
- register(Material.DISPENSER, CraftDispenser.class, CraftDispenser::new, DispenserBlockEntity::new);
|
||||
- register(Material.DROPPER, CraftDropper.class, CraftDropper::new, DropperBlockEntity::new);
|
||||
- register(Material.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new, EnchantmentTableBlockEntity::new);
|
||||
- register(Material.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new, EnderChestBlockEntity::new);
|
||||
- register(Material.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new, TheEndGatewayBlockEntity::new);
|
||||
- register(Material.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new, TheEndPortalBlockEntity::new);
|
||||
- register(Material.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new, FurnaceBlockEntity::new);
|
||||
- register(Material.HOPPER, CraftHopper.class, CraftHopper::new, HopperBlockEntity::new);
|
||||
- register(Material.JIGSAW, CraftJigsaw.class, CraftJigsaw::new, JigsawBlockEntity::new);
|
||||
- register(Material.JUKEBOX, CraftJukebox.class, CraftJukebox::new, JukeboxBlockEntity::new);
|
||||
- register(Material.LECTERN, CraftLectern.class, CraftLectern::new, LecternBlockEntity::new);
|
||||
- register(Material.MOVING_PISTON, CraftMovingPiston.class, CraftMovingPiston::new, PistonMovingBlockEntity::new);
|
||||
- register(Material.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new, SculkCatalystBlockEntity::new);
|
||||
- register(Material.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new, SculkSensorBlockEntity::new);
|
||||
- register(Material.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new, SculkShriekerBlockEntity::new);
|
||||
- register(Material.SMOKER, CraftSmoker.class, CraftSmoker::new, SmokerBlockEntity::new);
|
||||
- register(Material.SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new, SpawnerBlockEntity::new);
|
||||
- register(Material.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new, StructureBlockEntity::new);
|
||||
- register(Material.TRAPPED_CHEST, CraftChest.class, CraftChest::new, TrappedChestBlockEntity::new);
|
||||
+ // Paper start - simplify
|
||||
+ register(BlockEntityType.SIGN, CraftSign.class, CraftSign::new);
|
||||
+ register(BlockEntityType.HANGING_SIGN, CraftHangingSign.class, CraftHangingSign::new);
|
||||
+ register(BlockEntityType.SKULL, CraftSkull.class, CraftSkull::new);
|
||||
+ register(BlockEntityType.COMMAND_BLOCK, CraftCommandBlock.class, CraftCommandBlock::new);
|
||||
+ register(BlockEntityType.BANNER, CraftBanner.class, CraftBanner::new);
|
||||
+ register(BlockEntityType.SHULKER_BOX, CraftShulkerBox.class, CraftShulkerBox::new);
|
||||
+ register(BlockEntityType.BED, CraftBed.class, CraftBed::new);
|
||||
+ register(BlockEntityType.BEEHIVE, CraftBeehive.class, CraftBeehive::new);
|
||||
+ register(BlockEntityType.CAMPFIRE, CraftCampfire.class, CraftCampfire::new);
|
||||
+ register(BlockEntityType.BARREL, CraftBarrel.class, CraftBarrel::new);
|
||||
+ register(BlockEntityType.BEACON, CraftBeacon.class, CraftBeacon::new);
|
||||
+ register(BlockEntityType.BELL, CraftBell.class, CraftBell::new);
|
||||
+ register(BlockEntityType.BLAST_FURNACE, CraftBlastFurnace.class, CraftBlastFurnace::new);
|
||||
+ register(BlockEntityType.BREWING_STAND, CraftBrewingStand.class, CraftBrewingStand::new);
|
||||
+ register(BlockEntityType.CHEST, CraftChest.class, CraftChest::new);
|
||||
+ register(BlockEntityType.CHISELED_BOOKSHELF, CraftChiseledBookshelf.class, CraftChiseledBookshelf::new);
|
||||
+ register(BlockEntityType.COMPARATOR, CraftComparator.class, CraftComparator::new);
|
||||
+ register(BlockEntityType.CONDUIT, CraftConduit.class, CraftConduit::new);
|
||||
+ register(BlockEntityType.DAYLIGHT_DETECTOR, CraftDaylightDetector.class, CraftDaylightDetector::new);
|
||||
+ register(BlockEntityType.DISPENSER, CraftDispenser.class, CraftDispenser::new);
|
||||
+ register(BlockEntityType.DROPPER, CraftDropper.class, CraftDropper::new);
|
||||
+ register(BlockEntityType.ENCHANTING_TABLE, CraftEnchantingTable.class, CraftEnchantingTable::new);
|
||||
+ register(BlockEntityType.ENDER_CHEST, CraftEnderChest.class, CraftEnderChest::new);
|
||||
+ register(BlockEntityType.END_GATEWAY, CraftEndGateway.class, CraftEndGateway::new);
|
||||
+ register(BlockEntityType.END_PORTAL, CraftEndPortal.class, CraftEndPortal::new);
|
||||
+ register(BlockEntityType.FURNACE, CraftFurnaceFurnace.class, CraftFurnaceFurnace::new);
|
||||
+ register(BlockEntityType.HOPPER, CraftHopper.class, CraftHopper::new);
|
||||
+ register(BlockEntityType.JIGSAW, CraftJigsaw.class, CraftJigsaw::new);
|
||||
+ register(BlockEntityType.JUKEBOX, CraftJukebox.class, CraftJukebox::new);
|
||||
+ register(BlockEntityType.LECTERN, CraftLectern.class, CraftLectern::new);
|
||||
+ register(BlockEntityType.PISTON, CraftMovingPiston.class, CraftMovingPiston::new);
|
||||
+ register(BlockEntityType.SCULK_CATALYST, CraftSculkCatalyst.class, CraftSculkCatalyst::new);
|
||||
+ register(BlockEntityType.SCULK_SENSOR, CraftSculkSensor.class, CraftSculkSensor::new);
|
||||
+ register(BlockEntityType.SCULK_SHRIEKER, CraftSculkShrieker.class, CraftSculkShrieker::new);
|
||||
+ register(BlockEntityType.SMOKER, CraftSmoker.class, CraftSmoker::new);
|
||||
+ register(BlockEntityType.MOB_SPAWNER, CraftCreatureSpawner.class, CraftCreatureSpawner::new);
|
||||
+ register(BlockEntityType.STRUCTURE_BLOCK, CraftStructureBlock.class, CraftStructureBlock::new);
|
||||
+ register(BlockEntityType.TRAPPED_CHEST, CraftChest.class, CraftChest::new);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
private static void register(Material blockType, BlockStateFactory<?> factory) {
|
||||
@@ -0,0 +0,0 @@ public final class CraftBlockStates {
|
||||
}
|
||||
|
||||
private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
|
||||
- Material blockType,
|
||||
- Class<B> blockStateType,
|
||||
- BiFunction<World, T, B> blockStateConstructor,
|
||||
- BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor
|
||||
- ) {
|
||||
- CraftBlockStates.register(Collections.singletonList(blockType), blockStateType, blockStateConstructor, tileEntityConstructor);
|
||||
- }
|
||||
-
|
||||
- private static <T extends BlockEntity, B extends CraftBlockEntityState<T>> void register(
|
||||
- List<Material> blockTypes,
|
||||
+ net.minecraft.world.level.block.entity.BlockEntityType<? extends T> blockEntityType, // Paper
|
||||
Class<B> blockStateType,
|
||||
- BiFunction<World, T, B> blockStateConstructor,
|
||||
- BiFunction<BlockPos, net.minecraft.world.level.block.state.BlockState, T> tileEntityConstructor
|
||||
+ BiFunction<World, T, B> blockStateConstructor // Paper
|
||||
) {
|
||||
- BlockStateFactory<B> factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, tileEntityConstructor);
|
||||
- for (Material blockType : blockTypes) {
|
||||
- CraftBlockStates.register(blockType, factory);
|
||||
+ // Paper start
|
||||
+ BlockStateFactory<B> factory = new BlockEntityStateFactory<>(blockStateType, blockStateConstructor, blockEntityType::create);
|
||||
+ for (net.minecraft.world.level.block.Block block : blockEntityType.validBlocks) {
|
||||
+ CraftBlockStates.register(CraftMagicNumbers.getMaterial(block), factory);
|
||||
}
|
||||
+ CraftBlockStates.register(blockEntityType, factory);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
private static BlockStateFactory<?> getFactory(Material material) {
|
||||
return CraftBlockStates.FACTORIES.getOrDefault(material, DEFAULT_FACTORY);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static BlockStateFactory<?> getFactory(Material material, BlockEntityType<?> type) {
|
||||
+ if (type != null) {
|
||||
+ return CraftBlockStates.FACTORIES_BY_BLOCK_ENTITY_TYPE.getOrDefault(type, getFactory(material));
|
||||
+ } else {
|
||||
+ return getFactory(material);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static Class<? extends CraftBlockState> getBlockStateType(Material material) {
|
||||
Preconditions.checkNotNull(material, "material is null");
|
||||
return CraftBlockStates.getFactory(material).blockStateType;
|
||||
@@ -0,0 +0,0 @@ public final class CraftBlockStates {
|
||||
return null;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static Class<? extends CraftBlockState> getBlockStateType(BlockEntityType<?> blockEntityType) {
|
||||
+ Preconditions.checkNotNull(blockEntityType, "blockEntityType is null");
|
||||
+ return CraftBlockStates.getFactory(null, blockEntityType).blockStateType;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static BlockState getBlockState(Block block) {
|
||||
// Paper start
|
||||
return CraftBlockStates.getBlockState(block, true);
|
||||
@@ -0,0 +0,0 @@ public final class CraftBlockStates {
|
||||
if (world != null && tileEntity == null && CraftBlockStates.isTileEntityOptional(material)) {
|
||||
factory = CraftBlockStates.DEFAULT_FACTORY;
|
||||
} else {
|
||||
- factory = CraftBlockStates.getFactory(material);
|
||||
+ factory = CraftBlockStates.getFactory(material, tileEntity != null ? tileEntity.getType() : null); // Paper
|
||||
}
|
||||
return factory.createBlockState(world, blockPosition, blockData, tileEntity);
|
||||
}
|
||||
diff --git a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
|
||||
+++ b/src/test/java/org/bukkit/craftbukkit/block/BlockStateTest.java
|
||||
@@ -0,0 +0,0 @@ public class BlockStateTest extends AbstractTestingBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ @Test
|
||||
+ public void testBlockEntityTypes() {
|
||||
+ for (var blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) {
|
||||
+ org.junit.Assert.assertNotNull(CraftBlockStates.getBlockStateType(blockEntityType));
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
@@ -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
|
||||
public int getExperienceReward() {
|
||||
+ 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.getExperienceReward();
|
||||
+ // Paper start - only change the XP reward for the calculations in the super method
|
||||
+ int reward = super.getExperienceReward();
|
||||
+ this.xpReward = previousReward;
|
||||
+ return reward;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -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 {
|
||||
|
||||
// Paper start - move vehicle into method so it can be called above - short circuit around that code
|
||||
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(), null, null, true, false)
|
||||
+ );
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
private void mountSavedVehicle(ServerPlayer player, ServerLevel worldserver1, CompoundTag nbttagcompound) {
|
||||
// Paper end
|
||||
@@ -1,39 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sat, 4 Dec 2021 17:04:47 -0800
|
||||
Subject: [PATCH] Forward CraftEntity in teleport command
|
||||
|
||||
|
||||
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 Nameable, EntityAccess, CommandSource {
|
||||
}
|
||||
|
||||
public void restoreFrom(Entity original) {
|
||||
+ // Paper start
|
||||
+ CraftEntity bukkitEntity = original.bukkitEntity;
|
||||
+ if (bukkitEntity != null) {
|
||||
+ bukkitEntity.setHandle(this);
|
||||
+ this.bukkitEntity = bukkitEntity;
|
||||
+ }
|
||||
+ // Paper end
|
||||
CompoundTag nbttagcompound = original.saveWithoutId(new CompoundTag());
|
||||
|
||||
nbttagcompound.remove("Dimension");
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
if (worldserver.getTypeKey() == LevelStem.END) { // CraftBukkit
|
||||
ServerLevel.makeObsidianPlatform(worldserver, this); // CraftBukkit
|
||||
}
|
||||
- // CraftBukkit start - Forward the CraftEntity to the new entity
|
||||
- this.getBukkitEntity().setHandle(entity);
|
||||
- entity.bukkitEntity = this.getBukkitEntity();
|
||||
- // CraftBukkit end
|
||||
+ // // CraftBukkit start - Forward the CraftEntity to the new entity // Paper - moved to Entity#restoreFrom
|
||||
+ // this.getBukkitEntity().setHandle(entity);
|
||||
+ // entity.bukkitEntity = this.getBukkitEntity();
|
||||
+ // // CraftBukkit end
|
||||
}
|
||||
|
||||
this.removeAfterChangingDimensions();
|
||||
@@ -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 Nameable, EntityAccess, CommandSource {
|
||||
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 Nameable, EntityAccess, CommandSource {
|
||||
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 Nameable, EntityAccess, CommandSource {
|
||||
if (fromNetherPortal) {
|
||||
nbt.putBoolean("Paper.FromNetherPortal", true);
|
||||
}
|
||||
+ if (freezeLocked) {
|
||||
+ nbt.putBoolean("Paper.FreezeLock", true);
|
||||
+ }
|
||||
// Paper end
|
||||
return nbt;
|
||||
} catch (Throwable throwable) {
|
||||
@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
|
||||
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 {
|
||||
boolean flag1 = this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES);
|
||||
int i;
|
||||
|
||||
- if (!this.level.isClientSide && !this.isDeadOrDying()) {
|
||||
+ if (!this.level.isClientSide && !this.isDeadOrDying() && !freezeLocked) { // Paper - Freeze Tick Lock API
|
||||
i = this.getTicksFrozen();
|
||||
if (this.isInPowderSnow && this.canFreeze()) {
|
||||
this.setTicksFrozen(Math.min(this.getTicksRequiredToFreeze(), i + 1));
|
||||
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.discard();
|
||||
@@ -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<? extends net.minecraft.world.item.crafting.Recipe<?>> 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() 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
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 31 Mar 2022 05:18:28 -0700
|
||||
Subject: [PATCH] Guard against invalid entity positions
|
||||
|
||||
Anything not finite should be blocked and logged
|
||||
|
||||
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 Nameable, EntityAccess, CommandSource {
|
||||
return this.getZ((2.0D * this.random.nextDouble() - 1.0D) * widthScale);
|
||||
}
|
||||
|
||||
+ // Paper start - block invalid positions
|
||||
+ public static boolean checkPosition(Entity entity, double newX, double newY, double newZ) {
|
||||
+ if (Double.isFinite(newX) && Double.isFinite(newY) && Double.isFinite(newZ)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ String entityInfo = null;
|
||||
+ try {
|
||||
+ entityInfo = entity.toString();
|
||||
+ } catch (Exception ex) {
|
||||
+ entityInfo = "[Entity info unavailable] ";
|
||||
+ }
|
||||
+ LOGGER.error("New entity position is invalid! Tried to set invalid position (" + newX + "," + newY + "," + newZ + ") for entity " + entity.getClass().getName() + " located at " + entity.position + ", entity info: " + entityInfo, new Throwable());
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end - block invalid positions
|
||||
+
|
||||
public final void setPosRaw(double x, double y, double z) {
|
||||
// Paper start
|
||||
this.setPosRaw(x, y, z, false);
|
||||
}
|
||||
public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
|
||||
+ // Paper start - block invalid positions
|
||||
+ if (!checkPosition(this, x, y, z)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - block invalid positions
|
||||
// Paper end
|
||||
// Paper start - rewrite chunk system
|
||||
if (this.updatingSectionStatus) {
|
||||
@@ -1,118 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Noah van der Aa <ndvdaa@gmail.com>
|
||||
Date: Tue, 3 Aug 2021 17:28:27 +0200
|
||||
Subject: [PATCH] Hide unnecessary itemmeta from clients
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -0,0 +0,0 @@ public class ServerEntity {
|
||||
if (!itemstack.isEmpty()) {
|
||||
// Paper start - prevent oversized data
|
||||
final ItemStack sanitized = LivingEntity.sanitizeItemStack(itemstack.copy(), false);
|
||||
- list.add(Pair.of(enumitemslot, sanitized));
|
||||
+ list.add(Pair.of(enumitemslot, ((LivingEntity) this.entity).stripMeta(sanitized, false))); // Paper - remove unnecessary item meta
|
||||
// Paper end
|
||||
}
|
||||
}
|
||||
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 implements ServerPlayerConnection, Tic
|
||||
// Refresh the current entity metadata
|
||||
entity.getEntityData().refresh(player);
|
||||
// SPIGOT-7136 - Allays
|
||||
- if (entity instanceof Allay) {
|
||||
- ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, ((LivingEntity) entity).getItemBySlot(slot).copy())).collect(Collectors.toList())));
|
||||
+ if (entity instanceof Allay allay) { // Paper
|
||||
+ ServerGamePacketListenerImpl.this.send(new ClientboundSetEquipmentPacket(entity.getId(), Arrays.stream(net.minecraft.world.entity.EquipmentSlot.values()).map((slot) -> Pair.of(slot, allay.stripMeta(allay.getItemBySlot(slot), true))).collect(Collectors.toList()))); // Paper - remove unnecessary item meta
|
||||
player.containerMenu.sendAllDataToRemote();
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
||||
// Paper start - prevent oversized data
|
||||
ItemStack toSend = sanitizeItemStack(itemstack1, true);
|
||||
- list.add(Pair.of(enumitemslot, toSend));
|
||||
+ list.add(Pair.of(enumitemslot, stripMeta(toSend, toSend == itemstack1))); // Paper - hide unnecessary item meta
|
||||
// Paper end
|
||||
switch (enumitemslot.getType()) {
|
||||
case HAND:
|
||||
@@ -0,0 +0,0 @@ public abstract class LivingEntity extends Entity {
|
||||
((ServerLevel) this.level).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list));
|
||||
}
|
||||
|
||||
+ // Paper start - hide unnecessary item meta
|
||||
+ public ItemStack stripMeta(final ItemStack itemStack, final boolean copyItemStack) {
|
||||
+ if (itemStack.isEmpty() || (!itemStack.hasTag() && itemStack.getCount() < 2)) {
|
||||
+ return itemStack;
|
||||
+ }
|
||||
+
|
||||
+ final ItemStack copy = copyItemStack ? itemStack.copy() : itemStack;
|
||||
+ if (level.paperConfig().anticheat.obfuscation.items.hideDurability) {
|
||||
+ // Only show damage values for elytra's, since they show a different texture when broken.
|
||||
+ if (!copy.is(Items.ELYTRA) || copy.getDamageValue() < copy.getMaxDamage() - 1) {
|
||||
+ copy.setDamageValue(0);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final CompoundTag tag = copy.getTag();
|
||||
+ if (level.paperConfig().anticheat.obfuscation.items.hideItemmeta) {
|
||||
+ // Some resource packs show different textures when there is more than one item. Since this shouldn't provide a big advantage,
|
||||
+ // we'll tell the client if there's one or (more than) two items.
|
||||
+ copy.setCount(copy.getCount() > 1 ? 2 : 1);
|
||||
+ // We can't just strip out display, leather helmets still use the display.color tag.
|
||||
+ if (tag != null) {
|
||||
+ if (tag.get("display") instanceof CompoundTag displayTag) {
|
||||
+ displayTag.remove("Lore");
|
||||
+ displayTag.remove("Name");
|
||||
+ }
|
||||
+
|
||||
+ if (tag.get("Enchantments") instanceof ListTag enchantmentsTag && !enchantmentsTag.isEmpty()) {
|
||||
+ // The client still renders items with the enchantment glow if the enchantments tag contains at least one (empty) child.
|
||||
+ ListTag enchantments = new ListTag();
|
||||
+ CompoundTag fakeEnchantment = new CompoundTag();
|
||||
+ // Soul speed boots generate client side particles.
|
||||
+ if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.SOUL_SPEED, itemStack) > 0) {
|
||||
+ fakeEnchantment.putString("id", org.bukkit.enchantments.Enchantment.SOUL_SPEED.getKey().asString());
|
||||
+ fakeEnchantment.putInt("lvl", 1);
|
||||
+ }
|
||||
+ enchantments.add(fakeEnchantment);
|
||||
+ tag.put("Enchantments", enchantments);
|
||||
+ }
|
||||
+ tag.remove("AttributeModifiers");
|
||||
+
|
||||
+ // Books
|
||||
+ tag.remove("author");
|
||||
+ tag.remove("filtered_title");
|
||||
+ tag.remove("pages");
|
||||
+ tag.remove("filtered_pages");
|
||||
+ tag.remove("title");
|
||||
+ tag.remove("generation");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (level.paperConfig().anticheat.obfuscation.items.hideItemmetaWithVisualEffects && tag != null) {
|
||||
+ // Lodestone compasses
|
||||
+ tag.remove("LodestonePos");
|
||||
+ if (tag.contains("LodestoneDimension")) {
|
||||
+ // The client shows the glint if either the position or the dimension is present, so we just wipe
|
||||
+ // the position and fake the dimension
|
||||
+ tag.putString("LodestoneDimension", "paper:paper");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return copy;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
// Paper start - prevent oversized data
|
||||
public static ItemStack sanitizeItemStack(final ItemStack itemStack, final boolean copyItemStack) {
|
||||
if (itemStack.isEmpty() || !itemStack.hasTag()) {
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +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 {
|
||||
}
|
||||
|
||||
// Paper start
|
||||
+ @Override
|
||||
+ public ItemStack enchantWithLevels(ItemStack itemStack, int levels, boolean allowTreasure, java.util.Random random) {
|
||||
+ Validate.notNull(itemStack, "Argument 'itemStack' must not be null");
|
||||
+ Validate.isTrue(itemStack.getType() != Material.AIR, "Argument 'itemStack' must not be of type AIR");
|
||||
+ Validate.isTrue(itemStack.getAmount() > 0, "Argument 'itemStack' amount must be greater than 0");
|
||||
+ Validate.isTrue(levels > 0 && levels <= 30, "Argument 'levels' must be in range [1, 30] (attempted " + levels + ")");
|
||||
+ Validate.notNull(random, "Argument 'random' must not be null");
|
||||
+ final net.minecraft.world.item.ItemStack internalStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
+ if (internalStack.getTag() != null) {
|
||||
+ internalStack.getTag().remove(net.minecraft.world.item.ItemStack.TAG_ENCH);
|
||||
+ }
|
||||
+ final net.minecraft.world.item.ItemStack enchanted = net.minecraft.world.item.enchantment.EnchantmentHelper.enchantItem(new org.bukkit.craftbukkit.util.RandomSourceWrapper(random), internalStack, levels, allowTreasure);
|
||||
+ return CraftItemStack.asCraftMirror(enchanted);
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public net.kyori.adventure.text.event.HoverEvent<net.kyori.adventure.text.event.HoverEvent.ShowItem> asHoverEvent(final ItemStack item, final java.util.function.UnaryOperator<net.kyori.adventure.text.event.HoverEvent.ShowItem> op) {
|
||||
final net.minecraft.nbt.CompoundTag tag = CraftItemStack.asNMSCopy(item).getTag();
|
||||
@@ -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 CraftBlock.biomeBaseToBiome(this.getHandle().registryAccess().registryOrThrow(Registries.BIOME), this.getHandle().getNoiseBiome(x >> 2, y >> 2, z >> 2));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public Biome getComputedBiome(int x, int y, int z) {
|
||||
+ return CraftBlock.biomeBaseToBiome(this.getHandle().registryAccess().registryOrThrow(Registries.BIOME), 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);
|
||||
@@ -1,98 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Mon, 31 Jan 2022 11:21:50 +0100
|
||||
Subject: [PATCH] Implement regenerateChunk
|
||||
|
||||
Co-authored-by: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
|
||||
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 @@ import org.bukkit.util.Vector;
|
||||
public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
public static final int CUSTOM_DIMENSION_OFFSET = 10;
|
||||
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||
+ private static final ChunkStatus[] REGEN_CHUNK_STATUSES = {ChunkStatus.BIOMES, ChunkStatus.NOISE, ChunkStatus.SURFACE, ChunkStatus.CARVERS, ChunkStatus.LIQUID_CARVERS, ChunkStatus.FEATURES}; // Paper - implement regenerate chunk method
|
||||
|
||||
private final ServerLevel world;
|
||||
private WorldBorder worldBorder;
|
||||
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
@Override
|
||||
public boolean regenerateChunk(int x, int z) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("chunk regenerate"); // Spigot
|
||||
- throw new UnsupportedOperationException("Not supported in this Minecraft version! Unless you can fix it, this is not a bug :)");
|
||||
- /*
|
||||
- if (!unloadChunk0(x, z, false)) {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- final long chunkKey = ChunkCoordIntPair.pair(x, z);
|
||||
- world.getChunkProvider().unloadQueue.remove(chunkKey);
|
||||
+ // Paper start - implement regenerateChunk method
|
||||
+ final ServerLevel serverLevel = this.world;
|
||||
+ final net.minecraft.server.level.ServerChunkCache serverChunkCache = serverLevel.getChunkSource();
|
||||
+ final ChunkPos chunkPos = new ChunkPos(x, z);
|
||||
+ final net.minecraft.world.level.chunk.LevelChunk levelChunk = serverChunkCache.getChunk(chunkPos.x, chunkPos.z, true);
|
||||
+ for (final BlockPos blockPos : BlockPos.betweenClosed(chunkPos.getMinBlockX(), serverLevel.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), serverLevel.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ())) {
|
||||
+ levelChunk.removeBlockEntity(blockPos);
|
||||
+ serverLevel.setBlock(blockPos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), 16);
|
||||
+ }
|
||||
+
|
||||
+ for (final ChunkStatus chunkStatus : REGEN_CHUNK_STATUSES) {
|
||||
+ final List<ChunkAccess> list = new ArrayList<>();
|
||||
+ final int range = Math.max(1, chunkStatus.getRange());
|
||||
+ for (int chunkX = chunkPos.z - range; chunkX <= chunkPos.z + range; chunkX++) {
|
||||
+ for (int chunkZ = chunkPos.x - range; chunkZ <= chunkPos.x + range; chunkZ++) {
|
||||
+ ChunkAccess chunkAccess = serverChunkCache.getChunk(chunkZ, chunkX, chunkStatus.getParent(), true);
|
||||
+ if (chunkAccess instanceof ImposterProtoChunk accessProtoChunk) {
|
||||
+ chunkAccess = new ImposterProtoChunk(accessProtoChunk.getWrapped(), true);
|
||||
+ } else if (chunkAccess instanceof net.minecraft.world.level.chunk.LevelChunk accessLevelChunk) {
|
||||
+ chunkAccess = new ImposterProtoChunk(accessLevelChunk, true);
|
||||
+ }
|
||||
+ list.add(chunkAccess);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- net.minecraft.server.Chunk chunk = world.getChunkProvider().generateChunk(x, z);
|
||||
- PlayerChunk playerChunk = world.getPlayerChunkMap().getChunk(x, z);
|
||||
- if (playerChunk != null) {
|
||||
- playerChunk.chunk = chunk;
|
||||
+ final java.util.concurrent.CompletableFuture<com.mojang.datafixers.util.Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = chunkStatus.generate(
|
||||
+ Runnable::run,
|
||||
+ serverLevel,
|
||||
+ serverChunkCache.getGenerator(),
|
||||
+ serverLevel.getStructureManager(),
|
||||
+ serverChunkCache.getLightEngine(),
|
||||
+ chunk -> {
|
||||
+ throw new UnsupportedOperationException("Not creating full chunks here");
|
||||
+ },
|
||||
+ list,
|
||||
+ true
|
||||
+ );
|
||||
+ serverChunkCache.mainThreadProcessor.managedBlock(future::isDone);
|
||||
+ if (chunkStatus == ChunkStatus.NOISE) {
|
||||
+ future.join().left().ifPresent(chunk -> net.minecraft.world.level.levelgen.Heightmap.primeHeightmaps(chunk, ChunkStatus.POST_FEATURES));
|
||||
+ }
|
||||
}
|
||||
|
||||
- if (chunk != null) {
|
||||
- refreshChunk(x, z);
|
||||
+ for (final BlockPos blockPos : BlockPos.betweenClosed(chunkPos.getMinBlockX(), serverLevel.getMinBuildHeight(), chunkPos.getMinBlockZ(), chunkPos.getMaxBlockX(), serverLevel.getMaxBuildHeight() - 1, chunkPos.getMaxBlockZ())) {
|
||||
+ serverChunkCache.blockChanged(blockPos);
|
||||
}
|
||||
|
||||
- return chunk != null;
|
||||
- */
|
||||
+ final Set<ChunkPos> chunksToRelight = new HashSet<>(9);
|
||||
+ for (int chunkX = chunkPos.x - 1; chunkX <= chunkPos.x + 1 ; chunkX++) {
|
||||
+ for (int chunkZ = chunkPos.z - 1; chunkZ <= chunkPos.z + 1 ; chunkZ++) {
|
||||
+ chunksToRelight.add(new ChunkPos(chunkX, chunkZ));
|
||||
+ }
|
||||
+ }
|
||||
+ serverChunkCache.getLightEngine().relight(chunksToRelight, pos -> {}, relit -> {});
|
||||
+ return true;
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,84 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Thu, 4 Nov 2021 12:31:24 -0700
|
||||
Subject: [PATCH] Improve scoreboard entries
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java
|
||||
@@ -0,0 +0,0 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective
|
||||
return new CraftScore(this, entry);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public Score getScoreFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return getScore(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void unregister() throws IllegalStateException {
|
||||
CraftScoreboard scoreboard = this.checkState();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboard.java
|
||||
@@ -0,0 +0,0 @@ public final class CraftScoreboard implements org.bukkit.scoreboard.Scoreboard {
|
||||
public Scoreboard getHandle() {
|
||||
return this.board;
|
||||
}
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public ImmutableSet<Score> getScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.getScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void resetScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ this.resetScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public Team getEntityTeam(org.bukkit.entity.Entity entity) throws IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.getEntryTeam(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void addEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ this.addEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean removeEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.removeEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasEntity(org.bukkit.entity.Entity entity) throws IllegalStateException, IllegalArgumentException {
|
||||
+ Validate.notNull(entity, "Entity cannot be null");
|
||||
+ return this.hasEntry(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public static Visibility bukkitToNotch(NameTagVisibility visibility) {
|
||||
switch (visibility) {
|
||||
case ALWAYS:
|
||||
@@ -1,42 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Mon, 17 Jan 2022 19:47:19 +0100
|
||||
Subject: [PATCH] Kick on main for illegal chat
|
||||
|
||||
Makes the PlayerKickEvent fire on the main thread for
|
||||
illegal characters or chat out-of-order errors.
|
||||
|
||||
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 implements ServerPlayerConnection, Tic
|
||||
}
|
||||
// CraftBukkit end
|
||||
if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.message())) {
|
||||
+ this.server.scheduleOnMain(() -> { // Paper - push to main for event firing
|
||||
this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add cause
|
||||
+ }); // Paper - push to main for event firing
|
||||
} else {
|
||||
Optional<LastSeenMessages> optional = this.tryHandleChat(packet.message(), packet.timeStamp(), packet.lastSeenMessages());
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
@Override
|
||||
public void handleChatCommand(ServerboundChatCommandPacket packet) {
|
||||
if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.command())) {
|
||||
+ this.server.scheduleOnMain(() -> { // Paper - push to main for event firing
|
||||
this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper
|
||||
+ }); // Paper - push to main for event firing
|
||||
} else {
|
||||
Optional<LastSeenMessages> optional = this.tryHandleChat(packet.command(), packet.timeStamp(), packet.lastSeenMessages());
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
private Optional<LastSeenMessages> tryHandleChat(String message, Instant timestamp, LastSeenMessages.Update acknowledgment) {
|
||||
if (!this.updateChatOrder(timestamp)) {
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} sent out-of-order chat: '{}'", this.player.getName().getString(), message);
|
||||
+ this.server.scheduleOnMain(() -> { // Paper - push to main
|
||||
this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"), org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event ca
|
||||
+ }); // Paper - push to main
|
||||
return Optional.empty();
|
||||
} else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales
|
||||
this.send(new ClientboundSystemChatPacket(PaperAdventure.asAdventure(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED)), false)); // Paper - Adventure
|
||||
@@ -1,20 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Tue, 21 Dec 2021 22:13:26 -0800
|
||||
Subject: [PATCH] Load effect amplifiers greater than 127 correctly
|
||||
|
||||
MOJIRA: MC-118857
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
|
||||
+++ b/src/main/java/net/minecraft/world/effect/MobEffectInstance.java
|
||||
@@ -0,0 +0,0 @@ public class MobEffectInstance implements Comparable<MobEffectInstance> {
|
||||
}
|
||||
|
||||
private static MobEffectInstance loadSpecifiedEffect(MobEffect type, CompoundTag nbt) {
|
||||
- int i = nbt.getByte("Amplifier");
|
||||
+ int i = Byte.toUnsignedInt(nbt.getByte("Amplifier")); // Paper - correctly load amplifiers > 127
|
||||
int j = nbt.getInt("Duration");
|
||||
boolean bl = nbt.getBoolean("Ambient");
|
||||
boolean bl2 = true;
|
||||
@@ -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");
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 20 Sep 2020 16:10:49 -0700
|
||||
Subject: [PATCH] Make sure inlined getChunkAt has inlined logic for loaded
|
||||
chunks
|
||||
|
||||
Tux did some profiling some time ago and showed that the
|
||||
previous getChunkAt method which had inlined logic for loaded
|
||||
chunks did get inlined, but the standard CPS.getChunkAt
|
||||
method was not inlined.
|
||||
|
||||
Paper recently reverted this optimisation, so it's been reintroduced
|
||||
here.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
|
||||
@Override
|
||||
public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline
|
||||
+ // Paper start - make sure loaded chunks get the inlined variant of this function
|
||||
+ net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource();
|
||||
+ if (cps.mainThread == Thread.currentThread()) {
|
||||
+ LevelChunk ifLoaded = cps.getChunkAtIfLoadedMainThread(chunkX, chunkZ);
|
||||
+ if (ifLoaded != null) {
|
||||
+ return ifLoaded;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - make sure loaded chunks get the inlined variant of this function
|
||||
return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
public static boolean checkSurfaceWaterAnimalSpawnRules(EntityType<? extends WaterAnimal> type, LevelAccessor world, MobSpawnType reason, BlockPos pos, RandomSource random) {
|
||||
int i = world.getSeaLevel();
|
||||
int j = i - 13;
|
||||
+ // Paper start
|
||||
+ i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i);
|
||||
+ j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j);
|
||||
+ // Paper end
|
||||
return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Mon, 6 Jul 2020 22:48:48 -0700
|
||||
Subject: [PATCH] Manually inline methods in BlockPosition
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/core/BlockPos.java
|
||||
+++ b/src/main/java/net/minecraft/core/BlockPos.java
|
||||
@@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
|
||||
}
|
||||
|
||||
public BlockPos.MutableBlockPos set(int x, int y, int z) {
|
||||
- this.setX(x);
|
||||
- this.setY(y);
|
||||
- this.setZ(z);
|
||||
+ this.x = x; // Paper - force inline
|
||||
+ this.y = y; // Paper - force inline
|
||||
+ this.z = z; // Paper - force inline
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
|
||||
// Paper start - comment out useless overrides @Override - TODO figure out why this is suddenly important to keep
|
||||
@Override
|
||||
public BlockPos.MutableBlockPos setX(int i) {
|
||||
- super.setX(i);
|
||||
+ this.x = i; // Paper
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos.MutableBlockPos setY(int i) {
|
||||
- super.setY(i);
|
||||
+ this.y = i; // Paper
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos.MutableBlockPos setZ(int i) {
|
||||
- super.setZ(i);
|
||||
+ this.z = i; // Paper
|
||||
return this;
|
||||
}
|
||||
// Paper end
|
||||
diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/core/Vec3i.java
|
||||
+++ b/src/main/java/net/minecraft/core/Vec3i.java
|
||||
@@ -0,0 +0,0 @@ public class Vec3i implements Comparable<Vec3i> {
|
||||
return IntStream.of(vec.getX(), vec.getY(), vec.getZ());
|
||||
});
|
||||
public static final Vec3i ZERO = new Vec3i(0, 0, 0);
|
||||
- private int x;
|
||||
- private int y;
|
||||
- private int z;
|
||||
+ protected int x; // Paper - protected
|
||||
+ protected int y; // Paper - protected
|
||||
+ protected int z; // Paper - protected
|
||||
|
||||
private static Function<Vec3i, DataResult<Vec3i>> checkOffsetAxes(int maxAbsValue) {
|
||||
return (vec) -> {
|
||||
@@ -1,91 +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
|
||||
|
||||
|
||||
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 {
|
||||
public Color getColor() {
|
||||
return Color.fromRGB(this.handle.getColor());
|
||||
}
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public org.bukkit.NamespacedKey getKey() {
|
||||
+ return org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(net.minecraft.core.registries.BuiltInRegistries.MOB_EFFECT.getKey(this.handle));
|
||||
+ }
|
||||
+
|
||||
+ @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.getAttributeModifiers().forEach((attribute, attributeModifier) -> {
|
||||
+ attributeMap.put(org.bukkit.craftbukkit.attribute.CraftAttributeMap.fromMinecraft(attribute.toString()), org.bukkit.craftbukkit.attribute.CraftAttributeInstance.convert(attributeModifier));
|
||||
+ });
|
||||
+ 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");
|
||||
+ net.minecraft.world.entity.ai.attributes.Attribute nmsAttribute = org.bukkit.craftbukkit.attribute.CraftAttributeMap.toMinecraft(attribute);
|
||||
+ com.google.common.base.Preconditions.checkArgument(this.handle.getAttributeModifiers().containsKey(nmsAttribute), attribute + " is not present on " + this.getKey());
|
||||
+ return this.handle.getAttributeModifierValue(effectAmplifier, this.handle.getAttributeModifiers().get(nmsAttribute));
|
||||
+ }
|
||||
+
|
||||
+ @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
|
||||
}
|
||||
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.junit.Test;
|
||||
+
|
||||
+import static org.junit.Assert.assertEquals;
|
||||
+import static org.junit.Assert.assertNotNull;
|
||||
+
|
||||
+public class EffectCategoryTest {
|
||||
+
|
||||
+ @Test
|
||||
+ public void testEffectCategoriesExist() {
|
||||
+ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) {
|
||||
+ assertNotNull(mobEffectInfo + " is missing a bukkit equivalent", CraftPotionEffectType.fromNMS(mobEffectInfo));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testCategoryHasEquivalentColors() {
|
||||
+ for (MobEffectCategory mobEffectInfo : MobEffectCategory.values()) {
|
||||
+ PotionEffectType.Category bukkitEffectCategory = CraftPotionEffectType.fromNMS(mobEffectInfo);
|
||||
+ assertEquals(mobEffectInfo.getTooltipFormatting().name() + " doesn't equal " + bukkitEffectCategory.getColor(), bukkitEffectCategory.getColor(), PaperAdventure.asAdventure(mobEffectInfo.getTooltipFormatting()));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
@@ -1,385 +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.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.ThrownTrident dealtDamage
|
||||
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
|
||||
|
||||
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
|
||||
|
||||
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(@org.jetbrains.annotations.Nullable HitResult hitResult) {
|
||||
+ // Paper end - More projectile API
|
||||
if (!this.level.isClientSide) {
|
||||
ItemStack itemstack = this.getItem();
|
||||
Potion potionregistry = PotionUtils.getPotion(itemstack);
|
||||
@@ -0,0 +0,0 @@ public class ThrownPotion extends ThrowableItemProjectile implements ItemSupplie
|
||||
if (this.isLingering()) {
|
||||
showParticles = this.makeAreaOfEffectCloud(itemstack, potionregistry); // Paper
|
||||
} else {
|
||||
- showParticles = this.applySplash(list, hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null); // Paper
|
||||
+ showParticles = this.applySplash(list, hitResult != null && hitResult.getType() == HitResult.Type.ENTITY ? ((EntityHitResult) hitResult).getEntity() : null); // Paper - nullable hitResult
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
public void setBounce(boolean doesBounce) {
|
||||
this.doesBounce = doesBounce;
|
||||
}
|
||||
+ // Paper start
|
||||
+ @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().preOnHit(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().preOnHit(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;
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
}
|
||||
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 AbstractProjectile implements AbstractArrow {
|
||||
return org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(getHandle().getPickupItem());
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public void setLifetimeTicks(int ticks) {
|
||||
+ this.getHandle().life = ticks;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getLifetimeTicks() {
|
||||
+ return this.getHandle().life;
|
||||
+ }
|
||||
+
|
||||
+ @org.jetbrains.annotations.NotNull
|
||||
+ @Override
|
||||
+ public org.bukkit.Sound getHitSound() {
|
||||
+ return org.bukkit.craftbukkit.CraftSound.getBukkit(this.getHandle().soundEvent);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setHitSound(@org.jetbrains.annotations.NotNull org.bukkit.Sound sound) {
|
||||
+ this.getHandle().setSoundEvent(org.bukkit.craftbukkit.CraftSound.getSoundEffect(sound));
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public void setNoPhysics(boolean noPhysics) {
|
||||
this.getHandle().setNoPhysics(noPhysics);
|
||||
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), Material.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 ? ItemStack.EMPTY : 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;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
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
|
||||
this.getHandle().setTarget(target == null ? null : ((CraftEntity) target).getHandle());
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ 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() {
|
||||
+ return org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(this.getHandle().currentMoveDirection);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setCurrentMovementDirection(org.bukkit.block.BlockFace movementDirection) {
|
||||
+ this.getHandle().currentMoveDirection = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(movementDirection);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getFlightSteps() {
|
||||
+ return this.getHandle().flightSteps;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setFlightSteps(int steps) {
|
||||
+ this.getHandle().flightSteps = steps;
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CraftShulkerBullet";
|
||||
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
|
||||
Validate.notNull(item, "ItemStack cannot be null.");
|
||||
|
||||
// The ItemStack must be a potion.
|
||||
- Validate.isTrue(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack must be a lingering or splash potion. This item stack was " + item.getType() + ".");
|
||||
+ //Validate.isTrue(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack must be a lingering or splash potion. This item stack was " + 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().getItemRaw(), Material.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) 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 CraftArrow 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/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 meta) {
|
||||
+ ((org.bukkit.craftbukkit.inventory.CraftMetaItem) meta).applyToItem(itemStack.getOrCreateTag());
|
||||
+ }
|
||||
|
||||
public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item) {
|
||||
+ return getItemMeta(item, CraftItemStack.getType(item));
|
||||
+ }
|
||||
+ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, Material material) {
|
||||
+ // Paper end
|
||||
if (!CraftItemStack.hasItemMeta(item)) {
|
||||
- return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item));
|
||||
+ return CraftItemFactory.instance().getItemMeta(material); // Paper
|
||||
}
|
||||
- switch (CraftItemStack.getType(item)) {
|
||||
+ switch (material) { // Paper
|
||||
case WRITTEN_BOOK:
|
||||
return new CraftMetaBookSigned(item.getTag());
|
||||
case WRITABLE_BOOK:
|
||||
@@ -1,66 +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
|
||||
+ public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, it.unimi.dsi.fastutil.shorts.Short2ObjectMap<BlockState> blockChanges, boolean suppressLightUpdates) {
|
||||
+ this.sectionPos = sectionPos;
|
||||
+ this.positions = blockChanges.keySet().toShortArray();
|
||||
+ this.states = blockChanges.values().toArray(new BlockState[0]);
|
||||
+ this.suppressLightUpdates = suppressLightUpdates;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
buf.writeLong(this.sectionPos.asLong());
|
||||
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(Map<Location, BlockData> blockChanges, boolean suppressLightUpdates) {
|
||||
+ 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<Location, BlockData> entry : blockChanges.entrySet()) {
|
||||
+ Location location = entry.getKey();
|
||||
+ if (!location.getWorld().equals(this.getWorld())) continue;
|
||||
+
|
||||
+ BlockData blockData = entry.getValue();
|
||||
+ BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
||||
+ 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, suppressLightUpdates);
|
||||
+ this.getHandle().connection.send(packet);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void sendBlockChanges(Collection<BlockState> blocks, boolean suppressLightUpdates) {
|
||||
Preconditions.checkArgument(blocks != null, "blocks must not be null");
|
||||
@@ -1,126 +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
|
||||
return new ClientboundSetPlayerTeamPacket(team.getName(), operation == ClientboundSetPlayerTeamPacket.Action.ADD ? 3 : 4, Optional.empty(), ImmutableList.of(playerName));
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ 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
|
||||
+
|
||||
public ClientboundSetPlayerTeamPacket(FriendlyByteBuf 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
|
||||
+ 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
|
||||
+
|
||||
@Override
|
||||
public void removePlayerFromTeam(String playerName, PlayerTeam team) {
|
||||
super.removePlayerFromTeam(playerName, team);
|
||||
@@ -0,0 +0,0 @@ public class ServerScoreboard extends Scoreboard {
|
||||
this.setDirty();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ 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
|
||||
+
|
||||
@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, team);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @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 {
|
||||
+ Validate.notNull(entries, "Entries cannot be null");
|
||||
+ CraftScoreboard scoreboard = this.checkState();
|
||||
+
|
||||
+ ((net.minecraft.server.ServerScoreboard) scoreboard.board).addPlayersToTeam(entries, this.team);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public boolean removePlayer(OfflinePlayer player) throws IllegalStateException, IllegalArgumentException {
|
||||
Validate.notNull(player, "OfflinePlayer cannot be null");
|
||||
@@ -0,0 +0,0 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
|
||||
return true;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @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 {
|
||||
+ Validate.notNull(entries, "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
|
||||
+
|
||||
@Override
|
||||
public boolean hasPlayer(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException {
|
||||
Validate.notNull(player, "OfflinePlayer cannot be null");
|
||||
@@ -1,33 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 19 Jul 2020 15:17:01 -0700
|
||||
Subject: [PATCH] Name craft scheduler threads according to the plugin using
|
||||
them
|
||||
|
||||
Provides quick access to culprits running far more threads than
|
||||
they should be
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
|
||||
@@ -0,0 +0,0 @@ class CraftAsyncTask extends CraftTask {
|
||||
@Override
|
||||
public void run() {
|
||||
final Thread thread = Thread.currentThread();
|
||||
- synchronized (this.workers) {
|
||||
+ // Paper start - name threads according to running plugin
|
||||
+ final String nameBefore = thread.getName();
|
||||
+ thread.setName(nameBefore + " - " + this.getOwner().getName());
|
||||
+ try { synchronized (this.workers) { // Paper end - name threads according to running plugin
|
||||
if (getPeriod() == CraftTask.CANCEL) {
|
||||
// Never continue running after cancelled.
|
||||
// Checking this with the lock is important!
|
||||
@@ -0,0 +0,0 @@ class CraftAsyncTask extends CraftTask {
|
||||
}
|
||||
}
|
||||
}
|
||||
+ } finally { thread.setName(nameBefore); } // Paper - name worker thread according
|
||||
}
|
||||
|
||||
LinkedList<BukkitWorker> getWorkers() {
|
||||
@@ -1,97 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 19 Dec 2021 09:13:41 -0800
|
||||
Subject: [PATCH] Only write chunk data to disk if it serializes without
|
||||
throwing
|
||||
|
||||
This ensures at least a valid version of the chunk exists
|
||||
on disk, even if outdated
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
}
|
||||
|
||||
}
|
||||
+
|
||||
+ public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
|
||||
+
|
||||
// Paper end
|
||||
private class ChunkBuffer extends ByteArrayOutputStream {
|
||||
|
||||
@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
|
||||
this.pos = chunkcoordintpair;
|
||||
}
|
||||
|
||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||
+ @Override
|
||||
+ public void write(final int b) {
|
||||
+ if (this.count > MAX_CHUNK_SIZE) {
|
||||
+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + this.count);
|
||||
+ }
|
||||
+ super.write(b);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void write(final byte[] b, final int off, final int len) {
|
||||
+ if (this.count + len > MAX_CHUNK_SIZE) {
|
||||
+ throw new RegionFileStorage.RegionFileSizeException("Region file too large: " + (this.count + len));
|
||||
+ }
|
||||
+ super.write(b, off, len);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void close() throws IOException {
|
||||
ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
NbtIo.write(nbt, (DataOutput) dataoutputstream);
|
||||
regionfile.setStatus(pos.x, pos.z, ChunkSerializer.getStatus(nbt)); // Paper - cache status on disk
|
||||
regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone
|
||||
+ dataoutputstream.close(); // Paper - only write if successful
|
||||
+ // Paper start - don't write garbage data to disk if writing serialization fails
|
||||
+ } catch (RegionFileSizeException e) {
|
||||
+ attempts = 5; // Don't retry
|
||||
+ regionfile.clear(pos);
|
||||
+ throw e;
|
||||
+ // Paper end - don't write garbage data to disk if writing serialization fails
|
||||
} catch (Throwable throwable) {
|
||||
if (dataoutputstream != null) {
|
||||
try {
|
||||
- dataoutputstream.close();
|
||||
+ //dataoutputstream.close(); // Paper - don't write garbage data to disk if writing serialization fails
|
||||
} catch (Throwable throwable1) {
|
||||
throwable.addSuppressed(throwable1);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
|
||||
throw throwable;
|
||||
}
|
||||
-
|
||||
- if (dataoutputstream != null) {
|
||||
- dataoutputstream.close();
|
||||
- }
|
||||
+ // Paper - move into try block to only write if successfully serialized
|
||||
}
|
||||
// Paper start
|
||||
return;
|
||||
@@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
|
||||
}
|
||||
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public static final class RegionFileSizeException extends RuntimeException {
|
||||
+
|
||||
+ public RegionFileSizeException(String message) {
|
||||
+ super(message);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Fri, 19 Feb 2021 22:51:52 -0800
|
||||
Subject: [PATCH] Oprimise map impl for tracked players
|
||||
|
||||
Reference2BooleanOpenHashMap is going to have
|
||||
better lookups than HashMap.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final Entity entity;
|
||||
private final int range;
|
||||
SectionPos lastSectionPos;
|
||||
- public final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet();
|
||||
+ public final Set<ServerPlayerConnection> seenBy = new ReferenceOpenHashSet<>(); // Paper - optimise map impl
|
||||
|
||||
public TrackedEntity(Entity entity, int i, int j, boolean flag) {
|
||||
this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit
|
||||
@@ -1,51 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 10 Jun 2021 14:36:00 -0700
|
||||
Subject: [PATCH] Optimise BlockSoil nearby water lookup
|
||||
|
||||
Apparently the abstract block iteration was taking about
|
||||
75% of the method call.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
||||
@@ -0,0 +0,0 @@ public class FarmBlock extends Block {
|
||||
}
|
||||
|
||||
private static boolean isNearWater(LevelReader world, BlockPos pos) {
|
||||
- Iterator iterator = BlockPos.betweenClosed(pos.offset(-4, 0, -4), pos.offset(4, 1, 4)).iterator();
|
||||
-
|
||||
- BlockPos blockposition1;
|
||||
-
|
||||
- do {
|
||||
- if (!iterator.hasNext()) {
|
||||
- return false;
|
||||
+ // Paper start - remove abstract block iteration
|
||||
+ int xOff = pos.getX();
|
||||
+ int yOff = pos.getY();
|
||||
+ int zOff = pos.getZ();
|
||||
+
|
||||
+ for (int dz = -4; dz <= 4; ++dz) {
|
||||
+ int z = dz + zOff;
|
||||
+ for (int dx = -4; dx <= 4; ++dx) {
|
||||
+ int x = xOff + dx;
|
||||
+ for (int dy = 0; dy <= 1; ++dy) {
|
||||
+ int y = dy + yOff;
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)world.getChunk(x >> 4, z >> 4);
|
||||
+ net.minecraft.world.level.material.FluidState fluid = chunk.getBlockStateFinal(x, y, z).getFluidState();
|
||||
+ if (fluid.is(FluidTags.WATER)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ }
|
||||
|
||||
- blockposition1 = (BlockPos) iterator.next();
|
||||
- } while (!world.getFluidState(blockposition1).is(FluidTags.WATER));
|
||||
-
|
||||
- return true;
|
||||
+ return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,215 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 7 May 2020 05:48:54 -0700
|
||||
Subject: [PATCH] Optimise chunk tick iteration
|
||||
|
||||
Use a dedicated list of entity ticking chunks to reduce the cost
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
|
||||
this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
|
||||
// Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ // Paper start - optimise chunk tick iteration
|
||||
+ if (this.needsBroadcastChanges()) {
|
||||
+ this.chunkMap.needsChangeBroadcasting.add(this);
|
||||
+ }
|
||||
+ // Paper end - optimise chunk tick iteration
|
||||
}
|
||||
|
||||
public void onChunkRemove() {
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
this.playersInMobSpawnRange = null;
|
||||
this.playersInChunkTickRange = null;
|
||||
// Paper end - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ // Paper start - optimise chunk tick iteration
|
||||
+ if (this.needsBroadcastChanges()) {
|
||||
+ this.chunkMap.needsChangeBroadcasting.remove(this);
|
||||
+ }
|
||||
+ // Paper end - optimise chunk tick iteration
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
|
||||
if (i < 0 || i >= this.changedBlocksPerSection.length) return; // CraftBukkit - SPIGOT-6086, SPIGOT-6296
|
||||
if (this.changedBlocksPerSection[i] == null) {
|
||||
- this.hasChangedSections = true;
|
||||
+ this.hasChangedSections = true; this.addToBroadcastMap(); // Paper - optimise chunk tick iteration
|
||||
this.changedBlocksPerSection[i] = new ShortOpenHashSet();
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
int k = this.lightEngine.getMaxLightSection();
|
||||
|
||||
if (y >= j && y <= k) {
|
||||
+ this.addToBroadcastMap(); // Paper - optimise chunk tick iteration
|
||||
int l = y - j;
|
||||
|
||||
if (lightType == LightLayer.SKY) {
|
||||
@@ -0,0 +0,0 @@ public class ChunkHolder {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - optimise chunk tick iteration
|
||||
+ public final boolean needsBroadcastChanges() {
|
||||
+ return this.hasChangedSections || !this.skyChangedLightSectionFilter.isEmpty() || !this.blockChangedLightSectionFilter.isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ private void addToBroadcastMap() {
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("ChunkHolder update");
|
||||
+ this.chunkMap.needsChangeBroadcasting.add(this);
|
||||
+ }
|
||||
+ // Paper end - optimise chunk tick iteration
|
||||
+
|
||||
public void broadcastChanges(LevelChunk chunk) {
|
||||
- if (this.hasChangedSections || !this.skyChangedLightSectionFilter.isEmpty() || !this.blockChangedLightSectionFilter.isEmpty()) {
|
||||
+ if (this.needsBroadcastChanges()) { // Paper - moved into above, other logic needs to call
|
||||
Level world = chunk.getLevel();
|
||||
int i = 0;
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
||||
import org.bukkit.entity.Player;
|
||||
// CraftBukkit end
|
||||
|
||||
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
||||
+
|
||||
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
|
||||
|
||||
private static final byte CHUNK_TYPE_REPLACEABLE = -1;
|
||||
@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
private final Queue<Runnable> unloadQueue;
|
||||
int viewDistance;
|
||||
public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper
|
||||
+ public final ReferenceOpenHashSet<ChunkHolder> needsChangeBroadcasting = new ReferenceOpenHashSet<>();
|
||||
|
||||
// Paper - rewrite chunk system
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -0,0 +0,0 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
import net.minecraft.world.level.storage.LevelData;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
||||
|
||||
public class ServerChunkCache extends ChunkSource {
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
|
||||
this.lastSpawnState = spawnercreature_d;
|
||||
gameprofilerfiller.popPush("filteringLoadedChunks");
|
||||
- List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(l);
|
||||
- Iterator iterator = this.chunkMap.getChunks().iterator();
|
||||
+ // Paper - moved down
|
||||
this.level.timings.chunkTicks.startTiming(); // Paper
|
||||
|
||||
- while (iterator.hasNext()) {
|
||||
- ChunkHolder playerchunk = (ChunkHolder) iterator.next();
|
||||
- LevelChunk chunk = playerchunk.getTickingChunk();
|
||||
-
|
||||
- if (chunk != null) {
|
||||
- list.add(new ServerChunkCache.ChunkAndHolder(chunk, playerchunk));
|
||||
- }
|
||||
- }
|
||||
+ // Paper - moved down
|
||||
|
||||
gameprofilerfiller.popPush("spawnAndTick");
|
||||
boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||
|
||||
- Collections.shuffle(list);
|
||||
+ // Paper - only shuffle if per-player mob spawning is disabled
|
||||
// Paper - moved natural spawn event up
|
||||
- Iterator iterator1 = list.iterator();
|
||||
+ // Paper start - optimise chunk tick iteration
|
||||
+ Iterator<LevelChunk> iterator1;
|
||||
+ if (this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||
+ iterator1 = this.entityTickingChunks.iterator();
|
||||
+ } else {
|
||||
+ iterator1 = this.entityTickingChunks.unsafeIterator();
|
||||
+ List<LevelChunk> shuffled = Lists.newArrayListWithCapacity(this.entityTickingChunks.size());
|
||||
+ while (iterator1.hasNext()) {
|
||||
+ shuffled.add(iterator1.next());
|
||||
+ }
|
||||
+ Collections.shuffle(shuffled);
|
||||
+ iterator1 = shuffled.iterator();
|
||||
+ }
|
||||
|
||||
+ try {
|
||||
while (iterator1.hasNext()) {
|
||||
- ServerChunkCache.ChunkAndHolder chunkproviderserver_a = (ServerChunkCache.ChunkAndHolder) iterator1.next();
|
||||
- LevelChunk chunk1 = chunkproviderserver_a.chunk;
|
||||
+ LevelChunk chunk1 = iterator1.next();
|
||||
+ ChunkHolder holder = chunk1.playerChunk;
|
||||
+ if (holder != null) {
|
||||
+ // Paper - move down
|
||||
+ // Paper end - optimise chunk tick iteration
|
||||
ChunkPos chunkcoordintpair = chunk1.getPos();
|
||||
|
||||
- if (this.level.isNaturalSpawningAllowed(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ if ((true || this.level.isNaturalSpawningAllowed(chunkcoordintpair)) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning // Paper - the chunk is known ticking
|
||||
chunk1.incrementInhabitedTime(j);
|
||||
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning
|
||||
+ if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration
|
||||
NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1);
|
||||
}
|
||||
|
||||
- if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) {
|
||||
+ if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - the chunk is known ticking
|
||||
this.level.tickChunk(chunk1, k);
|
||||
}
|
||||
}
|
||||
+ // Paper start - optimise chunk tick iteration
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ } finally {
|
||||
+ if (iterator1 instanceof io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator safeIterator) {
|
||||
+ safeIterator.finishedIterating();
|
||||
+ }
|
||||
}
|
||||
+ // Paper end - optimise chunk tick iteration
|
||||
this.level.timings.chunkTicks.stopTiming(); // Paper
|
||||
gameprofilerfiller.popPush("customSpawners");
|
||||
if (flag2) {
|
||||
@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
|
||||
this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
|
||||
} // Paper - timings
|
||||
}
|
||||
-
|
||||
- gameprofilerfiller.popPush("broadcast");
|
||||
- list.forEach((chunkproviderserver_a1) -> {
|
||||
- this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
|
||||
- chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk);
|
||||
- this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
|
||||
- });
|
||||
gameprofilerfiller.pop();
|
||||
+ // Paper start - use set of chunks requiring updates, rather than iterating every single one loaded
|
||||
+ gameprofilerfiller.popPush("broadcast");
|
||||
+ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing
|
||||
+ if (!this.chunkMap.needsChangeBroadcasting.isEmpty()) {
|
||||
+ ReferenceOpenHashSet<ChunkHolder> copy = this.chunkMap.needsChangeBroadcasting.clone();
|
||||
+ this.chunkMap.needsChangeBroadcasting.clear();
|
||||
+ for (ChunkHolder holder : copy) {
|
||||
+ holder.broadcastChanges(holder.getFullChunkNowUnchecked()); // LevelChunks are NEVER unloaded
|
||||
+ if (holder.needsBroadcastChanges()) {
|
||||
+ // I DON'T want to KNOW what DUMB plugins might be doing.
|
||||
+ this.chunkMap.needsChangeBroadcasting.add(holder);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing
|
||||
gameprofilerfiller.pop();
|
||||
+ // Paper end - use set of chunks requiring updates, rather than iterating every single one loaded
|
||||
this.chunkMap.tick();
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 2 Jul 2020 12:02:43 -0700
|
||||
Subject: [PATCH] Optimise collision checking in player move packet handling
|
||||
|
||||
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
return;
|
||||
}
|
||||
|
||||
- boolean flag = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
+ AABB oldBox = entity.getBoundingBox(); // Paper - copy from player movement packet
|
||||
|
||||
d6 = d3 - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d7 = d4 - this.vehicleLastGoodY - 1.0E-6D; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
boolean flag1 = entity.verticalCollisionBelow;
|
||||
|
||||
entity.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
||||
+ boolean didCollide = toX != entity.getX() || toY != entity.getY() || toZ != entity.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
double d11 = d7;
|
||||
|
||||
d6 = d3 - entity.getX();
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
boolean flag2 = false;
|
||||
|
||||
if (d10 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
||||
- flag2 = true;
|
||||
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", new Object[]{entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)});
|
||||
}
|
||||
Location curPos = this.getCraftPlayer().getLocation(); // Spigot
|
||||
|
||||
entity.absMoveTo(d3, d4, d5, f, f1);
|
||||
this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
- boolean flag3 = worldserver.noCollision(entity, entity.getBoundingBox().deflate(0.0625D));
|
||||
|
||||
- if (flag && (flag2 || !flag3)) {
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ boolean teleportBack = flag2; // violating this is always a fail
|
||||
+ if (!teleportBack) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ AABB newBox = entity.getBoundingBox();
|
||||
+ if (didCollide || !oldBox.equals(newBox)) {
|
||||
+ teleportBack = this.hasNewCollision(worldserver, entity, oldBox, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ if (teleportBack) { // Paper end - optimise out extra getCubes
|
||||
entity.absMoveTo(d0, d1, d2, f, f1);
|
||||
this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||
this.connection.send(new ClientboundMoveVehiclePacket(entity));
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
|
||||
private boolean noBlocksAround(Entity entity) {
|
||||
- return entity.level.getBlockStates(entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D)).allMatch(BlockBehaviour.BlockStateBase::isAir);
|
||||
+ // Paper start - stop using streams, this is already a known fixed problem in Entity#move
|
||||
+ AABB box = entity.getBoundingBox().inflate(0.0625D).expandTowards(0.0D, -0.55D, 0.0D);
|
||||
+ int minX = Mth.floor(box.minX);
|
||||
+ int minY = Mth.floor(box.minY);
|
||||
+ int minZ = Mth.floor(box.minZ);
|
||||
+ int maxX = Mth.floor(box.maxX);
|
||||
+ int maxY = Mth.floor(box.maxY);
|
||||
+ int maxZ = Mth.floor(box.maxZ);
|
||||
+
|
||||
+ Level world = entity.level;
|
||||
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||
+
|
||||
+ for (int y = minY; y <= maxY; ++y) {
|
||||
+ for (int z = minZ; z <= maxZ; ++z) {
|
||||
+ for (int x = minX; x <= maxX; ++x) {
|
||||
+ pos.set(x, y, z);
|
||||
+ BlockState type = world.getBlockStateIfLoaded(pos);
|
||||
+ if (type != null && !type.isAir()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ // Paper end - stop using streams, this is already a known fixed problem in Entity#move
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
- if (this.tickCount - this.awaitingTeleportTime > 20) {
|
||||
+ if (false && this.tickCount - this.awaitingTeleportTime > 20) { // Paper - this will greatly screw with clients with > 1000ms RTT
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
}
|
||||
|
||||
- AABB axisalignedbb = this.player.getBoundingBox();
|
||||
+ AABB axisalignedbb = this.player.getBoundingBox(); // Paper - diff on change, should be old AABB
|
||||
|
||||
d7 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d8 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
boolean flag1 = this.player.verticalCollisionBelow;
|
||||
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d7, d8, d9));
|
||||
+ boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
boolean flag2 = false;
|
||||
|
||||
if (!this.player.isChangingDimension() && d11 > org.spigotmc.SpigotConfig.movedWronglyThreshold && !this.player.isSleeping() && !this.player.gameMode.isCreative() && this.player.gameMode.getGameModeForPlayer() != GameType.SPECTATOR) { // Spigot
|
||||
- flag2 = true;
|
||||
+ flag2 = true; // Paper - diff on change, this should be moved wrongly
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} moved wrongly!", this.player.getName().getString());
|
||||
}
|
||||
|
||||
this.player.absMoveTo(d0, d1, d2, f, f1);
|
||||
- if (!this.player.noPhysics && !this.player.isSleeping() && (flag2 && worldserver.noCollision(this.player, axisalignedbb) || this.isPlayerCollidingWithAnythingNew(worldserver, axisalignedbb))) {
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ // Original for reference:
|
||||
+ // boolean teleportBack = flag2 && worldserver.getCubes(this.player, axisalignedbb) || (didCollide && this.a((IWorldReader) worldserver, axisalignedbb));
|
||||
+ boolean teleportBack = flag2; // violating this is always a fail
|
||||
+ if (!this.player.noPhysics && !this.player.isSleeping() && !teleportBack) {
|
||||
+ AABB newBox = this.player.getBoundingBox();
|
||||
+ if (didCollide || !axisalignedbb.equals(newBox)) {
|
||||
+ // note: only call after setLocation, or else getBoundingBox is wrong
|
||||
+ teleportBack = this.hasNewCollision(worldserver, this.player, axisalignedbb, newBox);
|
||||
+ } // else: no collision at all detected, why do we care?
|
||||
+ }
|
||||
+ if (!this.player.noPhysics && !this.player.isSleeping() && teleportBack) { // Paper end - optimise out extra getCubes
|
||||
this.internalTeleport(d3, d4, d5, f, f1, Collections.emptySet(), false); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet.
|
||||
this.player.doCheckFallDamage(this.player.getY() - d6, packet.isOnGround());
|
||||
} else {
|
||||
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - optimise out extra getCubes
|
||||
+ private boolean hasNewCollision(final ServerLevel world, final Entity entity, final AABB oldBox, final AABB newBox) {
|
||||
+ final List<AABB> collisions = io.papermc.paper.util.CachedLists.getTempCollisionList();
|
||||
+ try {
|
||||
+ io.papermc.paper.util.CollisionUtil.getCollisions(world, entity, newBox, collisions, false, true,
|
||||
+ true, false, null, null);
|
||||
+
|
||||
+ for (int i = 0, len = collisions.size(); i < len; ++i) {
|
||||
+ final AABB box = collisions.get(i);
|
||||
+ if (!io.papermc.paper.util.CollisionUtil.voxelShapeIntersect(box, oldBox)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+ } finally {
|
||||
+ io.papermc.paper.util.CachedLists.returnTempCollisionList(collisions);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - optimise out extra getCubes
|
||||
+
|
||||
private boolean isPlayerCollidingWithAnythingNew(LevelReader world, AABB box) {
|
||||
Iterable<VoxelShape> iterable = world.getCollisions(this.player, this.player.getBoundingBox().deflate(9.999999747378752E-6D));
|
||||
VoxelShape voxelshape = Shapes.create(box.deflate(9.999999747378752E-6D));
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user