|
| 1 | +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Spottedleaf <Spottedleaf@users.noreply.github.com> |
| 3 | +Date: Sat, 19 Jun 2021 10:54:52 -0700 |
| 4 | +Subject: [PATCH] Fix Codec log spam |
| 5 | + |
| 6 | +Mojang did NOT add dataconverters for world gen configurations |
| 7 | +that they CHANGED. So, the codec fails to parse old data. |
| 8 | + |
| 9 | +This fixes two instances: |
| 10 | +- IntProvider is new and Mojang did not account for old data. |
| 11 | + Thankfully, only ColumnPlace needed to be special cased. |
| 12 | +- TreeConfiguration had changes. Thankfully, they were |
| 13 | + only renames for one value and thankfully defaults could |
| 14 | + be provided for two new values (WITHOUT changing behavior). |
| 15 | + |
| 16 | +diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java |
| 17 | +index 7684f0146fa522287d223d4b3cb1c999458b872e..3d1e1cb8a1ca32e11ccea7e554827cf88dd28c1b 100644 |
| 18 | +--- a/src/main/java/net/minecraft/server/MCUtil.java |
| 19 | ++++ b/src/main/java/net/minecraft/server/MCUtil.java |
| 20 | +@@ -718,4 +718,70 @@ public final class MCUtil { |
| 21 | + public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { |
| 22 | + return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); |
| 23 | + } |
| 24 | ++ |
| 25 | ++ public static <A> com.mojang.serialization.MapCodec<A> fieldWithFallbacks(com.mojang.serialization.Codec<A> codec, String name, String ...fallback) { |
| 26 | ++ return com.mojang.serialization.MapCodec.of( |
| 27 | ++ new com.mojang.serialization.codecs.FieldEncoder<>(name, codec), |
| 28 | ++ new FieldFallbackDecoder<>(name, java.util.Arrays.asList(fallback), codec), |
| 29 | ++ () -> "FieldFallback[" + name + ": " + codec.toString() + "]" |
| 30 | ++ ); |
| 31 | ++ } |
| 32 | ++ |
| 33 | ++ // This is likely a common occurrence, sadly |
| 34 | ++ public static final class FieldFallbackDecoder<A> extends com.mojang.serialization.MapDecoder.Implementation<A> { |
| 35 | ++ protected final String name; |
| 36 | ++ protected final List<String> fallback; |
| 37 | ++ private final com.mojang.serialization.Decoder<A> elementCodec; |
| 38 | ++ |
| 39 | ++ public FieldFallbackDecoder(final String name, final List<String> fallback, final com.mojang.serialization.Decoder<A> elementCodec) { |
| 40 | ++ this.name = name; |
| 41 | ++ this.fallback = fallback; |
| 42 | ++ this.elementCodec = elementCodec; |
| 43 | ++ } |
| 44 | ++ |
| 45 | ++ @Override |
| 46 | ++ public <T> com.mojang.serialization.DataResult<A> decode(final com.mojang.serialization.DynamicOps<T> ops, final com.mojang.serialization.MapLike<T> input) { |
| 47 | ++ T value = input.get(name); |
| 48 | ++ if (value == null) { |
| 49 | ++ for (String fall : fallback) { |
| 50 | ++ value = input.get(fall); |
| 51 | ++ if (value != null) { |
| 52 | ++ break; |
| 53 | ++ } |
| 54 | ++ } |
| 55 | ++ if (value == null) { |
| 56 | ++ return com.mojang.serialization.DataResult.error("No key " + name + " in " + input); |
| 57 | ++ } |
| 58 | ++ } |
| 59 | ++ return elementCodec.parse(ops, value); |
| 60 | ++ } |
| 61 | ++ |
| 62 | ++ @Override |
| 63 | ++ public <T> java.util.stream.Stream<T> keys(final com.mojang.serialization.DynamicOps<T> ops) { |
| 64 | ++ return java.util.stream.Stream.of(ops.createString(name)); |
| 65 | ++ } |
| 66 | ++ |
| 67 | ++ @Override |
| 68 | ++ public boolean equals(final Object o) { |
| 69 | ++ if (this == o) { |
| 70 | ++ return true; |
| 71 | ++ } |
| 72 | ++ if (o == null || getClass() != o.getClass()) { |
| 73 | ++ return false; |
| 74 | ++ } |
| 75 | ++ final FieldFallbackDecoder<?> that = (FieldFallbackDecoder<?>)o; |
| 76 | ++ return java.util.Objects.equals(name, that.name) && java.util.Objects.equals(elementCodec, that.elementCodec) |
| 77 | ++ && java.util.Objects.equals(fallback, that.fallback); |
| 78 | ++ } |
| 79 | ++ |
| 80 | ++ @Override |
| 81 | ++ public int hashCode() { |
| 82 | ++ return java.util.Objects.hash(name, fallback, elementCodec); |
| 83 | ++ } |
| 84 | ++ |
| 85 | ++ @Override |
| 86 | ++ public String toString() { |
| 87 | ++ return "FieldDecoder[" + name + ": " + elementCodec + ']'; |
| 88 | ++ } |
| 89 | ++ } |
| 90 | + } |
| 91 | +diff --git a/src/main/java/net/minecraft/util/valueproviders/IntProvider.java b/src/main/java/net/minecraft/util/valueproviders/IntProvider.java |
| 92 | +index 020a19cd683dd3779c5116d12b3cdcd3b3ca69b4..c81a0eec12436c10869bfdcc21af09173f438331 100644 |
| 93 | +--- a/src/main/java/net/minecraft/util/valueproviders/IntProvider.java |
| 94 | ++++ b/src/main/java/net/minecraft/util/valueproviders/IntProvider.java |
| 95 | +@@ -9,13 +9,44 @@ import net.minecraft.core.Registry; |
| 96 | + |
| 97 | + public abstract class IntProvider { |
| 98 | + private static final Codec<Either<Integer, IntProvider>> CONSTANT_OR_DISPATCH_CODEC = Codec.either(Codec.INT, Registry.INT_PROVIDER_TYPES.dispatch(IntProvider::getType, IntProviderType::codec)); |
| 99 | +- public static final Codec<IntProvider> CODEC = CONSTANT_OR_DISPATCH_CODEC.xmap((either) -> { |
| 100 | ++ public static final Codec<IntProvider> CODEC_REAL = CONSTANT_OR_DISPATCH_CODEC.xmap((either) -> { // Paper - used by CODEC below |
| 101 | + return either.map(ConstantInt::of, (intProvider) -> { |
| 102 | + return intProvider; |
| 103 | + }); |
| 104 | + }, (intProvider) -> { |
| 105 | + return intProvider.getType() == IntProviderType.CONSTANT ? Either.left(((ConstantInt)intProvider).getValue()) : Either.right(intProvider); |
| 106 | + }); |
| 107 | ++ // Paper start |
| 108 | ++ public static final Codec<IntProvider> CODEC = new Codec<>() { |
| 109 | ++ @Override |
| 110 | ++ public <T> DataResult<com.mojang.datafixers.util.Pair<IntProvider, T>> decode(com.mojang.serialization.DynamicOps<T> ops, T input) { |
| 111 | ++ /* |
| 112 | ++ UniformInt: |
| 113 | ++ count -> { (old format) |
| 114 | ++ base, spread |
| 115 | ++ } -> {UniformInt} { (new format & type) |
| 116 | ++ base, base + spread |
| 117 | ++ } */ |
| 118 | ++ |
| 119 | ++ |
| 120 | ++ if (ops.get(input, "base").result().isPresent() && ops.get(input, "spread").result().isPresent()) { |
| 121 | ++ // detected old format |
| 122 | ++ int base = ops.getNumberValue(ops.get(input, "base").result().get()).result().get().intValue(); |
| 123 | ++ int spread = ops.getNumberValue(ops.get(input, "spread").result().get()).result().get().intValue(); |
| 124 | ++ return DataResult.success(new com.mojang.datafixers.util.Pair<>(UniformInt.of(base, base + spread), input)); |
| 125 | ++ } |
| 126 | ++ |
| 127 | ++ // not old format, forward to real codec |
| 128 | ++ return CODEC_REAL.decode(ops, input); |
| 129 | ++ } |
| 130 | ++ |
| 131 | ++ @Override |
| 132 | ++ public <T> DataResult<T> encode(IntProvider input, com.mojang.serialization.DynamicOps<T> ops, T prefix) { |
| 133 | ++ // forward to real codec |
| 134 | ++ return CODEC_REAL.encode(input, ops, prefix); |
| 135 | ++ } |
| 136 | ++ }; |
| 137 | ++ // Paper end |
| 138 | + public static final Codec<IntProvider> NON_NEGATIVE_CODEC = codec(0, Integer.MAX_VALUE); |
| 139 | + public static final Codec<IntProvider> POSITIVE_CODEC = codec(1, Integer.MAX_VALUE); |
| 140 | + |
| 141 | +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java b/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java |
| 142 | +index 05bba5410fbd9f8e333584ccbd65a909f3040322..0cac5869be03bbbfb090c00447f75b4183a06781 100644 |
| 143 | +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java |
| 144 | ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/blockplacers/ColumnPlacer.java |
| 145 | +@@ -10,11 +10,41 @@ import net.minecraft.world.level.LevelAccessor; |
| 146 | + import net.minecraft.world.level.block.state.BlockState; |
| 147 | + |
| 148 | + public class ColumnPlacer extends BlockPlacer { |
| 149 | +- public static final Codec<ColumnPlacer> CODEC = RecordCodecBuilder.create((instance) -> { |
| 150 | ++ public static final Codec<ColumnPlacer> CODEC_REAL = RecordCodecBuilder.create((instance) -> { // Paper - used by CODEC below |
| 151 | + return instance.group(IntProvider.NON_NEGATIVE_CODEC.fieldOf("size").forGetter((columnPlacer) -> { |
| 152 | + return columnPlacer.size; |
| 153 | + })).apply(instance, ColumnPlacer::new); |
| 154 | + }); |
| 155 | ++ // Paper start |
| 156 | ++ public static final Codec<ColumnPlacer> CODEC = new Codec<>() { |
| 157 | ++ @Override |
| 158 | ++ public <T> com.mojang.serialization.DataResult<com.mojang.datafixers.util.Pair<ColumnPlacer, T>> decode(com.mojang.serialization.DynamicOps<T> ops, T input) { |
| 159 | ++ /* |
| 160 | ++ Old format: |
| 161 | ++ min_size, extra_size -> BiasedToBottomInt(min_size, min_size + extra_size) to place @ root.size |
| 162 | ++ */ |
| 163 | ++ if (ops.get(input, "min_size").result().isPresent() && ops.get(input, "extra_size").result().isPresent()) { |
| 164 | ++ // detected old format |
| 165 | ++ int min_size = ops.getNumberValue(ops.get(input, "min_size").result().get()).result().get().intValue(); |
| 166 | ++ int extra_size = ops.getNumberValue(ops.get(input, "extra_size").result().get()).result().get().intValue(); |
| 167 | ++ return com.mojang.serialization.DataResult.success( |
| 168 | ++ new com.mojang.datafixers.util.Pair<>(new ColumnPlacer(net.minecraft.util.valueproviders.BiasedToBottomInt.of( |
| 169 | ++ min_size, min_size + extra_size |
| 170 | ++ )), input) |
| 171 | ++ ); |
| 172 | ++ } |
| 173 | ++ |
| 174 | ++ // not old format, forward to real codec |
| 175 | ++ return CODEC_REAL.decode(ops, input); |
| 176 | ++ } |
| 177 | ++ |
| 178 | ++ @Override |
| 179 | ++ public <T> com.mojang.serialization.DataResult<T> encode(ColumnPlacer input, com.mojang.serialization.DynamicOps<T> ops, T prefix) { |
| 180 | ++ // forward to real codec |
| 181 | ++ return CODEC_REAL.encode(input, ops, prefix); |
| 182 | ++ } |
| 183 | ++ }; |
| 184 | ++ // Paper end |
| 185 | + private final IntProvider size; |
| 186 | + |
| 187 | + public ColumnPlacer(IntProvider size) { |
| 188 | +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java b/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java |
| 189 | +index 5da68897148192905c2747676c1ee2ee649f923f..b990099cf274f8cb0d96c139345cf0bf328affd6 100644 |
| 190 | +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java |
| 191 | ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/configurations/TreeConfiguration.java |
| 192 | +@@ -18,13 +18,13 @@ public class TreeConfiguration implements FeatureConfiguration { |
| 193 | + return treeConfiguration.trunkProvider; |
| 194 | + }), TrunkPlacer.CODEC.fieldOf("trunk_placer").forGetter((treeConfiguration) -> { |
| 195 | + return treeConfiguration.trunkPlacer; |
| 196 | +- }), BlockStateProvider.CODEC.fieldOf("foliage_provider").forGetter((treeConfiguration) -> { |
| 197 | ++ }), net.minecraft.server.MCUtil.fieldWithFallbacks(BlockStateProvider.CODEC, "foliage_provider", "leaves_provider").forGetter((treeConfiguration) -> { // Paper - provide fallback for rename |
| 198 | + return treeConfiguration.foliageProvider; |
| 199 | +- }), BlockStateProvider.CODEC.fieldOf("sapling_provider").forGetter((treeConfiguration) -> { |
| 200 | ++ }), BlockStateProvider.CODEC.optionalFieldOf("sapling_provider", new SimpleStateProvider(Blocks.OAK_SAPLING.defaultBlockState())).forGetter((treeConfiguration) -> { // Paper - provide default - it looks like for now this is OK because it's just used to check canSurvive. Same check happens in 1.16.5 for the default we provide - so it should retain behavior... |
| 201 | + return treeConfiguration.saplingProvider; |
| 202 | + }), FoliagePlacer.CODEC.fieldOf("foliage_placer").forGetter((treeConfiguration) -> { |
| 203 | + return treeConfiguration.foliagePlacer; |
| 204 | +- }), BlockStateProvider.CODEC.fieldOf("dirt_provider").forGetter((treeConfiguration) -> { |
| 205 | ++ }), BlockStateProvider.CODEC.optionalFieldOf("dirt_provider", new SimpleStateProvider(Blocks.DIRT.defaultBlockState())).forGetter((treeConfiguration) -> { // Paper - provide defaults, old data DOES NOT have this key (thankfully ALL OLD DATA used DIRT) |
| 206 | + return treeConfiguration.dirtProvider; |
| 207 | + }), FeatureSize.CODEC.fieldOf("minimum_size").forGetter((treeConfiguration) -> { |
| 208 | + return treeConfiguration.minimumSize; |
0 commit comments