Remove invalid team colors nicely (#12874)

This commit is contained in:
Jake Potrebic
2025-07-20 13:42:24 -07:00
committed by GitHub
parent 782ce950b8
commit a2d37f12fb
3 changed files with 36 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/scores/PlayerTeam.java
+++ b/net/minecraft/world/scores/PlayerTeam.java
@@ -222,7 +_,7 @@
instance -> instance.group(
Codec.STRING.fieldOf("Name").forGetter(PlayerTeam.Packed::name),
ComponentSerialization.CODEC.optionalFieldOf("DisplayName").forGetter(PlayerTeam.Packed::displayName),
- ChatFormatting.COLOR_CODEC.optionalFieldOf("TeamColor").forGetter(PlayerTeam.Packed::color),
+ io.papermc.paper.util.PaperCodecs.lenientCodec("TeamColor", ChatFormatting.COLOR_CODEC).forGetter(PlayerTeam.Packed::color), // Paper - better fail on decode
Codec.BOOL.optionalFieldOf("AllowFriendlyFire", true).forGetter(PlayerTeam.Packed::allowFriendlyFire),
Codec.BOOL.optionalFieldOf("SeeFriendlyInvisibles", true).forGetter(PlayerTeam.Packed::seeFriendlyInvisibles),
ComponentSerialization.CODEC.optionalFieldOf("MemberNamePrefix", CommonComponents.EMPTY).forGetter(PlayerTeam.Packed::memberNamePrefix),

View File

@@ -1,13 +1,18 @@
package io.papermc.paper.util; package io.papermc.paper.util;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult; import com.mojang.serialization.DataResult;
import com.mojang.serialization.Decoder; import com.mojang.serialization.Decoder;
import com.mojang.serialization.DynamicOps; import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.RecordBuilder;
import com.mojang.serialization.codecs.OptionalFieldCodec;
import io.papermc.paper.adventure.AdventureCodecs; import io.papermc.paper.adventure.AdventureCodecs;
import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryAccess;
import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.TypedKey; import io.papermc.paper.registry.TypedKey;
import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
@@ -19,6 +24,25 @@ import org.jspecify.annotations.NullMarked;
@NullMarked @NullMarked
public final class PaperCodecs { public final class PaperCodecs {
/**
* This codec is lenient on decoding and encoding compared to native OptionalFieldCodec
* which only has options to be lenient on decoding.
*/
public static <M> MapCodec<Optional<M>> lenientCodec(final String name, final Codec<M> codec) {
return new OptionalFieldCodec<>(name, codec, true) {
@Override
public <T> RecordBuilder<T> encode(final Optional<M> input, final DynamicOps<T> ops, final RecordBuilder<T> prefix) {
if (input.isPresent()) {
final DataResult<T> result = codec.encodeStart(ops, input.get());
if (!result.isError()) {
return prefix.add(name, result);
}
}
return prefix;
}
};
}
public static <A extends Keyed, M> Decoder<A> registryFileDecoderFor(final Decoder<? extends M> directNmsDecoder, final Function<? super Holder<M>, A> directHolderConverter, final RegistryKey<A> registryKey, final boolean allowInline) { // TODO remove Keyed public static <A extends Keyed, M> Decoder<A> registryFileDecoderFor(final Decoder<? extends M> directNmsDecoder, final Function<? super Holder<M>, A> directHolderConverter, final RegistryKey<A> registryKey, final boolean allowInline) { // TODO remove Keyed
final Decoder.Terminal<A> terminalDecoder = directNmsDecoder.map(nms -> directHolderConverter.apply(Holder.direct(nms))).terminal(); final Decoder.Terminal<A> terminalDecoder = directNmsDecoder.map(nms -> directHolderConverter.apply(Holder.direct(nms))).terminal();
return Decoder.ofTerminal(new Decoder.Terminal<>() { return Decoder.ofTerminal(new Decoder.Terminal<>() {

View File

@@ -149,6 +149,7 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
@Override @Override
public void setColor(ChatColor color) { public void setColor(ChatColor color) {
Preconditions.checkArgument(color != null, "Color cannot be null"); Preconditions.checkArgument(color != null, "Color cannot be null");
Preconditions.checkArgument(!color.isFormat(), "Color must be a color not a format");
this.checkState(); this.checkState();
this.team.setColor(CraftChatMessage.getColor(color)); this.team.setColor(CraftChatMessage.getColor(color));