Skip to content

Commit

Permalink
[1.20.1] Update Endec Library usage
Browse files Browse the repository at this point in the history
  • Loading branch information
Dragon-Seeker committed Aug 11, 2024
1 parent e13c7ed commit df5368e
Show file tree
Hide file tree
Showing 34 changed files with 606 additions and 181 deletions.
9 changes: 4 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ repositories {
maven { url "https://maven.ladysnake.org/releases" }

// owo
maven { url "https://maven.wispforest.io" }
maven { url "https://maven.wispforest.io/releases" }

// rei
maven { url "https://maven.shedaniel.me/" }
Expand Down Expand Up @@ -99,10 +99,9 @@ dependencies {

modImplementation include("io.wispforest:worldmesher:${project.worldmesher_version}")

implementation include("io.wispforest:endec:0.1.0-pre.7")
implementation include("io.wispforest.endec:gson:0.1.0-pre.1")
implementation include("io.wispforest.endec:netty:0.1.0-pre.1")
implementation include("io.wispforest.endec:codec:0.1.0-pre.1")
implementation include("io.wispforest:endec:0.1.7")
implementation include("io.wispforest.endec:gson:0.1.4")
implementation include("io.wispforest.endec:netty:0.1.3")

// sky block compatibility
modCompileOnly "maven.modrinth:sodium:${project.sodium_version}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.wispforest.affinity.network.AffinityNetwork;
import io.wispforest.affinity.object.AffinityBlocks;
import io.wispforest.endec.Endec;
import io.wispforest.endec.SerializationContext;
import io.wispforest.endec.annotations.NullableComponent;
import io.wispforest.endec.impl.KeyedEndec;
import io.wispforest.owo.network.ClientAccess;
Expand Down Expand Up @@ -104,7 +105,7 @@ public ActionResult onUse(PlayerEntity player, Hand hand, BlockHitResult hit) {

@Override
protected void writeNbt(NbtCompound nbt) {
nbt.putIfNotNull(LAST_KNOWN_SOURCE_NODE_KEY, this.lastKnownSourceNode);
nbt.putIfNotNull(SerializationContext.empty(), LAST_KNOWN_SOURCE_NODE_KEY, this.lastKnownSourceNode);
nbt.put(LAST_INSERTION_TIMESTAMP_KEY, this.lastInsertionTimestamp);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.wispforest.affinity.misc.util.MathUtil;
import io.wispforest.affinity.object.AffinityBlocks;
import io.wispforest.endec.Endec;
import io.wispforest.endec.SerializationContext;
import io.wispforest.endec.impl.BuiltInEndecs;
import io.wispforest.endec.impl.KeyedEndec;
import io.wispforest.owo.particles.ClientParticles;
Expand Down Expand Up @@ -154,8 +155,8 @@ public Text getCustomName() {

@Override
protected void writeNbt(NbtCompound nbt) {
nbt.putIfNotNull(CUSTOM_NAME_KEY, this.customName);
nbt.putIfNotNull(OWNER_KEY, this.owner);
nbt.putIfNotNull(SerializationContext.empty(), CUSTOM_NAME_KEY, this.customName);
nbt.putIfNotNull(SerializationContext.empty(), OWNER_KEY, this.owner);
nbt.put(GLOBAL_KEY, this.global);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.wispforest.affinity.object.AffinityBlocks;
import io.wispforest.affinity.particle.BezierPathParticleEffect;
import io.wispforest.affinity.particle.ColoredFallingDustParticleEffect;
import io.wispforest.endec.SerializationContext;
import io.wispforest.endec.impl.KeyedEndec;
import io.wispforest.owo.ops.WorldOps;
import io.wispforest.owo.particles.ClientParticles;
Expand Down Expand Up @@ -105,7 +106,7 @@ public void setStreamTargetPos(@Nullable Vec3d streamTargetPos) {
@Override
public NbtCompound toInitialChunkDataNbt() {
var nbt = super.toInitialChunkDataNbt();
nbt.putIfNotNull(STREAM_TARGET_POS_KEY, this.streamTargetPos);
nbt.putIfNotNull(SerializationContext.empty(), STREAM_TARGET_POS_KEY, this.streamTargetPos);
return nbt;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.wispforest.affinity.blockentity.impl;

import io.wispforest.affinity.blockentity.template.SyncedBlockEntity;
import io.wispforest.affinity.endec.CodecUtils;
import io.wispforest.affinity.endec.nbt.NbtEndec;
import io.wispforest.affinity.object.AffinityBlocks;
import io.wispforest.endec.CodecUtils;
import io.wispforest.endec.SerializationContext;
import io.wispforest.endec.impl.KeyedEndec;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
Expand All @@ -18,7 +19,7 @@

public class MangroveBasketBlockEntity extends SyncedBlockEntity {

public static final KeyedEndec<BlockState> CONTAINED_STATE_KEY = CodecUtils.ofCodec(BlockState.CODEC).keyed("ContainedState", (BlockState) null);
public static final KeyedEndec<BlockState> CONTAINED_STATE_KEY = CodecUtils.toEndec(BlockState.CODEC).keyed("ContainedState", (BlockState) null);
public static final KeyedEndec<NbtCompound> CONTAINED_BLOCK_ENTITY_KEY = NbtEndec.COMPOUND.keyed("ContainedBlockEntity", (NbtCompound) null);

private BlockState containedState = null;
Expand Down Expand Up @@ -84,7 +85,7 @@ public void readNbt(NbtCompound nbt) {

@Override
protected void writeNbt(NbtCompound nbt) {
nbt.putIfNotNull(CONTAINED_STATE_KEY, this.containedState);
nbt.putIfNotNull(SerializationContext.empty(), CONTAINED_STATE_KEY, this.containedState);

if (this.containedBlockEntity != null) {
nbt.put(CONTAINED_BLOCK_ENTITY_KEY, this.containedBlockEntity.createNbtWithId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class AffinityOwoWhatsThisPlugin implements OwoWhatsThisPlugin {

static {
PacketBufSerializer.register(PotionMixture.class, (buf, mixture) -> buf.write(PotionMixture.ENDEC, mixture), buf -> buf.read(PotionMixture.ENDEC));
ReflectiveEndecBuilder.INSTANCE.register(PotionMixture.ENDEC, PotionMixture.class);
ReflectiveEndecBuilder.SHARED_INSTANCE.register(PotionMixture.ENDEC, PotionMixture.class);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dev.onyxstudios.cca.api.v3.component.Component;
import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent;
import io.wispforest.affinity.misc.potion.GlowingPotion;
import io.wispforest.endec.SerializationContext;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.DyeColor;
Expand All @@ -23,7 +24,7 @@ public void readFromNbt(NbtCompound tag) {

@Override
public void writeToNbt(NbtCompound tag) {
tag.putIfNotNull(GlowingPotion.COLOR_KEY, this.color);
tag.putIfNotNull(SerializationContext.empty(), GlowingPotion.COLOR_KEY, this.color);
}

public DyeColor color() {
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/io/wispforest/affinity/endec/BuiltInEndecs.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import com.mojang.datafixers.util.Function3;
import io.wispforest.affinity.endec.nbt.NbtEndec;
import io.wispforest.endec.DataToken;
import io.wispforest.endec.Endec;
import io.wispforest.endec.format.json.JsonEndec;
import io.wispforest.endec.SerializationAttributes;
import io.wispforest.endec.format.gson.GsonEndec;
import io.wispforest.endec.impl.StructEndecBuilder;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.minecraft.item.ItemStack;
Expand All @@ -29,23 +29,23 @@ private BuiltInEndecs() {}

public static final Endec<Identifier> IDENTIFIER = Endec.STRING.xmap(Identifier::new, Identifier::toString);
public static final Endec<ItemStack> ITEM_STACK = NbtEndec.COMPOUND.xmap(ItemStack::fromNbt, stack -> stack.writeNbt(new NbtCompound()));
public static final Endec<Text> TEXT = JsonEndec.INSTANCE.xmap(Text.Serializer::fromJson, Text.Serializer::toJsonTree);
public static final Endec<Text> TEXT = GsonEndec.INSTANCE.xmap(Text.Serializer::fromJson, Text.Serializer::toJsonTree);

public static final Endec<Vec3i> VEC3I = vectorEndec("Vec3i", Endec.INT, Vec3i::new, Vec3i::getX, Vec3i::getY, Vec3i::getZ);
public static final Endec<Vec3d> VEC3D = vectorEndec("Vec3d", Endec.DOUBLE, Vec3d::new, Vec3d::getX, Vec3d::getY, Vec3d::getZ);
public static final Endec<Vector3f> VECTOR3F = vectorEndec("Vector3f", Endec.FLOAT, Vector3f::new, Vector3f::x, Vector3f::y, Vector3f::z);

public static final Endec<BlockPos> BLOCK_POS = Endec
.ifToken(
DataToken.HUMAN_READABLE,
.ifAttr(
SerializationAttributes.HUMAN_READABLE,
vectorEndec("BlockPos", Endec.INT, BlockPos::new, BlockPos::getX, BlockPos::getY, BlockPos::getZ)
).orElse(
Endec.LONG.xmap(BlockPos::fromLong, BlockPos::asLong)
);

public static final Endec<ChunkPos> CHUNK_POS = Endec
.ifToken(
DataToken.HUMAN_READABLE,
.ifAttr(
SerializationAttributes.HUMAN_READABLE,
Endec.INT.listOf().validate(ints -> {
if (ints.size() != 2) {
throw new IllegalStateException("ChunkPos array must have two elements");
Expand Down
166 changes: 166 additions & 0 deletions src/main/java/io/wispforest/affinity/endec/CodecUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package io.wispforest.affinity.endec;

import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.*;
import io.wispforest.affinity.endec.edm.EdmOps;
import io.wispforest.affinity.mixin.endec.ForwardingDynamicOpsAccessor;
import io.wispforest.endec.*;
import io.wispforest.endec.format.edm.*;
import net.minecraft.util.Util;
import net.minecraft.util.dynamic.ForwardingDynamicOps;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class CodecUtils {

/**
* Create a new endec serializing the same data as {@code codec}
* <p>
* This method is implemented by converting all data to be (de-)serialized
* to the Endec Data Model data format (hereto-forth to be referred to as EDM)
* which has both an endec ({@link EdmEndec}) and DynamicOps implementation ({@link EdmOps}).
* Since EDM encodes structure using a self-described format's native structural types,
* <b>this means that for JSON and NBT, the created endec's serialized representation is identical
* to that of {@code codec}</b>. In general, for non-self-described formats, the serialized
* representation is a byte array
* <p>
* When decoding, an EDM element is read from the deserializer and then parsed using {@code codec}
* <p>
* When encoding, the value is encoded using {@code codec} to an EDM element which is then
* written into the serializer
*/
public static <T> Endec<T> toEndec(Codec<T> codec) {
return Endec.of(
(ctx, serializer, value) -> {
var ops = createEdmOps(ctx);

EdmEndec.INSTANCE.encode(ctx, serializer, Util.getResult(codec.encodeStart(ops, value), IllegalStateException::new));
},
(ctx, deserializer) -> {
var ops = createEdmOps(ctx);

return Util.getResult(codec.parse(ops, EdmEndec.INSTANCE.decode(ctx, deserializer)), IllegalStateException::new);
}
);
}

//--

/**
* Create a codec serializing the same data as this endec, assuming
* that the serialized format posses the {@code assumedAttributes}
* <p>
* This method is implemented by converting between a given DynamicOps'
* datatype and EDM (see {@link #toEndec(Codec)}) and then encoding/decoding
* from/to an EDM element using the {@link EdmSerializer} and {@link EdmDeserializer}
* <p>
* The serialized representation of a codec created through this method is generally
* identical to that of a codec manually created to describe the same data
*/
public static <T> Codec<T> toCodec(Endec<T> endec, SerializationContext assumedContext) {
return new Codec<>() {
@Override
public <D> DataResult<Pair<T, D>> decode(DynamicOps<D> ops, D input) {
return captureThrows(() -> {
return new Pair<>(endec.decode(createContext(ops, assumedContext), LenientEdmDeserializer.of(ops.convertTo(EdmOps.withoutContext(), input))), input);
});
}

@Override
@SuppressWarnings("unchecked")
public <D> DataResult<D> encode(T input, DynamicOps<D> ops, D prefix) {
return captureThrows(() -> {
return EdmOps.withoutContext().convertTo(ops, endec.encodeFully(createContext(ops, assumedContext), EdmSerializer::of, input));
});
}
};
}

public static <T> Codec<T> toCodec(Endec<T> endec) {
return toCodec(endec, SerializationContext.empty());
}

public static <T> MapCodec<T> toMapCodec(StructEndec<T> structEndec, SerializationContext assumedContext) {
return new MapCodec<>() {
@Override
public <T1> Stream<T1> keys(DynamicOps<T1> ops) {
throw new UnsupportedOperationException("MapCodec generated from StructEndec cannot report keys");
}

@Override
public <T1> DataResult<T> decode(DynamicOps<T1> ops, MapLike<T1> input) {
return captureThrows(() -> {
var map = new HashMap<String, EdmElement<?>>();
input.entries().forEach(pair -> {
map.put(
Util.getResult(ops.getStringValue(pair.getFirst()), s -> new IllegalStateException("Unable to parse key: " + s)),
ops.convertTo(EdmOps.withoutContext(), pair.getSecond())
);
});

return structEndec.decode(createContext(ops, assumedContext), LenientEdmDeserializer.of(EdmElement.wrapMap(map)));
});
}

@Override
public <T1> RecordBuilder<T1> encode(T input, DynamicOps<T1> ops, RecordBuilder<T1> prefix) {
try {
var context = createContext(ops, assumedContext);

var element = structEndec.encodeFully(context, EdmSerializer::of, input).<Map<String, EdmElement<?>>>cast();

var result = prefix;
for (var entry : element.entrySet()) {
result = result.add(entry.getKey(), EdmOps.withoutContext().convertTo(ops, entry.getValue()));
}

return result;
} catch (Exception e) {
return prefix.withErrorsFrom(DataResult.error(e::getMessage, input));
}
}
};
}

public static <T> MapCodec<T> toMapCodec(StructEndec<T> structEndec) {
return toMapCodec(structEndec, SerializationContext.empty());
}

//--

public static SerializationContext createContext(DynamicOps<?> ops, SerializationContext assumedContext) {
var rootOps = ops;
while (rootOps instanceof ForwardingDynamicOps<?>) rootOps = ((ForwardingDynamicOpsAccessor<?>) rootOps).owo$delegate();

var context = rootOps instanceof EdmOps edmOps
? edmOps.capturedContext().and(assumedContext)
: assumedContext;

// if (ops instanceof RegistryOps<?> registryOps) {
// context = context.withAttributes(RegistriesAttribute.tryFromCachedInfoGetter(((RegistryOpsAccessor) registryOps).owo$infoGetter()));
// }

return context;
}

public static DynamicOps<EdmElement<?>> createEdmOps(SerializationContext ctx) {
DynamicOps<EdmElement<?>> ops = EdmOps.withContext(ctx);

// if (ctx.hasAttribute(RegistriesAttribute.REGISTRIES)) {
// ops = RegistryOps.of(ops, ctx.getAttributeValue(RegistriesAttribute.REGISTRIES).infoGetter());
// }

return ops;
}

private static <T> DataResult<T> captureThrows(Supplier<T> action) {
try {
return DataResult.success(action.get());
} catch (Exception e) {
return DataResult.error(e::getMessage);
}
}
}
Loading

0 comments on commit df5368e

Please sign in to comment.