From e879050a33085a38091d53782064a15c6b6badac Mon Sep 17 00:00:00 2001 From: Siphalor Date: Sun, 1 Mar 2026 19:44:42 +0100 Subject: [PATCH] feat(coat-bridge): Add experimental text mapper based on Tweed Serde --- CHANGELOG.md | 1 + .../coat/bridge/api/TweedCoatMappers.java | 7 + .../bridge/impl/TweedCoatMappersImpl.java | 181 ++++++++++++++++++ .../testmod/TweedCoatBridgeTestMod.java | 8 +- 4 files changed, 193 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 180acfe..a73a4de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `networking`: Added module for Minecraft networking. +- `coat-bridge`: Added experimental text mapper based on Tweed Serde. ### Changed - `weaver-pojo-serde-extension`: Slightly changed the `SerdePojoReaderWriterSpec` diff --git a/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/api/TweedCoatMappers.java b/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/api/TweedCoatMappers.java index 71d1b12..cafa988 100644 --- a/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/api/TweedCoatMappers.java +++ b/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/api/TweedCoatMappers.java @@ -5,6 +5,7 @@ import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatMapper; import de.siphalor.tweed5.coat.bridge.impl.TweedCoatMappersImpl; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.jetbrains.annotations.ApiStatus; import java.util.function.Function; @@ -66,4 +67,10 @@ public class TweedCoatMappers { //noinspection unchecked return TweedCoatMappersImpl.convertingTextMapper(new Class[]{valueClass}, textMapper, textParser); } + + @ApiStatus.Experimental + public static TweedCoatMapper serdeTextMapper(Class valueClass) { + //noinspection unchecked + return TweedCoatMappersImpl.serdeTextMapper(new Class[]{valueClass}); + } } diff --git a/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/impl/TweedCoatMappersImpl.java b/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/impl/TweedCoatMappersImpl.java index c939c31..1e67c28 100644 --- a/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/impl/TweedCoatMappersImpl.java +++ b/tweed5-minecraft/coat-bridge/src/main/java/de/siphalor/tweed5/coat/bridge/impl/TweedCoatMappersImpl.java @@ -20,6 +20,13 @@ import de.siphalor.tweed5.coat.bridge.api.mapping.handler.BasicTweedCoatEntryHan import de.siphalor.tweed5.coat.bridge.api.mapping.handler.ConvertingTweedCoatEntryHandler; import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry; +import de.siphalor.tweed5.data.extension.api.ReadWriteExtension; +import de.siphalor.tweed5.data.extension.api.TweedEntryReadException; +import de.siphalor.tweed5.data.extension.api.TweedEntryReader; +import de.siphalor.tweed5.data.extension.api.TweedReadContext; +import de.siphalor.tweed5.dataapi.api.*; +import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration; +import de.siphalor.tweed5.patchwork.api.Patchwork; import lombok.RequiredArgsConstructor; import lombok.Value; import lombok.extern.apachecommons.CommonsLog; @@ -82,6 +89,10 @@ public class TweedCoatMappersImpl { public static TweedCoatMapper COMPOUND_CATEGORY_MAPPER = new CompoundCategoryMapper<>(); + public static TweedCoatMapper serdeTextMapper(Class[] valueClasses) { + return new SerdeTextMapper<>(valueClasses); + } + public static TweedCoatMapper convertingTextMapper( Class[] valueClasses, Function textMapper, @@ -90,6 +101,176 @@ public class TweedCoatMappersImpl { return new ConvertingTextMapper<>(valueClasses, textMapper, textParser); } + @RequiredArgsConstructor + public static class SerdeTextMapper implements TweedCoatMapper { + private final Class[] valueClasses; + + @Override + public TweedCoatEntryMappingResult mapEntry(ConfigEntry entry, TweedCoatEntryMappingContext context) { + if (!anyClassMatches(entry.valueClass(), valueClasses)) { + return TweedCoatEntryMappingResult.notApplicable(); + } + + ReadWriteExtension readWriteExtension = entry.container().extension(ReadWriteExtension.class) + .orElseThrow(() -> new IllegalArgumentException("No ReadWriteExtension registered")); + + return new TweedCoatEntryMappingResult() { + @Override + public boolean isApplicable() { + return true; + } + + @Override + public ConfigInput createInput(TweedCoatEntryCreationContext context) { + return new TextConfigInput(convertToString(context.currentValue())); + } + + @Override + public ConfigEntryHandler createHandler(TweedCoatEntryCreationContext context) { + if (context.parentSaveHandler() == null) { + throw new IllegalArgumentException("No parent save handler provided"); + } + return new ConvertingTweedCoatEntryHandler<>( + new BasicTweedCoatEntryHandler<>(entry, context.defaultValue(), context.parentSaveHandler()), + this::convertToString, + input -> { + try { + TweedEntryReader> reader = + readWriteExtension.getDefinedEntryReader(entry); + Patchwork readExtData = readWriteExtension.createReadWriteContextExtensionsData(); + //noinspection DataFlowIssue + return reader.read( + new TweedDataReader() { + private boolean consumed = false; + + @Override + public TweedDataToken peekToken() throws TweedDataReadException { + if (consumed) { + throw new IllegalStateException("Already consumed"); + } + return new TweedDataToken() { + @Override + public boolean canReadAsString() { + return true; + } + + @Override + public String readAsString() { + return input; + } + }; + } + + @Override + public TweedDataToken readToken() throws TweedDataReadException { + TweedDataToken token = peekToken(); + consumed = true; + return token; + } + + @Override + public void close() { + } + }, entry, new TweedReadContext() { + @Override + public ReadWriteExtension readWriteExtension() { + return readWriteExtension; + } + + @Override + public Patchwork extensionsData() { + return readExtData; + } + } + ); + } catch (TweedEntryReadException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + ); + } + + @Override + public @Nullable ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext context) { + return null; + } + + private String convertToString(T value) { + String[] wrapper = new String[]{""}; + try { + readWriteExtension.write( + new TweedDataVisitor() { + @Override + public void visitNull() { + } + + @Override + public void visitBoolean(boolean value) { + } + + @Override + public void visitByte(byte value) { + } + + @Override + public void visitShort(short value) { + } + + @Override + public void visitInt(int value) { + } + + @Override + public void visitLong(long value) { + } + + @Override + public void visitFloat(float value) { + } + + @Override + public void visitDouble(double value) { + } + + @Override + public void visitString(String value) { + wrapper[0] = value; + } + + @Override + public void visitListStart() { + } + + @Override + public void visitListEnd() { + } + + @Override + public void visitMapStart() { + } + + @Override + public void visitMapEntryKey(String key) { + } + + @Override + public void visitMapEnd() { + } + + @Override + public void visitDecoration(TweedDataDecoration decoration) { + } + }, value, entry, readWriteExtension.createReadWriteContextExtensionsData() + ); + } catch (Exception e) { + log.warn("Failed to serialize value " + value + " to string", e); + } + return wrapper[0]; + } + }; + } + } + @RequiredArgsConstructor public static class ConvertingTextMapper implements TweedCoatMapper { private final Class[] valueClasses; diff --git a/tweed5-minecraft/coat-bridge/src/testmod/java/de/siphalor/tweed5/coat/bridge/testmod/TweedCoatBridgeTestMod.java b/tweed5-minecraft/coat-bridge/src/testmod/java/de/siphalor/tweed5/coat/bridge/testmod/TweedCoatBridgeTestMod.java index b78462b..7baba82 100644 --- a/tweed5-minecraft/coat-bridge/src/testmod/java/de/siphalor/tweed5/coat/bridge/testmod/TweedCoatBridgeTestMod.java +++ b/tweed5-minecraft/coat-bridge/src/testmod/java/de/siphalor/tweed5/coat/bridge/testmod/TweedCoatBridgeTestMod.java @@ -58,9 +58,9 @@ public class TweedCoatBridgeTestMod implements ClientModInitializer { MOD_ID + ".config", GLFW.GLFW_KEY_T, //# if MC_VERSION_NUMBER >= 12109 - KeyMapping.Category.MISC + //- KeyMapping.Category.MISC //# else - //- "key.categories.misc" + "key.categories.misc" //# end )); @@ -69,9 +69,9 @@ public class TweedCoatBridgeTestMod implements ClientModInitializer { private class ScreenKeyBinding extends KeyMapping implements PriorityKeyBinding { //# if MC_VERSION_NUMBER >= 12109 - public ScreenKeyBinding(String name, int key, Category category) { + //- public ScreenKeyBinding(String name, int key, Category category) { //# else - //- public ScreenKeyBinding(String name, int key, String category) { + public ScreenKeyBinding(String name, int key, String category) { //# end super(name, key, category); }