diff --git a/src/main/java/io/wispforest/owo/serialization/StructEndec.java b/src/main/java/io/wispforest/owo/serialization/StructEndec.java
index af41932c..76b645c0 100644
--- a/src/main/java/io/wispforest/owo/serialization/StructEndec.java
+++ b/src/main/java/io/wispforest/owo/serialization/StructEndec.java
@@ -1,9 +1,22 @@
package io.wispforest.owo.serialization;
-import io.wispforest.owo.serialization.endec.StructEndecBuilder;
+import com.mojang.serialization.*;
+import io.wispforest.owo.serialization.format.edm.EdmDeserializer;
+import io.wispforest.owo.serialization.format.edm.EdmElement;
+import io.wispforest.owo.serialization.format.edm.EdmOps;
+import io.wispforest.owo.serialization.format.edm.EdmSerializer;
+import net.minecraft.util.Util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Stream;
/**
- * Helper Interface for Structs that do not conform to the {@link StructEndecBuilder} format
+ * Marker and template interface for all endecs which serialize structs
+ *
+ * Every such endec should extend this interface to profit from the implementation of {@link #mapCodec()}
+ * and composability which allows {@link Endec#dispatchedStruct(Function, Function, Endec, String)} to work
*/
public interface StructEndec extends Endec {
@@ -22,4 +35,49 @@ default void encode(Serializer> serializer, T value) {
default T decode(Deserializer> deserializer) {
return this.decodeStruct(deserializer.struct());
}
+
+ default MapCodec mapCodec() {
+ return new MapCodec<>() {
+ @Override
+ public Stream keys(DynamicOps ops) {
+ throw new UnsupportedOperationException("MapCodec generated from StructEndec cannot report keys");
+ }
+
+ @Override
+ public DataResult decode(DynamicOps ops, MapLike input) {
+ try {
+ var map = new HashMap>();
+ input.entries().forEach(pair -> {
+ map.put(
+ Util.getResult(
+ ops.getStringValue(pair.getFirst()),
+ s -> new IllegalStateException("Unable to parse key: " + s)
+ ),
+ ops.convertTo(EdmOps.INSTANCE, pair.getSecond())
+ );
+ });
+
+ return DataResult.success(StructEndec.this.decode(new EdmDeserializer(EdmElement.wrapMap(map))));
+ } catch (Exception e) {
+ return DataResult.error(e::getMessage);
+ }
+ }
+
+ @Override
+ public RecordBuilder encode(T input, DynamicOps ops, RecordBuilder prefix) {
+ try {
+ var element = StructEndec.this.encodeFully(EdmSerializer::new, input).