[coat-bridge] Implement first version of Tweed Coat bridge
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class ConfigScreenCreateParams<T> {
|
||||
private final ConfigEntry<T> rootEntry;
|
||||
private final T currentValue;
|
||||
private final T defaultValue;
|
||||
private final Component title;
|
||||
private final String translationKeyPrefix;
|
||||
private final Consumer<T> saveHandler;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TweedCoatAttributes {
|
||||
public static final String BACKGROUND_TEXTURE = "backgroundTexture";
|
||||
public static final String TRANSLATION_KEY = "translationKey";
|
||||
public static final String ENUM_TRANSLATION_KEY = "enumTranslationKey";
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api;
|
||||
|
||||
import de.siphalor.coat.screen.ConfigScreen;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatMapper;
|
||||
import de.siphalor.tweed5.coat.bridge.impl.TweedCoatBridgeExtensionImpl;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
|
||||
public interface TweedCoatBridgeExtension extends TweedExtension {
|
||||
Class<? extends TweedCoatBridgeExtension> DEFAULT = TweedCoatBridgeExtensionImpl.class;
|
||||
String EXTENSION_ID = "coat-bridge";
|
||||
|
||||
//static <T> Function<ConfigEntry<T>, ConfigScreen> createConfigScreen(T value) {
|
||||
// return configEntry -> configEntry.container().extension(TweedCoatBridgeExtension.class)
|
||||
// .map(extension -> extension.createConfigScreen(configEntry, value))
|
||||
// .orElseThrow(() -> new IllegalStateException("No TweedCoatBridgeExtension present"));
|
||||
//}
|
||||
|
||||
void addMapper(TweedCoatMapper<?> mapper);
|
||||
|
||||
<T> ConfigScreen createConfigScreen(ConfigScreenCreateParams<T> params);
|
||||
|
||||
@Override
|
||||
default String getId() {
|
||||
return EXTENSION_ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api;
|
||||
|
||||
import de.siphalor.coat.util.EnumeratedMaterial;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatMapper;
|
||||
import de.siphalor.tweed5.coat.bridge.impl.TweedCoatMappersImpl;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TweedCoatMappers {
|
||||
public static TweedCoatMapper<Byte> byteTextMapper() {
|
||||
return TweedCoatMappersImpl.BYTE_TEXT_MAPPER;
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<Short> shortTextMapper() {
|
||||
return TweedCoatMappersImpl.SHORT_TEXT_MAPPER;
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<Integer> integerTextMapper() {
|
||||
return TweedCoatMappersImpl.INTEGER_TEXT_MAPPER;
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<Long> longTextMapper() {
|
||||
return TweedCoatMappersImpl.LONG_TEXT_MAPPER;
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<Float> floatTextMapper() {
|
||||
return TweedCoatMappersImpl.FLOAT_TEXT_MAPPER;
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<Double> doubleTextMapper() {
|
||||
return TweedCoatMappersImpl.DOUBLE_TEXT_MAPPER;
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<Boolean> booleanCheckboxMapper() {
|
||||
return TweedCoatMappersImpl.BOOLEAN_CHECKBOX_MAPPER;
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<String> stringTextMapper() {
|
||||
return TweedCoatMappersImpl.STRING_TEXT_MAPPER;
|
||||
}
|
||||
|
||||
public static <T extends Enum<T>> TweedCoatMapper<T> enumCycleButtonMapper() {
|
||||
//noinspection unchecked
|
||||
return (TweedCoatMapper<T>) TweedCoatMappersImpl.ENUM_CYCLE_BUTTON_MAPPER;
|
||||
}
|
||||
|
||||
public static <T> TweedCoatMapper<T> enumeratedMaterialCycleButtonMapper(
|
||||
Class<T> valueClass,
|
||||
EnumeratedMaterial<T> material
|
||||
) {
|
||||
return new TweedCoatMappersImpl.EnumeratedMaterialCycleButtonMapper<>(valueClass, material);
|
||||
}
|
||||
|
||||
public static TweedCoatMapper<Object> compoundCategoryMapper() {
|
||||
return TweedCoatMappersImpl.COMPOUND_CATEGORY_MAPPER;
|
||||
}
|
||||
|
||||
public static <T> TweedCoatMapper<T> convertingTextMapper(
|
||||
Class<T> valueClass,
|
||||
Function<T, String> textMapper,
|
||||
Function<String, T> textParser
|
||||
) {
|
||||
//noinspection unchecked
|
||||
return TweedCoatMappersImpl.convertingTextMapper(new Class[]{valueClass}, textMapper, textParser);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TweedCoatMappingUtils {
|
||||
public static MutableComponent translatableComponentWithFallback(String translationKey, @Nullable String fallback) {
|
||||
return Component.translatableWithFallback(translationKey, fallback == null ? "" : fallback);
|
||||
// FIXME
|
||||
//if (I18n.exists(translationKey)) {
|
||||
// return Component.translatable(translationKey);
|
||||
//} else if (fallback != null) {
|
||||
// return Component.literal(fallback);
|
||||
//} else {
|
||||
// return Component.empty();
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Builder
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class TweedCoatEntryCreationContext<T> {
|
||||
private final ConfigEntry<T> entry;
|
||||
private final T currentValue;
|
||||
private final T defaultValue;
|
||||
private final @Nullable Consumer<T> parentSaveHandler;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public
|
||||
class TweedCoatEntryMappingContext {
|
||||
@Getter(AccessLevel.NONE)
|
||||
private final TweedCoatMapper<?> mappingDelegate;
|
||||
private final String entryName;
|
||||
private final String translationKeyPrefix;
|
||||
private final @Nullable Class<?> parentWidgetClass;
|
||||
|
||||
public static Builder rootBuilder(TweedCoatMapper<?> mappingDelegate, String translationKeyPrefix) {
|
||||
return new Builder(mappingDelegate, "root", translationKeyPrefix);
|
||||
}
|
||||
|
||||
public <T> TweedCoatEntryMappingResult<T, ?> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext context) {
|
||||
//noinspection unchecked,rawtypes
|
||||
return (TweedCoatEntryMappingResult<T, ?>) mappingDelegate.mapEntry((ConfigEntry) entry, context);
|
||||
}
|
||||
|
||||
public Builder subContextBuilder(String entryName) {
|
||||
return new Builder(mappingDelegate, entryName, translationKeyPrefix + "." + entryName);
|
||||
}
|
||||
|
||||
@Setter
|
||||
public static class Builder {
|
||||
private final TweedCoatMapper<?> mappingDelegate;
|
||||
private final String entryName;
|
||||
private String translationKeyPrefix;
|
||||
private @Nullable Class<?> parentWidgetClass;
|
||||
|
||||
private Builder(TweedCoatMapper<?> mappingDelegate, String entryName, String translationKeyPrefix) {
|
||||
this.mappingDelegate = mappingDelegate;
|
||||
this.entryName = entryName;
|
||||
this.translationKeyPrefix = translationKeyPrefix;
|
||||
}
|
||||
|
||||
public TweedCoatEntryMappingContext build() {
|
||||
return new TweedCoatEntryMappingContext(mappingDelegate, entryName, translationKeyPrefix, parentWidgetClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping;
|
||||
|
||||
import de.siphalor.coat.handler.ConfigEntryHandler;
|
||||
import de.siphalor.coat.input.ConfigInput;
|
||||
import de.siphalor.coat.screen.ConfigContentWidget;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The result of a {@link TweedCoatMapper}.
|
||||
* <br />
|
||||
* There are three types of results:
|
||||
* <ol>
|
||||
* <li>The mapper isn't applicable to the entry.</li>
|
||||
* <li>The mapper is applicable and provides methods for creating
|
||||
* {@link ConfigInput} and {@link ConfigEntryHandler} instances for the config entry.</li>
|
||||
* FIXME
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
* @param <T> the actual (Tweed) type of the entry
|
||||
* @param <U> the UI (coat) type of the entry
|
||||
*/
|
||||
public interface TweedCoatEntryMappingResult<T, U> {
|
||||
TweedCoatEntryMappingResult<?, ?> NOT_APPLICABLE = new TweedCoatEntryMappingResult<Object, Object>() {
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigInput<Object> createInput(TweedCoatEntryCreationContext<Object> context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigEntryHandler<Object> createHandler(TweedCoatEntryCreationContext<Object> context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext<Object> context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static <T, U> TweedCoatEntryMappingResult<T, U> notApplicable() {
|
||||
//noinspection unchecked
|
||||
return (TweedCoatEntryMappingResult<T, U>) NOT_APPLICABLE;
|
||||
}
|
||||
|
||||
boolean isApplicable();
|
||||
|
||||
@Nullable ConfigInput<U> createInput(TweedCoatEntryCreationContext<T> context);
|
||||
|
||||
@Nullable ConfigEntryHandler<U> createHandler(TweedCoatEntryCreationContext<T> context);
|
||||
|
||||
@Nullable ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext<T> context);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
|
||||
public interface TweedCoatMapper<T> {
|
||||
TweedCoatEntryMappingResult<T, ?> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext context);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping.handler;
|
||||
|
||||
import de.siphalor.coat.handler.ConfigEntryHandler;
|
||||
import de.siphalor.coat.handler.Message;
|
||||
import de.siphalor.tweed5.coat.bridge.impl.TweedCoatMappersImpl;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssues;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BasicTweedCoatEntryHandler<T extends @Nullable Object> implements ConfigEntryHandler<T> {
|
||||
protected final ConfigEntry<T> configEntry;
|
||||
protected final T defaultValue;
|
||||
protected final Consumer<T> parentSaveHandler;
|
||||
protected final ValidationExtension validationExtension;
|
||||
|
||||
public BasicTweedCoatEntryHandler(ConfigEntry<T> configEntry, T defaultValue, Consumer<T> parentSaveHandler) {
|
||||
this.configEntry = configEntry;
|
||||
this.defaultValue = defaultValue;
|
||||
this.parentSaveHandler = parentSaveHandler;
|
||||
this.validationExtension = configEntry.container().extension(ValidationExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException("No validation extension registered"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getDefault() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Message> getMessages(T value) {
|
||||
ValidationIssues issues = validationExtension.validate(configEntry, value);
|
||||
return issues.issuesByPath().values().stream()
|
||||
.flatMap(entryIssues -> entryIssues.issues().stream())
|
||||
.map(issue -> new Message(
|
||||
mapLevel(issue.level()),
|
||||
Component.literal(issue.message())
|
||||
))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Message.Level mapLevel(ValidationIssueLevel level) {
|
||||
switch (level) {
|
||||
case INFO:
|
||||
return Message.Level.INFO;
|
||||
case WARN:
|
||||
return Message.Level.WARNING;
|
||||
case ERROR:
|
||||
return Message.Level.ERROR;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown validation issue level " + level);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(T value) {
|
||||
parentSaveHandler.accept(processSaveValue(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component asText(T value) {
|
||||
return Component.literal(Objects.toString(value));
|
||||
}
|
||||
|
||||
protected T processSaveValue(T value) {
|
||||
ValidationResult<T> validationResult = validationExtension.validateValueFlat(configEntry, value);
|
||||
if (validationResult.hasError()) {
|
||||
TweedCoatMappersImpl.log.warn(
|
||||
"Failed to save value " + value + " because of issues: " + validationResult.issues()
|
||||
+ "; using default: " + defaultValue + " instead"
|
||||
);
|
||||
return defaultValue;
|
||||
}
|
||||
return validationResult.value();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping.handler;
|
||||
|
||||
import de.siphalor.coat.handler.ConfigEntryHandler;
|
||||
import de.siphalor.coat.handler.Message;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@CommonsLog
|
||||
public class ConvertingTweedCoatEntryHandler<T extends @Nullable Object, C> implements ConfigEntryHandler<C> {
|
||||
private static final String CONVERSION_EXCEPTION_TEXT_KEY = "tweed5_coat_bridge.handler.conversion.exception";
|
||||
|
||||
private final ConfigEntryHandler<T> inner;
|
||||
private final Function<T, C> toCoatMapper;
|
||||
private final Function<C, T> fromCoatMapper;
|
||||
|
||||
@Override
|
||||
public C getDefault() {
|
||||
return toCoatMapper.apply(inner.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Message> getMessages(C value) {
|
||||
try {
|
||||
T innerValue = fromCoatMapper.apply(value);
|
||||
return inner.getMessages(innerValue);
|
||||
} catch (Exception e) {
|
||||
return Collections.singletonList(new Message(
|
||||
Message.Level.ERROR,
|
||||
Component.translatable(CONVERSION_EXCEPTION_TEXT_KEY, e.getMessage())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(C value) {
|
||||
inner.save(convertSaveValue(value));
|
||||
}
|
||||
|
||||
protected T convertSaveValue(C value) {
|
||||
try {
|
||||
return fromCoatMapper.apply(value);
|
||||
} catch (Exception e) {
|
||||
log.warn(
|
||||
"Failed to convert value "
|
||||
+ value
|
||||
+ " for saving, using default: "
|
||||
+ inner.getDefault(), e
|
||||
);
|
||||
return inner.getDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component asText(C value) {
|
||||
return Component.literal(Objects.toString(value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping.handler;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package de.siphalor.tweed5.coat.bridge.api.mapping;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package de.siphalor.tweed5.coat.bridge.api;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.siphalor.tweed5.coat.bridge.impl;
|
||||
|
||||
import de.siphalor.coat.util.EnumeratedMaterial;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.translatableComponentWithFallback;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class CoatEnumMaterial<T> implements EnumeratedMaterial<T> {
|
||||
private final Class<T> enumClass;
|
||||
private final String textTranslationKeyPrefix;
|
||||
|
||||
@Override
|
||||
public T[] values() {
|
||||
return enumClass.getEnumConstants();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component asText(T value) {
|
||||
return translatableComponentWithFallback(
|
||||
textTranslationKeyPrefix + "." + value.toString().toLowerCase(Locale.ROOT),
|
||||
value.toString()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package de.siphalor.tweed5.coat.bridge.impl;
|
||||
|
||||
import de.siphalor.coat.screen.ConfigContentWidget;
|
||||
import de.siphalor.coat.screen.ConfigScreen;
|
||||
import de.siphalor.tweed5.coat.bridge.api.ConfigScreenCreateParams;
|
||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatBridgeExtension;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatEntryCreationContext;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatEntryMappingContext;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatEntryMappingResult;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatMapper;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TweedCoatBridgeExtensionImpl implements TweedCoatBridgeExtension {
|
||||
private final PatchworkPartAccess<CustomData> customDataAccess;
|
||||
private final List<TweedCoatMapper<?>> mappers = new ArrayList<>();
|
||||
|
||||
public TweedCoatBridgeExtensionImpl(TweedExtensionSetupContext setupContext) {
|
||||
customDataAccess = setupContext.registerEntryExtensionData(CustomData.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMapper(TweedCoatMapper<?> mapper) {
|
||||
mappers.add(mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ConfigScreen createConfigScreen(ConfigScreenCreateParams<T> params) {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
|
||||
TweedCoatEntryMappingContext mappingContext = TweedCoatEntryMappingContext.rootBuilder(
|
||||
this::mapEntry,
|
||||
params.translationKeyPrefix()
|
||||
).parentWidgetClass(ConfigScreen.class).build();
|
||||
|
||||
TweedCoatEntryMappingResult<T, ?> rootResult = mapEntry(params.rootEntry(), mappingContext);
|
||||
if (!rootResult.isApplicable()) {
|
||||
throw new IllegalStateException("Failed to map root entry");
|
||||
}
|
||||
|
||||
T value = params.rootEntry().deepCopy(params.currentValue());
|
||||
TweedCoatEntryCreationContext<T> creationContext = TweedCoatEntryCreationContext.<T>builder()
|
||||
.entry(params.rootEntry())
|
||||
.currentValue(value)
|
||||
.defaultValue(params.defaultValue())
|
||||
.build();
|
||||
|
||||
ConfigContentWidget contentWidget = rootResult.createContentWidget(creationContext);
|
||||
if (contentWidget == null) {
|
||||
throw new IllegalStateException("Failed to create root content widget");
|
||||
}
|
||||
|
||||
ConfigScreen configScreen = new ConfigScreen(
|
||||
minecraft.screen, params.title(), Collections.singletonList(contentWidget)
|
||||
);
|
||||
configScreen.setOnSave(() -> params.saveHandler().accept(value));
|
||||
return configScreen;
|
||||
}
|
||||
|
||||
private <T> TweedCoatEntryMappingResult<T, ?> mapEntry(
|
||||
ConfigEntry<T> entry,
|
||||
TweedCoatEntryMappingContext context
|
||||
) {
|
||||
for (TweedCoatMapper<?> mapper : mappers) {
|
||||
//noinspection rawtypes,unchecked
|
||||
TweedCoatEntryMappingResult<T, ?> result = mapper.mapEntry((ConfigEntry) entry, context);
|
||||
if (result.isApplicable()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return TweedCoatEntryMappingResult.notApplicable();
|
||||
}
|
||||
|
||||
private static class CustomData {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
package de.siphalor.tweed5.coat.bridge.impl;
|
||||
|
||||
import de.siphalor.coat.handler.ConfigEntryHandler;
|
||||
import de.siphalor.coat.input.CheckBoxConfigInput;
|
||||
import de.siphalor.coat.input.ConfigInput;
|
||||
import de.siphalor.coat.input.CycleButtonConfigInput;
|
||||
import de.siphalor.coat.input.TextConfigInput;
|
||||
import de.siphalor.coat.list.complex.ConfigCategoryWidget;
|
||||
import de.siphalor.coat.list.entry.ConfigCategoryConfigEntry;
|
||||
import de.siphalor.coat.screen.ConfigContentWidget;
|
||||
import de.siphalor.coat.util.EnumeratedMaterial;
|
||||
import de.siphalor.tweed5.attributesextension.api.AttributesExtension;
|
||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatAttributes;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatEntryCreationContext;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatEntryMappingContext;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatEntryMappingResult;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.TweedCoatMapper;
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.handler.BasicTweedCoatEntryHandler;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.siphalor.tweed5.coat.bridge.api.TweedCoatMappingUtils.translatableComponentWithFallback;
|
||||
|
||||
@CommonsLog
|
||||
@SuppressWarnings("unchecked")
|
||||
public class TweedCoatMappersImpl {
|
||||
public static TweedCoatMapper<Byte> BYTE_TEXT_MAPPER = convertingTextMapper(
|
||||
new Class[]{Byte.class, byte.class},
|
||||
value -> Byte.toString(value),
|
||||
Byte::parseByte
|
||||
);
|
||||
public static TweedCoatMapper<Short> SHORT_TEXT_MAPPER = convertingTextMapper(
|
||||
new Class[]{Short.class, short.class},
|
||||
value -> Short.toString(value),
|
||||
Short::parseShort
|
||||
);
|
||||
public static TweedCoatMapper<Integer> INTEGER_TEXT_MAPPER = convertingTextMapper(
|
||||
new Class[]{Integer.class, int.class},
|
||||
value -> Integer.toString(value),
|
||||
Integer::parseInt
|
||||
);
|
||||
public static TweedCoatMapper<Long> LONG_TEXT_MAPPER = convertingTextMapper(
|
||||
new Class[]{Long.class, long.class},
|
||||
value -> Long.toString(value),
|
||||
Long::parseLong
|
||||
);
|
||||
public static TweedCoatMapper<Float> FLOAT_TEXT_MAPPER = convertingTextMapper(
|
||||
new Class[]{Float.class, float.class},
|
||||
value -> Float.toString(value),
|
||||
Float::parseFloat
|
||||
);
|
||||
public static TweedCoatMapper<Double> DOUBLE_TEXT_MAPPER = convertingTextMapper(
|
||||
new Class[]{Double.class, double.class},
|
||||
value -> Double.toString(value),
|
||||
Double::parseDouble
|
||||
);
|
||||
public static TweedCoatMapper<Boolean> BOOLEAN_CHECKBOX_MAPPER
|
||||
= new SimpleMapper<Boolean>(new Class[]{Boolean.class, boolean.class}, CheckBoxConfigInput::new);
|
||||
|
||||
public static TweedCoatMapper<String> STRING_TEXT_MAPPER = new SimpleMapper<String>(
|
||||
new Class[]{String.class},
|
||||
TextConfigInput::new
|
||||
);
|
||||
|
||||
public static TweedCoatMapper<Enum<?>> ENUM_CYCLE_BUTTON_MAPPER = new EnumCycleButtonMapper<>();
|
||||
|
||||
public static TweedCoatMapper<Object> COMPOUND_CATEGORY_MAPPER = new CompoundCategoryMapper<>();
|
||||
|
||||
public static <T> TweedCoatMapper<T> convertingTextMapper(
|
||||
Class<T>[] valueClasses,
|
||||
Function<T, String> textMapper,
|
||||
Function<String, T> textParser
|
||||
) {
|
||||
return new ConvertingTextMapper<>(valueClasses, textMapper, textParser);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public static class ConvertingTextMapper<T> implements TweedCoatMapper<T> {
|
||||
private final Class<T>[] valueClasses;
|
||||
private final Function<T, String> textMapper;
|
||||
private final Function<String, T> textParser;
|
||||
|
||||
@Override
|
||||
public TweedCoatEntryMappingResult<T, String> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext context) {
|
||||
boolean applicable = anyClassMatches(entry.valueClass(), valueClasses);
|
||||
|
||||
return new TweedCoatEntryMappingResult<T, String>() {
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
return applicable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigInput<String> createInput(TweedCoatEntryCreationContext<T> context) {
|
||||
return new TextConfigInput(textMapper.apply(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<>(
|
||||
context.entry(), context.defaultValue(), context.parentSaveHandler()
|
||||
),
|
||||
textMapper,
|
||||
textParser
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext<T> context) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public static class EnumeratedMaterialCycleButtonMapper<T> implements TweedCoatMapper<T> {
|
||||
private final Class<T> valueClass;
|
||||
private final EnumeratedMaterial<T> material;
|
||||
|
||||
@Override
|
||||
public TweedCoatEntryMappingResult<T, ?> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext context) {
|
||||
if (!valueClass.isAssignableFrom(entry.valueClass())) {
|
||||
return TweedCoatEntryMappingResult.notApplicable();
|
||||
}
|
||||
|
||||
return new CycleButtonMappingResult<>(material);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EnumCycleButtonMapper<T extends Enum<?>> implements TweedCoatMapper<T> {
|
||||
@Override
|
||||
public TweedCoatEntryMappingResult<T, ?> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext context) {
|
||||
if (!Enum.class.isAssignableFrom(entry.valueClass())) {
|
||||
return TweedCoatEntryMappingResult.notApplicable();
|
||||
}
|
||||
Class<T> enumClass = entry.valueClass();
|
||||
|
||||
String translationKeyPrefix = entry.container().extension(AttributesExtension.class)
|
||||
.map(extension -> extension.getAttributeValue(entry, TweedCoatAttributes.ENUM_TRANSLATION_KEY))
|
||||
.orElse(enumClass.getPackage().getName());
|
||||
|
||||
CoatEnumMaterial<T> material = new CoatEnumMaterial<>(enumClass, translationKeyPrefix + ".");
|
||||
return new CycleButtonMappingResult<>(material);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class CycleButtonMappingResult<T> implements TweedCoatEntryMappingResult<T, T> {
|
||||
private final EnumeratedMaterial<T> material;
|
||||
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigInput<T> createInput(TweedCoatEntryCreationContext<T> context) {
|
||||
return new CycleButtonConfigInput<>(material, false, context.currentValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEntryHandler<T> createHandler(TweedCoatEntryCreationContext<T> context) {
|
||||
if (context.parentSaveHandler() == null) {
|
||||
throw new IllegalArgumentException("No parent save handler provided");
|
||||
}
|
||||
return new BasicTweedCoatEntryHandler<>(
|
||||
context.entry(), context.defaultValue(), context.parentSaveHandler()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext<T> context) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
private static class SimpleMapper<T> implements TweedCoatMapper<T> {
|
||||
private final Class<T>[] valueClasses;
|
||||
private final Function<T, ConfigInput<T>> inputFactory;
|
||||
|
||||
@Override
|
||||
public TweedCoatEntryMappingResult<T, T> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext context) {
|
||||
matchingClass: {
|
||||
for (Class<T> valueClass : valueClasses) {
|
||||
if (entry.valueClass() == valueClass) {
|
||||
break matchingClass;
|
||||
}
|
||||
}
|
||||
return TweedCoatEntryMappingResult.notApplicable();
|
||||
}
|
||||
|
||||
return new TweedCoatEntryMappingResult<T, T>() {
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigInput<T> createInput(TweedCoatEntryCreationContext<T> context) {
|
||||
return inputFactory.apply(context.currentValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEntryHandler<T> createHandler(TweedCoatEntryCreationContext<T> context) {
|
||||
if (context.parentSaveHandler() == null) {
|
||||
throw new IllegalArgumentException("No parent save handler provided");
|
||||
}
|
||||
return new BasicTweedCoatEntryHandler<>(
|
||||
context.entry(), context.defaultValue(), context.parentSaveHandler()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext<T> context) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static class CompoundCategoryMapper<T> implements TweedCoatMapper<T> {
|
||||
@Override
|
||||
public TweedCoatEntryMappingResult<T, ?> mapEntry(ConfigEntry<T> entry, TweedCoatEntryMappingContext mappingContext) {
|
||||
@Value
|
||||
class MappedEntry<U> {
|
||||
String name;
|
||||
String translationKeyPrefix;
|
||||
ConfigEntry<U> entry;
|
||||
TweedCoatEntryMappingContext mappingContext;
|
||||
TweedCoatEntryMappingResult<U, ?> mappingResult;
|
||||
}
|
||||
|
||||
if (!(entry instanceof CompoundConfigEntry)) {
|
||||
return TweedCoatEntryMappingResult.notApplicable();
|
||||
}
|
||||
CompoundConfigEntry<T> compoundEntry = (CompoundConfigEntry<T>) entry;
|
||||
|
||||
Optional<AttributesExtension> attributesExtension = entry.container().extension(AttributesExtension.class);
|
||||
ResourceLocation backgroundTexture = attributesExtension
|
||||
.map(extension -> extension.getAttributeValue(
|
||||
entry,
|
||||
TweedCoatAttributes.BACKGROUND_TEXTURE
|
||||
))
|
||||
.map(ResourceLocation::tryParse)
|
||||
.orElse(null);
|
||||
String translationKey = attributesExtension
|
||||
.map(extension -> extension.getAttributeValue(
|
||||
entry,
|
||||
TweedCoatAttributes.TRANSLATION_KEY
|
||||
))
|
||||
.orElse(mappingContext.translationKeyPrefix());
|
||||
|
||||
List<MappedEntry<Object>> mappedEntries = compoundEntry.subEntries().entrySet().stream()
|
||||
.map(mapEntry -> {
|
||||
String subTranslationKeyPrefix = translationKey + "." + mapEntry.getKey();
|
||||
TweedCoatEntryMappingContext subMappingContext = mappingContext.subContextBuilder(mapEntry.getKey())
|
||||
.translationKeyPrefix(subTranslationKeyPrefix)
|
||||
.parentWidgetClass(ConfigCategoryWidget.class)
|
||||
.build();
|
||||
return new MappedEntry<>(
|
||||
mapEntry.getKey(),
|
||||
subTranslationKeyPrefix,
|
||||
(ConfigEntry<Object>) mapEntry.getValue(),
|
||||
subMappingContext,
|
||||
(TweedCoatEntryMappingResult<@NonNull Object, ?>) subMappingContext.mapEntry(
|
||||
mapEntry.getValue(),
|
||||
subMappingContext
|
||||
)
|
||||
);
|
||||
})
|
||||
.filter(mappedEntry -> mappedEntry.mappingResult.isApplicable())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new TweedCoatEntryMappingResult<T, T>() {
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigInput<T> createInput(TweedCoatEntryCreationContext<T> context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigEntryHandler<T> createHandler(TweedCoatEntryCreationContext<T> context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigContentWidget createContentWidget(TweedCoatEntryCreationContext<T> context) {
|
||||
ConfigCategoryWidget categoryWidget = new ConfigCategoryWidget(
|
||||
Minecraft.getInstance(),
|
||||
translatableComponentWithFallback(
|
||||
translationKey,
|
||||
mappingContext.entryName()
|
||||
),
|
||||
Collections.emptyList(),
|
||||
backgroundTexture
|
||||
);
|
||||
for (MappedEntry<Object> mappedEntry : mappedEntries) {
|
||||
TweedCoatEntryMappingResult<Object, ?> mappingResult = mappedEntry.mappingResult();
|
||||
if (!mappingResult.isApplicable()) {
|
||||
log.warn(
|
||||
"Failed to resolve mapping for entry \"" + mappedEntry.name() + "\" at \""
|
||||
+ translationKey + "\". Entry will be ignored in UI."
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
Object subEntryValue = compoundEntry.get(context.currentValue(), mappedEntry.name());
|
||||
Object subEntryDefaultValue = compoundEntry.get(context.defaultValue(), mappedEntry.name());
|
||||
TweedCoatEntryCreationContext<Object> creationContext = TweedCoatEntryCreationContext.builder()
|
||||
.entry(mappedEntry.entry())
|
||||
.currentValue(subEntryValue)
|
||||
.defaultValue(subEntryDefaultValue)
|
||||
.parentSaveHandler(value -> compoundEntry.set(context.currentValue(), mappedEntry.name(), value))
|
||||
.build();
|
||||
|
||||
ConfigInput<?> input = mappingResult.createInput(creationContext);
|
||||
if (input != null) {
|
||||
ConfigCategoryConfigEntry<Object> entry = new ConfigCategoryConfigEntry<>(
|
||||
translatableComponentWithFallback(mappedEntry.translationKeyPrefix(), mappedEntry.name()),
|
||||
translatableComponentWithFallback(mappedEntry.translationKeyPrefix() + ".description", null),
|
||||
(ConfigEntryHandler<Object>) mappingResult
|
||||
.createHandler(creationContext),
|
||||
(ConfigInput<Object>) input
|
||||
);
|
||||
categoryWidget.addEntry(entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigContentWidget contentWidget = mappingResult.createContentWidget(creationContext);
|
||||
if (contentWidget != null) {
|
||||
categoryWidget.addSubTree(contentWidget);
|
||||
}
|
||||
}
|
||||
return categoryWidget;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean anyClassMatches(Object value, Class<?>... classes) {
|
||||
for (Class<?> clazz : classes) {
|
||||
if (clazz.isInstance(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@NullMarked
|
||||
@ApiStatus.Internal
|
||||
package de.siphalor.tweed5.coat.bridge.impl;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"tweed5_coat_bridge.handler.conversion.exception": "Failed to convert: %s"
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package de.siphalor.tweed5.coat.bridge.testmod;
|
||||
|
||||
import de.siphalor.amecs.api.PriorityKeyBinding;
|
||||
import de.siphalor.coat.screen.ConfigScreen;
|
||||
import de.siphalor.tweed5.coat.bridge.api.ConfigScreenCreateParams;
|
||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatBridgeExtension;
|
||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatMappers;
|
||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonSerde;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
||||
import de.siphalor.tweed5.fabric.helper.api.FabricConfigContainerHelper;
|
||||
import de.siphalor.tweed5.weaver.pojo.impl.weaving.TweedPojoWeaverBootstrapper;
|
||||
import lombok.extern.apachecommons.CommonsLog;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.TitleScreen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@CommonsLog
|
||||
public class TweedCoatBridgeTestMod implements ClientModInitializer {
|
||||
public static final String MOD_ID = "tweed5_coat_bridge_testmod";
|
||||
|
||||
private static final TweedCoatBridgeTestModConfig DEFAULT_CONFIG_VALUE = new TweedCoatBridgeTestModConfig();
|
||||
|
||||
private ConfigContainer<TweedCoatBridgeTestModConfig> configContainer;
|
||||
private TweedCoatBridgeExtension configCoatBridgeExtension;
|
||||
private FabricConfigContainerHelper<TweedCoatBridgeTestModConfig> configContainerHelper;
|
||||
private TweedCoatBridgeTestModConfig config;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
configContainer = TweedPojoWeaverBootstrapper.create(TweedCoatBridgeTestModConfig.class).weave();
|
||||
configCoatBridgeExtension = configContainer.extension(TweedCoatBridgeExtension.class)
|
||||
.orElseThrow(() -> new IllegalStateException("TweedCoatBridgeExtension not found"));
|
||||
Arrays.asList(
|
||||
TweedCoatMappers.compoundCategoryMapper(),
|
||||
TweedCoatMappers.stringTextMapper(),
|
||||
TweedCoatMappers.integerTextMapper()
|
||||
).forEach(configCoatBridgeExtension::addMapper);
|
||||
|
||||
configContainer.initialize();
|
||||
|
||||
configContainerHelper = FabricConfigContainerHelper.create(
|
||||
configContainer,
|
||||
new HjsonSerde(new HjsonWriter.Options()),
|
||||
MOD_ID
|
||||
);
|
||||
|
||||
config = configContainerHelper.loadAndUpdateInConfigDirectory(() -> DEFAULT_CONFIG_VALUE);
|
||||
|
||||
KeyBindingHelper.registerKeyBinding(new ScreenKeyBinding(MOD_ID + ".config", 84, KeyMapping.Category.MISC));
|
||||
|
||||
log.info("current config");
|
||||
}
|
||||
|
||||
private class ScreenKeyBinding extends KeyMapping implements PriorityKeyBinding {
|
||||
public ScreenKeyBinding(String name, int key, Category category) {
|
||||
super(name, key, category);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPressedPriority() {
|
||||
if (!(Minecraft.getInstance().screen instanceof TitleScreen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigScreen configScreen = configCoatBridgeExtension.createConfigScreen(
|
||||
ConfigScreenCreateParams.<TweedCoatBridgeTestModConfig>builder()
|
||||
.translationKeyPrefix(MOD_ID + ".config")
|
||||
.title(Component.translatable(MOD_ID + ".title"))
|
||||
.rootEntry(configContainer.rootEntry())
|
||||
.currentValue(config)
|
||||
.defaultValue(DEFAULT_CONFIG_VALUE)
|
||||
.saveHandler(value -> {
|
||||
config = value;
|
||||
log.info("Updated config: " + config);
|
||||
configContainerHelper.writeConfigInConfigDirectory(config);
|
||||
})
|
||||
.build()
|
||||
);
|
||||
Minecraft.getInstance().setScreen(configScreen);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package de.siphalor.tweed5.coat.bridge.testmod;
|
||||
|
||||
import de.siphalor.tweed5.attributesextension.api.AttributesExtension;
|
||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatAttributes;
|
||||
import de.siphalor.tweed5.coat.bridge.api.TweedCoatBridgeExtension;
|
||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.CompoundWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.DefaultWeavingExtensions;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeaving;
|
||||
import de.siphalor.tweed5.weaver.pojo.api.annotation.PojoWeavingExtension;
|
||||
import de.siphalor.tweed5.weaver.pojoext.attributes.api.Attribute;
|
||||
import de.siphalor.tweed5.weaver.pojoext.attributes.api.AttributesPojoWeavingProcessor;
|
||||
import de.siphalor.tweed5.weaver.pojoext.serde.api.auto.AutoReadWritePojoWeavingProcessor;
|
||||
import de.siphalor.tweed5.weaver.pojoext.serde.api.auto.DefaultReadWriteMappings;
|
||||
import de.siphalor.tweed5.weaver.pojoext.validation.api.Validator;
|
||||
import de.siphalor.tweed5.weaver.pojoext.validation.api.ValidatorsPojoWeavingProcessor;
|
||||
import de.siphalor.tweed5.weaver.pojoext.validation.api.validators.WeavableNumberRangeValidator;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@PojoWeaving(extensions = {
|
||||
ReadWriteExtension.class,
|
||||
TweedCoatBridgeExtension.class,
|
||||
ValidationExtension.class,
|
||||
AttributesExtension.class,
|
||||
})
|
||||
@PojoWeavingExtension(AutoReadWritePojoWeavingProcessor.class)
|
||||
@PojoWeavingExtension(ValidatorsPojoWeavingProcessor.class)
|
||||
@PojoWeavingExtension(AttributesPojoWeavingProcessor.class)
|
||||
@DefaultWeavingExtensions
|
||||
@DefaultReadWriteMappings
|
||||
@CompoundWeaving(namingFormat = "kebab_case")
|
||||
@Data
|
||||
public class TweedCoatBridgeTestModConfig {
|
||||
private String test = "hello world";
|
||||
private int someInteger = 123;
|
||||
@Validator(value = WeavableNumberRangeValidator.class, config = "-10=..=10")
|
||||
private int integerInRange = -5;
|
||||
|
||||
@Attribute(key = TweedCoatAttributes.BACKGROUND_TEXTURE, values = "textures/block/green_terracotta.png")
|
||||
private Greeting serverGreeting = new Greeting("Hello server!", "Server");
|
||||
@Attribute(key = TweedCoatAttributes.BACKGROUND_TEXTURE, values = "textures/block/red_terracotta.png")
|
||||
private Greeting clientGreeting = new Greeting("Hello client!", "Client");
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@CompoundWeaving
|
||||
public static class Greeting {
|
||||
public String greeting;
|
||||
public String greeter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"tweed5_coat_bridge_testmod.title": "Test Mod",
|
||||
"tweed5_coat_bridge_testmod.config": "Test Mod config",
|
||||
"tweed5_coat_bridge_testmod.config.test": "Test entry",
|
||||
"tweed5_coat_bridge_testmod.config.test.description": "Just a simple string entry",
|
||||
"tweed5_coat_bridge_testmod.config.some-integer": "Some integer",
|
||||
"tweed5_coat_bridge_testmod.config.integer-in-range": "Integer in range"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "tweed5_coat_bridge_testmod",
|
||||
"version": "0.1.0",
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"de.siphalor.tweed5.coat.bridge.testmod.TweedCoatBridgeTestMod"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user