diff --git a/patches/server/0004-Paper-config-files.patch b/patches/server/0004-Paper-config-files.patch index 07fac6871e..488d7a0304 100644 --- a/patches/server/0004-Paper-config-files.patch +++ b/patches/server/0004-Paper-config-files.patch @@ -934,10 +934,10 @@ index 0000000000000000000000000000000000000000..69add4a7f1147015806bc9b63a8340d1 +} diff --git a/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java new file mode 100644 -index 0000000000000000000000000000000000000000..0b6d68350f608bb64a701d0e390283d50f12094e +index 0000000000000000000000000000000000000000..9fde9ccb5d069ddce8dd837ef1bc68b93ce66434 --- /dev/null +++ b/src/main/java/io/papermc/paper/configuration/PaperConfigurations.java -@@ -0,0 +1,435 @@ +@@ -0,0 +1,439 @@ +package io.papermc.paper.configuration; + +import com.google.common.base.Suppliers; @@ -947,10 +947,11 @@ index 0000000000000000000000000000000000000000..0b6d68350f608bb64a701d0e390283d5 +import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; +import io.papermc.paper.configuration.serializer.ComponentSerializer; +import io.papermc.paper.configuration.serializer.EnumValueSerializer; -+import io.papermc.paper.configuration.serializer.FastutilMapSerializer; ++import io.papermc.paper.configuration.serializer.collections.FastutilMapSerializer; ++import io.papermc.paper.configuration.serializer.NbtPathSerializer; +import io.papermc.paper.configuration.serializer.PacketClassSerializer; +import io.papermc.paper.configuration.serializer.StringRepresentableSerializer; -+import io.papermc.paper.configuration.serializer.TableSerializer; ++import io.papermc.paper.configuration.serializer.collections.TableSerializer; +import io.papermc.paper.configuration.serializer.collections.MapSerializer; +import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer; +import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer; @@ -958,7 +959,8 @@ index 0000000000000000000000000000000000000000..0b6d68350f608bb64a701d0e390283d5 +import io.papermc.paper.configuration.transformation.global.LegacyPaperConfig; +import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration; +import io.papermc.paper.configuration.transformation.world.LegacyPaperWorldConfig; -+import io.papermc.paper.configuration.transformation.world.ZeroWorldHeight; ++import io.papermc.paper.configuration.transformation.world.versioned.V29_ZeroWorldHeight; ++import io.papermc.paper.configuration.transformation.world.versioned.V30_RenameFilterNbtFromSpawnEgg; +import io.papermc.paper.configuration.type.BooleanOrDefault; +import io.papermc.paper.configuration.type.DoubleOrDefault; +import io.papermc.paper.configuration.type.Duration; @@ -1150,6 +1152,7 @@ index 0000000000000000000000000000000000000000..0b6d68350f608bb64a701d0e390283d5 + .register(BooleanOrDefault.SERIALIZER) + .register(Duration.SERIALIZER) + .register(EngineMode.SERIALIZER) ++ .register(NbtPathSerializer.SERIALIZER) + .register(FallbackValueSerializer.create(contextMap.require(SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get(), MinecraftServer::getServer)) + .register(new RegistryValueSerializer<>(new TypeToken>() {}, Registries.ENTITY_TYPE, true)) + .register(new RegistryValueSerializer<>(Item.class, Registries.ITEM, true)) @@ -1174,7 +1177,8 @@ index 0000000000000000000000000000000000000000..0b6d68350f608bb64a701d0e390283d5 + builder.build().apply(node); + + final ConfigurationTransformation.VersionedBuilder versionedBuilder = Transformations.versionedBuilder(); -+ ZeroWorldHeight.apply(versionedBuilder); ++ V29_ZeroWorldHeight.apply(versionedBuilder); ++ V30_RenameFilterNbtFromSpawnEgg.apply(versionedBuilder); + // ADD FUTURE VERSIONED TRANSFORMS TO versionedBuilder HERE + versionedBuilder.build().apply(node); + } @@ -1447,7 +1451,7 @@ new file mode 100644 index 0000000000000000000000000000000000000000..2e9590c73d867c3ebb42f695df4c796a0f477452 --- /dev/null +++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java -@@ -0,0 +1,472 @@ +@@ -0,0 +1,475 @@ +package io.papermc.paper.configuration; + +import com.google.common.collect.HashBasedTable; @@ -1458,6 +1462,7 @@ index 0000000000000000000000000000000000000000..2e9590c73d867c3ebb42f695df4c796a +import io.papermc.paper.configuration.legacy.MaxEntityCollisionsInitializer; +import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization; +import io.papermc.paper.configuration.legacy.SpawnLoadedRangeInitializer; ++import io.papermc.paper.configuration.serializer.NbtPathSerializer; +import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration; +import io.papermc.paper.configuration.type.BooleanOrDefault; +import io.papermc.paper.configuration.type.DoubleOrDefault; @@ -1476,6 +1481,7 @@ index 0000000000000000000000000000000000000000..2e9590c73d867c3ebb42f695df4c796a +import java.util.function.Function; +import java.util.stream.Collectors; +import net.minecraft.Util; ++import net.minecraft.commands.arguments.NbtPathArgument; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; @@ -1497,7 +1503,7 @@ index 0000000000000000000000000000000000000000..2e9590c73d867c3ebb42f695df4c796a +@SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"}) +public class WorldConfiguration extends ConfigurationPart { + private static final Logger LOGGER = LogUtils.getLogger(); -+ static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): zero height fixes ++ static final int CURRENT_VERSION = 30; // (when you change the version, change the comment, so it conflicts on rebases): rename filter bad nbt from spawn eggs + + private transient final SpigotWorldConfig spigotConfig; + private transient final ResourceLocation worldKey; @@ -1573,7 +1579,8 @@ index 0000000000000000000000000000000000000000..2e9590c73d867c3ebb42f695df4c796a + public class Spawning extends ConfigurationPart { + public ArrowDespawnRate nonPlayerArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); + public ArrowDespawnRate creativeArrowDespawnRate = ArrowDespawnRate.def(WorldConfiguration.this.spigotConfig); -+ public boolean filterNbtDataFromSpawnEggsAndRelated = true; ++ public boolean filterBadTileEntityNbtFromFallingBlocks = true; ++ public List filteredEntityTagNbtPaths = NbtPathSerializer.fromString(List.of("Pos", "Motion", "SleepingX", "SleepingY", "SleepingZ")); + public boolean disableMobSpawnerSpawnEggTransformation = false; + public boolean perPlayerMobSpawns = true; + public boolean scanForLegacyEnderDragon = true; @@ -2300,78 +2307,61 @@ index 0000000000000000000000000000000000000000..2afb9268447792e3cdb46172b2050dbc + return item.name(); + } +} -diff --git a/src/main/java/io/papermc/paper/configuration/serializer/FastutilMapSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/FastutilMapSerializer.java +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/NbtPathSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/NbtPathSerializer.java new file mode 100644 -index 0000000000000000000000000000000000000000..f2f362883d1825084c277608c791f82165828ebe +index 0000000000000000000000000000000000000000..b44b2dc28f619594e302417848e95c0087acbcea --- /dev/null -+++ b/src/main/java/io/papermc/paper/configuration/serializer/FastutilMapSerializer.java -@@ -0,0 +1,69 @@ ++++ b/src/main/java/io/papermc/paper/configuration/serializer/NbtPathSerializer.java +@@ -0,0 +1,52 @@ +package io.papermc.paper.configuration.serializer; + -+import io.leangen.geantyref.GenericTypeReflector; -+import io.leangen.geantyref.TypeFactory; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.spongepowered.configurate.ConfigurationNode; -+import org.spongepowered.configurate.serialize.SerializationException; -+import org.spongepowered.configurate.serialize.TypeSerializer; -+ -+import java.lang.reflect.ParameterizedType; ++import com.destroystokyo.paper.util.SneakyThrow; ++import com.mojang.brigadier.StringReader; ++import com.mojang.brigadier.exceptions.CommandSyntaxException; +import java.lang.reflect.Type; -+import java.util.Collections; -+import java.util.Map; -+import java.util.function.Function; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.function.Predicate; ++import net.minecraft.commands.arguments.NbtPathArgument; ++import org.spongepowered.configurate.serialize.ScalarSerializer; ++import org.spongepowered.configurate.serialize.SerializationException; + -+@SuppressWarnings("rawtypes") -+public abstract class FastutilMapSerializer> implements TypeSerializer { -+ private final Function factory; ++public class NbtPathSerializer extends ScalarSerializer { + -+ protected FastutilMapSerializer(final Function factory) { -+ this.factory = factory; ++ public static final NbtPathSerializer SERIALIZER = new NbtPathSerializer(); ++ private static final NbtPathArgument DUMMY_ARGUMENT = new NbtPathArgument(); ++ ++ private NbtPathSerializer() { ++ super(NbtPathArgument.NbtPath.class); + } + + @Override -+ public M deserialize(final Type type, final ConfigurationNode node) throws SerializationException { -+ @Nullable final Map map = (Map) node.get(this.createBaseMapType((ParameterizedType) type)); -+ return this.factory.apply(map == null ? Collections.emptyMap() : map); ++ public NbtPathArgument.NbtPath deserialize(final Type type, final Object obj) throws SerializationException { ++ return fromString(obj.toString()); + } + + @Override -+ public void serialize(final Type type, @Nullable final M obj, final ConfigurationNode node) throws SerializationException { -+ if (obj == null || obj.isEmpty()) { -+ node.raw(null); -+ } else { -+ final Type baseMapType = this.createBaseMapType((ParameterizedType) type); -+ node.set(baseMapType, obj); -+ } ++ protected Object serialize(final NbtPathArgument.NbtPath item, final Predicate> typeSupported) { ++ return item.toString(); + } + -+ protected abstract Type createBaseMapType(final ParameterizedType type); -+ -+ public static final class SomethingToPrimitive> extends FastutilMapSerializer { -+ private final Type primitiveType; -+ -+ public SomethingToPrimitive(final Function factory, final Type primitiveType) { -+ super(factory); -+ this.primitiveType = primitiveType; -+ } -+ -+ @Override -+ protected Type createBaseMapType(final ParameterizedType type) { -+ return TypeFactory.parameterizedClass(Map.class, type.getActualTypeArguments()[0], GenericTypeReflector.box(this.primitiveType)); ++ public static List fromString(final List tags) { ++ List paths = new ArrayList<>(); ++ try { ++ for (final String tag : tags) { ++ paths.add(fromString(tag)); ++ } ++ } catch (SerializationException ex) { ++ SneakyThrow.sneaky(ex); + } ++ return List.copyOf(paths); + } + -+ public static final class PrimitiveToSomething> extends FastutilMapSerializer { -+ private final Type primitiveType; -+ -+ public PrimitiveToSomething(final Function factory, final Type primitiveType) { -+ super(factory); -+ this.primitiveType = primitiveType; -+ } -+ -+ @Override -+ protected Type createBaseMapType(final ParameterizedType type) { -+ return TypeFactory.parameterizedClass(Map.class, GenericTypeReflector.box(this.primitiveType), type.getActualTypeArguments()[0]); ++ private static NbtPathArgument.NbtPath fromString(final String tag) throws SerializationException { ++ try { ++ return DUMMY_ARGUMENT.parse(new StringReader(tag)); ++ } catch (CommandSyntaxException e) { ++ throw new SerializationException(NbtPathArgument.NbtPath.class, e); + } + } +} @@ -2525,99 +2515,79 @@ index 0000000000000000000000000000000000000000..7fc0905fc6b8f5df762b4cea573f935d + return item.getSerializedName(); + } +} -diff --git a/src/main/java/io/papermc/paper/configuration/serializer/TableSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/TableSerializer.java +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/collections/FastutilMapSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/collections/FastutilMapSerializer.java new file mode 100644 -index 0000000000000000000000000000000000000000..346422c5eb791961061cc73b9b827d63bbd67daf +index 0000000000000000000000000000000000000000..4af710e144b70933d750c22edfe484c18e4a3540 --- /dev/null -+++ b/src/main/java/io/papermc/paper/configuration/serializer/TableSerializer.java -@@ -0,0 +1,89 @@ -+package io.papermc.paper.configuration.serializer; ++++ b/src/main/java/io/papermc/paper/configuration/serializer/collections/FastutilMapSerializer.java +@@ -0,0 +1,69 @@ ++package io.papermc.paper.configuration.serializer.collections; + -+import com.google.common.collect.HashBasedTable; -+import com.google.common.collect.ImmutableTable; -+import com.google.common.collect.Table; ++import io.leangen.geantyref.GenericTypeReflector; +import io.leangen.geantyref.TypeFactory; +import org.checkerframework.checker.nullness.qual.Nullable; -+import org.spongepowered.configurate.BasicConfigurationNode; +import org.spongepowered.configurate.ConfigurationNode; -+import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializer; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; ++import java.util.Collections; +import java.util.Map; -+import java.util.Objects; ++import java.util.function.Function; + -+public class TableSerializer implements TypeSerializer> { -+ private static final int ROW_TYPE_ARGUMENT_INDEX = 0; -+ private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1; -+ private static final int VALUE_TYPE_ARGUMENT_INDEX = 2; ++@SuppressWarnings("rawtypes") ++public abstract class FastutilMapSerializer> implements TypeSerializer { ++ private final Function factory; + -+ @Override -+ public Table deserialize(final Type type, final ConfigurationNode node) throws SerializationException { -+ final Table table = HashBasedTable.create(); -+ if (!node.empty() && node.isMap()) { -+ this.deserialize0(table, (ParameterizedType) type, node); -+ } -+ return table; -+ } -+ -+ @SuppressWarnings("unchecked") -+ private void deserialize0(final Table table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException { -+ final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; -+ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; -+ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; -+ -+ final @Nullable TypeSerializer rowKeySerializer = (TypeSerializer) node.options().serializers().get(rowType); -+ if (rowKeySerializer == null) { -+ throw new SerializationException("Could not find serializer for table row type " + rowType); -+ } -+ -+ final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType); -+ final @Nullable TypeSerializer> columnValueSerializer = (TypeSerializer>) node.options().serializers().get(mapType); -+ if (columnValueSerializer == null) { -+ throw new SerializationException("Could not find serializer for table column-value map " + type); -+ } -+ -+ final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options()); -+ -+ for (final Object key : node.childrenMap().keySet()) { -+ final R rowKey = rowKeySerializer.deserialize(rowType, rowKeyNode.set(key)); -+ final Map map = columnValueSerializer.deserialize(mapType, node.node(rowKeyNode.raw())); -+ map.forEach((column, value) -> table.put(rowKey, column, value)); -+ } ++ protected FastutilMapSerializer(final Function factory) { ++ this.factory = factory; + } + + @Override -+ public void serialize(final Type type, @Nullable final Table table, final ConfigurationNode node) throws SerializationException { -+ if (table != null) { -+ this.serialize0(table, (ParameterizedType) type, node); -+ } -+ } -+ -+ @SuppressWarnings({"rawtypes", "unchecked"}) -+ private void serialize0(final Table table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException { -+ final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; -+ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; -+ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; -+ -+ final @Nullable TypeSerializer rowKeySerializer = node.options().serializers().get(rowType); -+ if (rowKeySerializer == null) { -+ throw new SerializationException("Could not find a serializer for table row type " + rowType); -+ } -+ -+ final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options()); -+ for (final R key : table.rowKeySet()) { -+ rowKeySerializer.serialize(rowType, key, rowKeyNode.set(key)); -+ final Object keyObj = Objects.requireNonNull(rowKeyNode.raw()); -+ node.node(keyObj).set(TypeFactory.parameterizedClass(Map.class, columnType, valueType), table.row(key)); -+ } ++ public M deserialize(final Type type, final ConfigurationNode node) throws SerializationException { ++ @Nullable final Map map = (Map) node.get(this.createBaseMapType((ParameterizedType) type)); ++ return this.factory.apply(map == null ? Collections.emptyMap() : map); + } + + @Override -+ public @Nullable Table emptyValue(Type specificType, ConfigurationOptions options) { -+ return ImmutableTable.of(); ++ public void serialize(final Type type, @Nullable final M obj, final ConfigurationNode node) throws SerializationException { ++ if (obj == null || obj.isEmpty()) { ++ node.raw(null); ++ } else { ++ final Type baseMapType = this.createBaseMapType((ParameterizedType) type); ++ node.set(baseMapType, obj); ++ } ++ } ++ ++ protected abstract Type createBaseMapType(final ParameterizedType type); ++ ++ public static final class SomethingToPrimitive> extends FastutilMapSerializer { ++ private final Type primitiveType; ++ ++ public SomethingToPrimitive(final Function factory, final Type primitiveType) { ++ super(factory); ++ this.primitiveType = primitiveType; ++ } ++ ++ @Override ++ protected Type createBaseMapType(final ParameterizedType type) { ++ return TypeFactory.parameterizedClass(Map.class, type.getActualTypeArguments()[0], GenericTypeReflector.box(this.primitiveType)); ++ } ++ } ++ ++ public static final class PrimitiveToSomething> extends FastutilMapSerializer { ++ private final Type primitiveType; ++ ++ public PrimitiveToSomething(final Function factory, final Type primitiveType) { ++ super(factory); ++ this.primitiveType = primitiveType; ++ } ++ ++ @Override ++ protected Type createBaseMapType(final ParameterizedType type) { ++ return TypeFactory.parameterizedClass(Map.class, GenericTypeReflector.box(this.primitiveType), type.getActualTypeArguments()[0]); ++ } + } +} diff --git a/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/collections/MapSerializer.java @@ -2788,9 +2758,104 @@ index 0000000000000000000000000000000000000000..f44d4cb05eab25d79a8ac09b9da98163 + public interface WriteBack { // marker interface + } +} +diff --git a/src/main/java/io/papermc/paper/configuration/serializer/collections/TableSerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/collections/TableSerializer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..36ca88b677e1b55b41c52750948d5b6de7ecd007 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/serializer/collections/TableSerializer.java +@@ -0,0 +1,89 @@ ++package io.papermc.paper.configuration.serializer.collections; ++ ++import com.google.common.collect.HashBasedTable; ++import com.google.common.collect.ImmutableTable; ++import com.google.common.collect.Table; ++import io.leangen.geantyref.TypeFactory; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.spongepowered.configurate.BasicConfigurationNode; ++import org.spongepowered.configurate.ConfigurationNode; ++import org.spongepowered.configurate.ConfigurationOptions; ++import org.spongepowered.configurate.serialize.SerializationException; ++import org.spongepowered.configurate.serialize.TypeSerializer; ++ ++import java.lang.reflect.ParameterizedType; ++import java.lang.reflect.Type; ++import java.util.Map; ++import java.util.Objects; ++ ++public class TableSerializer implements TypeSerializer> { ++ private static final int ROW_TYPE_ARGUMENT_INDEX = 0; ++ private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1; ++ private static final int VALUE_TYPE_ARGUMENT_INDEX = 2; ++ ++ @Override ++ public Table deserialize(final Type type, final ConfigurationNode node) throws SerializationException { ++ final Table table = HashBasedTable.create(); ++ if (!node.empty() && node.isMap()) { ++ this.deserialize0(table, (ParameterizedType) type, node); ++ } ++ return table; ++ } ++ ++ @SuppressWarnings("unchecked") ++ private void deserialize0(final Table table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException { ++ final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; ++ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; ++ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; ++ ++ final @Nullable TypeSerializer rowKeySerializer = (TypeSerializer) node.options().serializers().get(rowType); ++ if (rowKeySerializer == null) { ++ throw new SerializationException("Could not find serializer for table row type " + rowType); ++ } ++ ++ final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType); ++ final @Nullable TypeSerializer> columnValueSerializer = (TypeSerializer>) node.options().serializers().get(mapType); ++ if (columnValueSerializer == null) { ++ throw new SerializationException("Could not find serializer for table column-value map " + type); ++ } ++ ++ final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options()); ++ ++ for (final Object key : node.childrenMap().keySet()) { ++ final R rowKey = rowKeySerializer.deserialize(rowType, rowKeyNode.set(key)); ++ final Map map = columnValueSerializer.deserialize(mapType, node.node(rowKeyNode.raw())); ++ map.forEach((column, value) -> table.put(rowKey, column, value)); ++ } ++ } ++ ++ @Override ++ public void serialize(final Type type, @Nullable final Table table, final ConfigurationNode node) throws SerializationException { ++ if (table != null) { ++ this.serialize0(table, (ParameterizedType) type, node); ++ } ++ } ++ ++ @SuppressWarnings({"rawtypes", "unchecked"}) ++ private void serialize0(final Table table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException { ++ final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX]; ++ final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX]; ++ final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX]; ++ ++ final @Nullable TypeSerializer rowKeySerializer = node.options().serializers().get(rowType); ++ if (rowKeySerializer == null) { ++ throw new SerializationException("Could not find a serializer for table row type " + rowType); ++ } ++ ++ final BasicConfigurationNode rowKeyNode = BasicConfigurationNode.root(node.options()); ++ for (final R key : table.rowKeySet()) { ++ rowKeySerializer.serialize(rowType, key, rowKeyNode.set(key)); ++ final Object keyObj = Objects.requireNonNull(rowKeyNode.raw()); ++ node.node(keyObj).set(TypeFactory.parameterizedClass(Map.class, columnType, valueType), table.row(key)); ++ } ++ } ++ ++ @Override ++ public @Nullable Table emptyValue(Type specificType, ConfigurationOptions options) { ++ return ImmutableTable.of(); ++ } ++} diff --git a/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java new file mode 100644 -index 0000000000000000000000000000000000000000..0e4e0f1788cf67312cb52bd572784c2f27db71b6 +index 0000000000000000000000000000000000000000..18da824fd003c110083a6c08d5db75578171433c --- /dev/null +++ b/src/main/java/io/papermc/paper/configuration/serializer/registry/RegistryEntrySerializer.java @@ -0,0 +1,62 @@ @@ -2826,7 +2891,7 @@ index 0000000000000000000000000000000000000000..0e4e0f1788cf67312cb52bd572784c2f + } + + protected final Registry registry() { -+ return MinecraftServer.getServer().registryAccess().registryOrThrow(this.registryKey); ++ return MinecraftServer.getServer().registryAccess().registryOrThrow(this.registryKey); // TODO don't depend on MinecraftServer#getServer + } + + protected abstract T convertFromResourceKey(ResourceKey key) throws SerializationException; @@ -3616,13 +3681,13 @@ index 0000000000000000000000000000000000000000..edaa6ef28c1f9a223943969870889700 + moveFromRootAndRename(builder, path("game-mechanics", oldKey), newKey, parents); + } +} -diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/ZeroWorldHeight.java b/src/main/java/io/papermc/paper/configuration/transformation/world/ZeroWorldHeight.java +diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V29_ZeroWorldHeight.java b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V29_ZeroWorldHeight.java new file mode 100644 -index 0000000000000000000000000000000000000000..dcb1f3722de215800ddb0285538bc188d02af054 +index 0000000000000000000000000000000000000000..f67e82fbeb97d68d5733bbd1c246183f5e91ab0a --- /dev/null -+++ b/src/main/java/io/papermc/paper/configuration/transformation/world/ZeroWorldHeight.java -@@ -0,0 +1,46 @@ -+package io.papermc.paper.configuration.transformation.world; ++++ b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V29_ZeroWorldHeight.java +@@ -0,0 +1,49 @@ ++package io.papermc.paper.configuration.transformation.world.versioned; + +import io.papermc.paper.configuration.type.IntOr; +import org.checkerframework.checker.nullness.qual.Nullable; @@ -3638,7 +3703,7 @@ index 0000000000000000000000000000000000000000..dcb1f3722de215800ddb0285538bc188 + * Several configurations that set a y-level used '0' as the "disabled" value. + * Since 0 is now a valid value, they need to be updated. + */ -+public class ZeroWorldHeight implements TransformAction { ++public final class V29_ZeroWorldHeight implements TransformAction { + + private static final int VERSION = 29; + @@ -3649,7 +3714,10 @@ index 0000000000000000000000000000000000000000..dcb1f3722de215800ddb0285538bc188 + private static final String ENVIRONMENT_KEY = "environment"; + private static final String NETHER_CEILING_VOID_DAMAGE_HEIGHT_KEY = "nether-ceiling-void-damage-height"; + -+ private static final ZeroWorldHeight INSTANCE = new ZeroWorldHeight(); ++ private static final V29_ZeroWorldHeight INSTANCE = new V29_ZeroWorldHeight(); ++ ++ private V29_ZeroWorldHeight() { ++ } + + public static void apply(ConfigurationTransformation.VersionedBuilder builder) { + final ConfigurationTransformation transformation = ConfigurationTransformation.builder() @@ -3668,6 +3736,37 @@ index 0000000000000000000000000000000000000000..dcb1f3722de215800ddb0285538bc188 + return null; + } +} +diff --git a/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V30_RenameFilterNbtFromSpawnEgg.java b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V30_RenameFilterNbtFromSpawnEgg.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d08b65234192d5b639cead675114f64bf1f409c4 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/configuration/transformation/world/versioned/V30_RenameFilterNbtFromSpawnEgg.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.configuration.transformation.world.versioned; ++ ++import org.spongepowered.configurate.NodePath; ++import org.spongepowered.configurate.transformation.ConfigurationTransformation; ++ ++import static org.spongepowered.configurate.NodePath.path; ++import static org.spongepowered.configurate.transformation.TransformAction.rename; ++ ++/** ++ * The {@code filter-nbt-data-from-spawn-eggs-and-related} setting had nothing ++ * to do with spawn eggs, and was just filtering bad falling blocks. ++ */ ++public final class V30_RenameFilterNbtFromSpawnEgg { ++ ++ private static final int VERSION = 30; ++ private static final NodePath OLD_PATH = path("entities", "spawning", "filter-nbt-data-from-spawn-eggs-and-related"); ++ private static final String NEW_PATH = "filter-bad-tile-entity-nbt-from-falling-blocks"; ++ ++ private V30_RenameFilterNbtFromSpawnEgg() { ++ } ++ ++ public static void apply(ConfigurationTransformation.VersionedBuilder builder) { ++ builder.addVersion(VERSION, ConfigurationTransformation.builder().addAction(OLD_PATH, rename(NEW_PATH)).build()); ++ } ++} diff --git a/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java b/src/main/java/io/papermc/paper/configuration/type/BooleanOrDefault.java new file mode 100644 index 0000000000000000000000000000000000000000..3e422b74a377fa3edaf82dd960e7449c998c2912 diff --git a/patches/server/0110-Filter-bad-data-from-ArmorStand-and-SpawnEgg-items.patch b/patches/server/0110-Filter-bad-data-from-ArmorStand-and-SpawnEgg-items.patch deleted file mode 100644 index df705ffa89..0000000000 --- a/patches/server/0110-Filter-bad-data-from-ArmorStand-and-SpawnEgg-items.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zach Brown -Date: Sat, 12 Nov 2016 23:25:22 -0600 -Subject: [PATCH] Filter bad data from ArmorStand and SpawnEgg items - - -diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 561b8d6fcf4d511fb026bcc2c02054e56589d0b7..e7404619877099aa2223da349e15090d2c9be1d0 100644 ---- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -318,6 +318,18 @@ public class FallingBlockEntity extends Entity { - @Override - protected void readAdditionalSaveData(CompoundTag nbt) { - this.blockState = NbtUtils.readBlockState(this.level.holderLookup(Registries.BLOCK), nbt.getCompound("BlockState")); -+ // Paper start - Block FallingBlocks with Command Blocks -+ final Block b = this.blockState.getBlock(); -+ if (this.level.paperConfig().entities.spawning.filterNbtDataFromSpawnEggsAndRelated -+ && (b == Blocks.COMMAND_BLOCK -+ || b == Blocks.REPEATING_COMMAND_BLOCK -+ || b == Blocks.CHAIN_COMMAND_BLOCK -+ || b == Blocks.JIGSAW -+ || b == Blocks.STRUCTURE_BLOCK -+ || b instanceof net.minecraft.world.level.block.GameMasterBlock)) { -+ this.blockState = Blocks.STONE.defaultBlockState(); -+ } -+ // Paper end - this.time = nbt.getInt("Time"); - if (nbt.contains("HurtEntities", 99)) { - this.hurtEntities = nbt.getBoolean("HurtEntities"); diff --git a/patches/server/0110-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch b/patches/server/0110-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch new file mode 100644 index 0000000000..d71e5f98da --- /dev/null +++ b/patches/server/0110-Filter-bad-tile-entity-nbt-data-from-falling-blocks.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Sat, 12 Nov 2016 23:25:22 -0600 +Subject: [PATCH] Filter bad tile entity nbt data from falling blocks + + +diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +index 561b8d6fcf4d511fb026bcc2c02054e56589d0b7..97b2d12713d2245f1621d3ade5b5655b5897cbf4 100644 +--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java ++++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +@@ -331,7 +331,7 @@ public class FallingBlockEntity extends Entity { + this.dropItem = nbt.getBoolean("DropItem"); + } + +- if (nbt.contains("TileEntityData", 10)) { ++ if (nbt.contains("TileEntityData", 10) && !(this.level.paperConfig().entities.spawning.filterBadTileEntityNbtFromFallingBlocks && this.blockState.getBlock() instanceof net.minecraft.world.level.block.GameMasterBlock)) { + this.blockData = nbt.getCompound("TileEntityData"); + } + diff --git a/patches/server/0844-FallingBlock-auto-expire-setting.patch b/patches/server/0844-FallingBlock-auto-expire-setting.patch index 3898a05650..423e657aa6 100644 --- a/patches/server/0844-FallingBlock-auto-expire-setting.patch +++ b/patches/server/0844-FallingBlock-auto-expire-setting.patch @@ -5,7 +5,7 @@ Subject: [PATCH] FallingBlock auto expire setting diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 23bd2a9af71b63bf463c7091ac261b033e9ce9af..72f1866226269396ba0f0c1be269e237925d9322 100644 +index 06f6fe4d1be4b14c45d2576561201c9386988dc1..eacb8a407fe99af2c13f23c12b5544696bda8890 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -63,6 +63,7 @@ public class FallingBlockEntity extends Entity { @@ -33,7 +33,7 @@ index 23bd2a9af71b63bf463c7091ac261b033e9ce9af..72f1866226269396ba0f0c1be269e237 } -@@ -369,6 +371,10 @@ public class FallingBlockEntity extends Entity { +@@ -357,6 +359,10 @@ public class FallingBlockEntity extends Entity { int srcZ = nbt.getInt("SourceLoc_z"); this.setOrigin(new org.bukkit.Location(level.getWorld(), srcX, srcY, srcZ)); } diff --git a/patches/server/0956-config-for-disabling-entity-tag-tags.patch b/patches/server/0956-config-for-disabling-entity-tag-tags.patch new file mode 100644 index 0000000000..2ae3536198 --- /dev/null +++ b/patches/server/0956-config-for-disabling-entity-tag-tags.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 15 Sep 2021 14:52:42 -0700 +Subject: [PATCH] config for disabling entity tag tags + + +diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java +index e5cd4b7609243669c9d84ff8a4988c209e6101aa..4589f7db68f7a72065c85c0a50216c6d02658f1e 100644 +--- a/src/main/java/net/minecraft/world/entity/EntityType.java ++++ b/src/main/java/net/minecraft/world/entity/EntityType.java +@@ -484,6 +484,13 @@ public class EntityType implements FeatureElement, EntityTypeT + if (world.isClientSide || !entity.onlyOpCanSetNbt() || player != null && minecraftserver.getPlayerList().isOp(player.getGameProfile())) { + CompoundTag nbttagcompound1 = entity.saveWithoutId(new CompoundTag()); + UUID uuid = entity.getUUID(); ++ // Paper start - filter out protected tags ++ if (player == null || !player.getBukkitEntity().hasPermission("minecraft.nbt.place")) { ++ for (net.minecraft.commands.arguments.NbtPathArgument.NbtPath tag : world.paperConfig().entities.spawning.filteredEntityTagNbtPaths) { ++ tag.remove(itemNbt.getCompound("EntityTag")); ++ } ++ } ++ // Paper end + + nbttagcompound1.merge(itemNbt.getCompound("EntityTag")); + entity.setUUID(uuid);