Skip to content

Instantly share code, notes, and snippets.

@kvverti
Created October 18, 2020 19:26
Show Gist options
  • Save kvverti/dec17e824922e1974313b8beadc621c5 to your computer and use it in GitHub Desktop.
Save kvverti/dec17e824922e1974313b8beadc621c5 to your computer and use it in GitHub Desktop.
Extending Codecs with Mixin
[15:18:46] [main/INFO] (Minecraft) [STDOUT]: Injected field: 47
package robosky.uplands.mixin;
import java.util.function.Function;
import com.mojang.datafixers.kinds.App;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import net.minecraft.world.gen.surfacebuilder.TernarySurfaceConfig;
@Mixin(TernarySurfaceConfig.class)
public abstract class TernarySurfaceConfigMixin {
// injected field(s)
@Unique
private int myInteger = 3;
// codec modification
// target the `RecordCodecBuilder.create(...)` call
// generics are extra disgusting, see DFU docs for more info
@Dynamic("Static init")
@ModifyArg(
method = "<clinit>",
index = 0,
at = @At(
value = "INVOKE",
target = "Lcom/mojang/serialization/codecs/RecordCodecBuilder;create(Ljava/util/function/Function;)Lcom/mojang/serialization/Codec;",
remap = false
)
)
private static Function<RecordCodecBuilder.Instance<TernarySurfaceConfig>, ? extends App<RecordCodecBuilder.Mu<TernarySurfaceConfig>, TernarySurfaceConfig>>
extendCodec(Function<RecordCodecBuilder.Instance<TernarySurfaceConfig>, ? extends App<RecordCodecBuilder.Mu<TernarySurfaceConfig>, TernarySurfaceConfig>> fields) {
MapCodec<TernarySurfaceConfig> mapCodec = RecordCodecBuilder.mapCodec(fields);
return inst -> inst.group(
// preserve the original fields
mapCodec.forGetter(Function.identity()),
// inject our new field
// use optionalFieldOf so that vanilla JSON configs still deserialize properly
Codec.INT.optionalFieldOf("myInt", 3).forGetter(cfg -> ((TernarySurfaceConfigMixin)(Object)cfg).myInteger)
).apply(inst, (cfg, i) -> {
// set additional fields in cfg, then return it
((TernarySurfaceConfigMixin)(Object)cfg).myInteger = i;
System.out.println("Injected field: " + i);
return cfg;
});
}
}
{
"type": "$modid:uplands_surface_builder",
"config": {
"top_material": {
"Name": "$modid:uplander_grass"
},
"under_material": {
"Name": "$modid:uplander_dirt"
},
"underwater_material": {
"Name": "$modid:uplander_dirt"
},
"myInt": 47
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment