feat(coat-bridge): Add experimental text mapper based on Tweed Serde

This commit is contained in:
2026-03-01 19:44:42 +01:00
parent 7673399f3e
commit e879050a33
4 changed files with 193 additions and 4 deletions

View File

@@ -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`

View File

@@ -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 <T> TweedCoatMapper<T> serdeTextMapper(Class<T> valueClass) {
//noinspection unchecked
return TweedCoatMappersImpl.serdeTextMapper(new Class[]{valueClass});
}
}

View File

@@ -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<Object> COMPOUND_CATEGORY_MAPPER = new CompoundCategoryMapper<>();
public static <T> TweedCoatMapper<T> serdeTextMapper(Class<T>[] valueClasses) {
return new SerdeTextMapper<>(valueClasses);
}
public static <T> TweedCoatMapper<T> convertingTextMapper(
Class<T>[] valueClasses,
Function<T, String> textMapper,
@@ -90,6 +101,176 @@ public class TweedCoatMappersImpl {
return new ConvertingTextMapper<>(valueClasses, textMapper, textParser);
}
@RequiredArgsConstructor
public static class SerdeTextMapper<T> implements TweedCoatMapper<T> {
private final Class<T>[] valueClasses;
@Override
public TweedCoatEntryMappingResult<T, ?> mapEntry(ConfigEntry<T> 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<T, String>() {
@Override
public boolean isApplicable() {
return true;
}
@Override
public ConfigInput<String> createInput(TweedCoatEntryCreationContext<T> context) {
return new TextConfigInput(convertToString(context.currentValue()));
}
@Override
public ConfigEntryHandler<String> createHandler(TweedCoatEntryCreationContext<T> 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<T, ConfigEntry<T>> 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<T> 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<T> implements TweedCoatMapper<T> {
private final Class<T>[] valueClasses;

View File

@@ -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);
}