Skip to content

Commit f36645f

Browse files
committed
Fix Codec log spam
Mojang did NOT add dataconverters for world gen configurations that they CHANGED. So, the codec fails to parse old data. This fixes two instances: - IntProvider is new and Mojang did not account for old data. Thankfully, only ColumnPlace needed to be special cased. - TreeConfiguration had changes. Thankfully, they were only renames for one value and thankfully defaults could be provided for two new values (WITHOUT changing behavior).
1 parent ed5100f commit f36645f

File tree

1 file changed

+208
-0
lines changed

1 file changed

+208
-0
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
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

Comments
 (0)