feat(config-core): support save hooks for config screens

This commit is contained in:
Johannes Frohnmeyer 2023-08-13 22:54:54 +02:00
parent a312c86783
commit c967a36eaa
Signed by: Johannes
GPG Key ID: E76429612C2929F4
12 changed files with 167 additions and 26 deletions

View File

@ -4,6 +4,7 @@ import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import io.gitlab.jfronny.libjf.config.impl.ui.ConfigScreenFactoryDiscovery;
import net.minecraft.client.gui.screen.Screen;
@Deprecated
public interface ConfigScreenFactory<S extends Screen> {
static ConfigScreenFactory<?> getInstance() {
return ConfigScreenFactoryDiscovery.getConfigured();

View File

@ -0,0 +1,21 @@
package io.gitlab.jfronny.libjf.config.api.v2.ui;
import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import io.gitlab.jfronny.libjf.config.impl.ui.ConfigScreenFactoryDiscovery;
import net.minecraft.client.gui.screen.Screen;
public interface ConfigScreenFactory<S extends Screen, B extends ConfigScreenFactory.Built<S>> {
static ConfigScreenFactory<?, ?> getInstance() {
return ConfigScreenFactoryDiscovery.getConfigured2();
}
B create(ConfigInstance config, Screen parent);
int getPriority();
interface Built<S extends Screen> {
S get();
void onSave(Runnable action);
}
}

View File

@ -0,0 +1,29 @@
package io.gitlab.jfronny.libjf.config.impl.ui;
import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory;
import net.minecraft.client.gui.screen.Screen;
public record ConfigScreenFactory1To2<S extends Screen>(io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory<S> impl) implements ConfigScreenFactory<S, ConfigScreenFactory1To2.Built<S>> {
@Override
public Built<S> create(ConfigInstance config, Screen parent) {
return new Built<>(impl.create(config, parent));
}
@Override
public int getPriority() {
return impl.getPriority();
}
public record Built<S extends Screen>(S screen) implements ConfigScreenFactory.Built<S> {
@Override
public S get() {
return null;
}
@Override
public void onSave(Runnable action) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,17 @@
package io.gitlab.jfronny.libjf.config.impl.ui;
import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory;
import net.minecraft.client.gui.screen.Screen;
public record ConfigScreenFactory2To1<S extends Screen, B extends io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory.Built<S>>(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory<S, B> impl) implements ConfigScreenFactory<S> {
@Override
public S create(ConfigInstance config, Screen parent) {
return impl.create(config, parent).get();
}
@Override
public int getPriority() {
return impl.getPriority();
}
}

View File

@ -4,18 +4,52 @@ import io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory;
import net.fabricmc.loader.api.FabricLoader;
import java.util.Comparator;
import java.util.List;
public class ConfigScreenFactoryDiscovery {
private static ConfigScreenFactory<?> discovered = null;
private static ConfigScreenFactory<?> discovered1 = null;
private static io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory discovered2 = null;
@Deprecated
public static ConfigScreenFactory<?> getConfigured() {
if (discovered == null) {
discovered = FabricLoader.getInstance()
.getEntrypoints("libjf:config_screen", ConfigScreenFactory.class)
if (discovered1 == null) {
List<Object> entrypoints = getEntrypoints();
discovered1 = entrypoints
.stream()
.max(Comparator.comparing(ConfigScreenFactory::getPriority))
.orElse(new PlaceholderScreenFactory());
.filter(it -> it instanceof io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory<?,?>)
.map(it -> (io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory) it)
.max(Comparator.comparing(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory::getPriority))
.<ConfigScreenFactory>map(ConfigScreenFactory2To1::new)
.orElseGet(() -> entrypoints
.stream()
.filter(it -> it instanceof ConfigScreenFactory<?>)
.map(it -> (ConfigScreenFactory) it)
.max(Comparator.comparing(ConfigScreenFactory::getPriority))
.orElseGet(() -> new ConfigScreenFactory2To1(new PlaceholderScreenFactory())));
}
return discovered;
return discovered1;
}
public static io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory<?, ?> getConfigured2() {
if (discovered2 == null) {
List<Object> entrypoints = getEntrypoints();
discovered2 = entrypoints
.stream()
.filter(it -> it instanceof io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory<?,?>)
.map(it -> (io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory) it)
.max(Comparator.comparing(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory::getPriority))
.orElseGet(() -> entrypoints
.stream()
.filter(it -> it instanceof ConfigScreenFactory<?>)
.map(it -> (ConfigScreenFactory) it)
.<io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory>map(ConfigScreenFactory1To2::new)
.max(Comparator.comparing(io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory::getPriority))
.orElseGet(PlaceholderScreenFactory::new));
}
return discovered2;
}
private static List<Object> getEntrypoints() {
return FabricLoader.getInstance().getEntrypoints("libjf:config_screen", Object.class);
}
}

View File

@ -27,6 +27,6 @@ public class ModMenuAdapter implements ModMenuApi {
}
private static ConfigScreenFactory<?> buildFactory(ConfigInstance config) {
return s -> io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory.getInstance().create(config, s);
return s -> io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory.getInstance().create(config, s).get();
}
}

View File

@ -1,17 +1,29 @@
package io.gitlab.jfronny.libjf.config.impl.ui;
import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory;
import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory;
import net.minecraft.client.gui.screen.Screen;
public class PlaceholderScreenFactory implements ConfigScreenFactory<PlaceholderScreen> {
public class PlaceholderScreenFactory implements ConfigScreenFactory<PlaceholderScreen, PlaceholderScreenFactory.Built> {
@Override
public PlaceholderScreen create(ConfigInstance config, Screen parent) {
return new PlaceholderScreen(parent);
public Built create(ConfigInstance config, Screen parent) {
return new Built(new PlaceholderScreen(parent));
}
@Override
public int getPriority() {
return -100;
}
public record Built(PlaceholderScreen screen) implements ConfigScreenFactory.Built<PlaceholderScreen> {
@Override
public PlaceholderScreen get() {
return screen;
}
@Override
public void onSave(Runnable action) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -8,6 +8,6 @@ import net.minecraft.client.gui.screen.Screen;
public interface ConfigScreen {
TinyConfigScreenFactory FACTORY = new TinyConfigScreenFactory();
static Screen create(ConfigInstance config, Screen parent) {
return FACTORY.create(config, parent);
return FACTORY.create(config, parent).get();
}
}

View File

@ -10,13 +10,9 @@ import net.minecraft.client.font.TextHandler;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.BookEditScreen;
import net.minecraft.client.gui.screen.option.OptionsScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.OptionListWidget;
import net.minecraft.client.util.NarratorManager;
import net.minecraft.client.util.SelectionManager;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Rect2i;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.text.*;
@ -31,7 +27,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.Consumer;
public class EditorScreen extends Screen {
public class EditorScreen extends ScreenWithSaveHook {
private static final int SCROLLBAR_SIZE = 7;
private static final int HEADER_SIZE = 32;
private static final int FOOTER_SIZE = 36;
@ -134,7 +130,10 @@ public class EditorScreen extends Screen {
}
private void quit(boolean save) {
if (save && (this.initialText == null || !this.initialText.equals(this.text))) onSave.accept(text);
if (save && (this.initialText == null || !this.initialText.equals(this.text))) {
onSave.accept(text);
saveHook.run();
}
close();
}

View File

@ -0,0 +1,13 @@
package io.gitlab.jfronny.libjf.config.impl.ui.tiny;
import io.gitlab.jfronny.commons.ref.R;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
public abstract class ScreenWithSaveHook extends Screen {
public Runnable saveHook = R::nop;
protected ScreenWithSaveHook(Text title) {
super(title);
}
}

View File

@ -27,7 +27,7 @@ import net.minecraft.util.math.MathHelper;
import java.util.*;
@Environment(EnvType.CLIENT)
public class TinyConfigScreen extends Screen {
public class TinyConfigScreen extends ScreenWithSaveHook {
public static Text getTitle(String categoryPath) {
final String titlePath = categoryPath + "title";
if (JfConfigSafe.TRANSLATION_SUPPLIER.apply(titlePath) != null) {
@ -79,6 +79,7 @@ public class TinyConfigScreen extends Screen {
}
config.getRoot().write();
Objects.requireNonNull(client).setScreen(parent);
saveHook.run();
})
.dimensions(this.width / 2 + 4, this.height - 28, 150, 20)
.build();

View File

@ -6,7 +6,7 @@ import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo;
import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder;
import io.gitlab.jfronny.libjf.config.api.v1.type.Type;
import io.gitlab.jfronny.libjf.config.api.v1.ui.ConfigScreenFactory;
import io.gitlab.jfronny.libjf.config.api.v2.ui.ConfigScreenFactory;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.resource.language.I18n;
@ -14,9 +14,9 @@ import net.minecraft.client.toast.SystemToast;
import net.minecraft.text.Text;
// IDEA doesn't like this, but it does work in practice
public class TinyConfigScreenFactory implements ConfigScreenFactory<Screen> {
public class TinyConfigScreenFactory implements ConfigScreenFactory<Screen, TinyConfigScreenFactory.Built> {
@Override
public Screen create(ConfigInstance config, Screen parent) {
public Built create(ConfigInstance config, Screen parent) {
if (config.getEntries().size() == 1
&& config.getPresets().keySet().stream().allMatch(s -> s.equals(CategoryBuilder.CONFIG_PRESET_DEFAULT))
&& config.getReferencedConfigs().isEmpty()
@ -31,7 +31,7 @@ public class TinyConfigScreenFactory implements ConfigScreenFactory<Screen> {
throw new RuntimeException(e);
}
String key = config.getTranslationPrefix() + entry.getName();
return new EditorScreen(
return new Built(new EditorScreen(
Text.translatable(key),
I18n.hasTranslation(key + ".tooltip") ? Text.translatable(key + ".tooltip") : null,
parent,
@ -50,14 +50,28 @@ public class TinyConfigScreenFactory implements ConfigScreenFactory<Screen> {
);
}
}
);
));
}
}
return new TinyConfigScreen(config, parent);
return new Built(new TinyConfigScreen(config, parent));
}
@Override
public int getPriority() {
return 0;
}
public record Built(ScreenWithSaveHook screen) implements ConfigScreenFactory.Built<Screen> {
public Screen get() {
return screen;
}
public void onSave(Runnable action) {
Runnable currentHook = screen.saveHook;
screen.saveHook = () -> {
currentHook.run();
action.run();
};
}
}
}