|
1 | 1 | package com.axialeaa.blockybubbles.config; |
2 | 2 |
|
3 | 3 | import com.axialeaa.blockybubbles.BlockyBubbles; |
4 | | -import net.caffeinemc.mods.sodium.api.config.ConfigEntryPoint; |
5 | | -import net.caffeinemc.mods.sodium.api.config.ConfigState; |
6 | | -import net.caffeinemc.mods.sodium.api.config.option.OptionFlag; |
7 | | -import net.caffeinemc.mods.sodium.api.config.option.OptionImpact; |
8 | | -import net.caffeinemc.mods.sodium.api.config.structure.ConfigBuilder; |
9 | | -import net.minecraft.network.chat.Component; |
10 | | -import net.minecraft.resources.Identifier; |
11 | | - |
12 | | -public class BlockyBubblesConfig implements ConfigEntryPoint { |
13 | | - |
14 | | - private static final Identifier QUALITY = BlockyBubbles.id("quality"); |
15 | | - private static final Identifier ANIMATIONS = BlockyBubbles.id("animations"); |
16 | | - private static final Identifier OPAQUE_FACES = BlockyBubbles.id("opaque_faces"); |
17 | | - private static final Identifier TOP_FACE_CULLING_METHOD = BlockyBubbles.id("top_face_culling_method"); |
18 | | - private static final int THEME_COLOR = 0xFF77D9FF; |
19 | | - |
20 | | - private static BlockyBubblesConfigStorage storage = null; |
21 | | - |
22 | | - @Override |
23 | | - public void registerConfigLate(ConfigBuilder configBuilder) { |
24 | | - configBuilder.registerOwnModOptions() |
25 | | - .setColorTheme(configBuilder.createColorTheme().setBaseThemeRGB(THEME_COLOR)) |
26 | | - .setIcon(BlockyBubbles.id("textures/gui/config_icon.png")) |
27 | | - .setName(BlockyBubbles.MOD_NAME) |
28 | | - .addPage(configBuilder.createOptionPage() |
29 | | - .setName(optionText(BlockyBubbles.id("page.bubble_columns"))) |
30 | | - .addOptionGroup(configBuilder.createOptionGroup() |
31 | | - .addOption(configBuilder.createEnumOption(QUALITY, BubblesQuality.class) |
32 | | - .setName(optionText(QUALITY)) |
33 | | - .setElementNameProvider(value -> optionText(QUALITY, '.' + value.path)) |
34 | | - .setTooltip(optionTooltip(QUALITY)) |
35 | | - .setStorageHandler(getStorage()) |
36 | | - .setBinding(value -> getStorage().quality = value, () -> getStorage().quality) |
37 | | - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) |
38 | | - .setImpact(OptionImpact.MEDIUM) |
39 | | - .setDefaultValue(BubblesQuality.FAST) |
40 | | - ) |
41 | | - ) |
42 | | - .addOptionGroup(configBuilder.createOptionGroup() |
43 | | - .addOption(configBuilder.createBooleanOption(ANIMATIONS) |
44 | | - .setName(optionText(ANIMATIONS)) |
45 | | - .setTooltip(optionTooltip(ANIMATIONS)) |
46 | | - .setStorageHandler(getStorage()) |
47 | | - .setBinding(value -> getStorage().animations = value, () -> getStorage().animations) |
48 | | - .setFlags(OptionFlag.REQUIRES_ASSET_RELOAD) |
49 | | - .setImpact(OptionImpact.MEDIUM) |
50 | | - .setDefaultValue(true) |
51 | | - .setEnabledProvider(BlockyBubblesConfig::isFast, QUALITY) |
52 | | - ) |
53 | | - .addOption(configBuilder.createBooleanOption(OPAQUE_FACES) |
54 | | - .setName(optionText(OPAQUE_FACES)) |
55 | | - .setTooltip(optionTooltip(OPAQUE_FACES)) |
56 | | - .setStorageHandler(getStorage()) |
57 | | - .setBinding(value -> getStorage().opaqueFaces = value, () -> getStorage().opaqueFaces) |
58 | | - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) |
59 | | - .setImpact(OptionImpact.MEDIUM) |
60 | | - .setDefaultValue(false) |
61 | | - .setEnabledProvider(BlockyBubblesConfig::isFast, QUALITY) |
62 | | - ) |
63 | | - .addOption(configBuilder.createEnumOption(TOP_FACE_CULLING_METHOD, TopFaceCullingMethod.class) |
64 | | - .setName(optionText(TOP_FACE_CULLING_METHOD)) |
65 | | - .setElementNameProvider(value -> optionText(TOP_FACE_CULLING_METHOD, '.' + value.path)) |
66 | | - .setTooltip(value -> optionText(TOP_FACE_CULLING_METHOD, '.' + value.path + ".tooltip")) |
67 | | - .setStorageHandler(getStorage()) |
68 | | - .setBinding(value -> getStorage().topFaceCullingMethod = value, () -> getStorage().topFaceCullingMethod) |
69 | | - .setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD) |
70 | | - .setImpact(OptionImpact.LOW) |
71 | | - .setDefaultValue(TopFaceCullingMethod.NON_AIR) |
72 | | - .setEnabledProvider(BlockyBubblesConfig::isFast, QUALITY) |
73 | | - ) |
74 | | - ) |
75 | | - ); |
76 | | - } |
77 | | - |
78 | | - public static BlockyBubblesConfigStorage getStorage() { |
79 | | - if (storage == null) |
80 | | - storage = BlockyBubblesConfigStorage.loadFromFile(); |
81 | | - |
82 | | - return storage; |
83 | | - } |
84 | | - |
85 | | - private static boolean isFast(ConfigState configState) { |
86 | | - return configState.readEnumOption(QUALITY, BubblesQuality.class) == BubblesQuality.FAST; |
87 | | - } |
88 | | - |
89 | | - public static Component optionTooltip(Identifier option) { |
90 | | - return optionText(option, ".tooltip"); |
91 | | - } |
92 | | - |
93 | | - public static Component optionText(Identifier option) { |
94 | | - return optionText(option, ""); |
95 | | - } |
96 | | - |
97 | | - public static Component optionText(Identifier option, String suffix) { |
98 | | - return Component.translatable(option.withPrefix("options.").toLanguageKey() + suffix); |
| 4 | +import com.google.gson.FieldNamingPolicy; |
| 5 | +import com.google.gson.Gson; |
| 6 | +import com.google.gson.GsonBuilder; |
| 7 | +import com.google.gson.annotations.Expose; |
| 8 | +import org.jspecify.annotations.Nullable; |
| 9 | + |
| 10 | +import java.io.File; |
| 11 | +import java.io.FileReader; |
| 12 | +import java.io.FileWriter; |
| 13 | +import java.io.IOException; |
| 14 | +import java.util.Objects; |
| 15 | + |
| 16 | +public class BlockyBubblesConfig { |
| 17 | + |
| 18 | + private static final Gson GSON = new GsonBuilder() |
| 19 | + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) |
| 20 | + .excludeFieldsWithoutExposeAnnotation() |
| 21 | + .setPrettyPrinting() |
| 22 | + .create(); |
| 23 | + |
| 24 | + @Expose @Nullable private Quality quality = Quality.FAST; |
| 25 | + @Expose @Nullable private Boolean animations = true; |
| 26 | + @Expose @Nullable private Boolean opaqueFaces = false; |
| 27 | + @Expose @Nullable private CullfaceMethod cullfaceMethod = CullfaceMethod.NON_AIR; |
| 28 | + |
| 29 | + @Nullable private File file; |
| 30 | + |
| 31 | + public static BlockyBubblesConfig loadFromFile() { |
| 32 | + File configFile = createFile(); |
| 33 | + BlockyBubblesConfig config = parseOrCreate(configFile); |
| 34 | + |
| 35 | + config.file = configFile; |
| 36 | + config.writeToFile(); |
| 37 | + |
| 38 | + return config; |
| 39 | + } |
| 40 | + |
| 41 | + private static File createFile() { |
| 42 | + return BlockyBubbles.LOADER.getConfigDir().resolve(BlockyBubbles.MOD_ID + ".json").toFile(); |
| 43 | + } |
| 44 | + |
| 45 | + private static BlockyBubblesConfig parseOrCreate(File configFile) { |
| 46 | + if (!configFile.exists()) |
| 47 | + return new BlockyBubblesConfig(); |
| 48 | + |
| 49 | + try (FileReader reader = new FileReader(configFile)) { |
| 50 | + return Objects.requireNonNullElse(GSON.fromJson(reader, BlockyBubblesConfig.class), new BlockyBubblesConfig()); |
| 51 | + } |
| 52 | + catch (Exception e) { |
| 53 | + BlockyBubbles.LOGGER.warn("Falling back to defaults as the config could not be parsed.", e); |
| 54 | + return new BlockyBubblesConfig(); |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + public void writeToFile() { |
| 59 | + this.validateDirectory(); |
| 60 | + this.tryWriteFile(); |
| 61 | + } |
| 62 | + |
| 63 | + private void validateDirectory() { |
| 64 | + if (this.file == null) |
| 65 | + throw new RuntimeException("Config file not found!"); |
| 66 | + |
| 67 | + File directory = this.file.getParentFile(); |
| 68 | + |
| 69 | + if (!directory.exists()) { |
| 70 | + tryMakeDirectories(directory); |
| 71 | + return; |
| 72 | + } |
| 73 | + |
| 74 | + if (!directory.isDirectory()) |
| 75 | + throw new RuntimeException(directory + " must be a directory!"); |
| 76 | + } |
| 77 | + |
| 78 | + private static void tryMakeDirectories(File parentFile) { |
| 79 | + if (!parentFile.mkdirs()) |
| 80 | + throw new RuntimeException("Failed to create parent directories!"); |
| 81 | + } |
| 82 | + |
| 83 | + private void tryWriteFile() { |
| 84 | + assert this.file != null; // checked in validateDirectories |
| 85 | + |
| 86 | + try (FileWriter fileWriter = new FileWriter(this.file)) { |
| 87 | + GSON.toJson(this, fileWriter); |
| 88 | + } |
| 89 | + catch (IOException e) { |
| 90 | + throw new RuntimeException("Failed to save configuration file!", e); |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + public boolean isFancy() { |
| 95 | + return this.getQuality() == Quality.FANCY; |
| 96 | + } |
| 97 | + |
| 98 | + public void setAnimations(boolean animations) { |
| 99 | + this.animations = animations; |
| 100 | + } |
| 101 | + |
| 102 | + public void setOpaqueFaces(boolean opaqueFaces) { |
| 103 | + this.opaqueFaces = opaqueFaces; |
| 104 | + } |
| 105 | + |
| 106 | + public void setQuality(Quality quality) { |
| 107 | + this.quality = quality; |
| 108 | + } |
| 109 | + |
| 110 | + public void setCullfaceMethod(CullfaceMethod cullfaceMethod) { |
| 111 | + this.cullfaceMethod = cullfaceMethod; |
| 112 | + } |
| 113 | + |
| 114 | + public boolean hasAnimations() { |
| 115 | + return Objects.requireNonNullElse(this.animations, true); |
| 116 | + } |
| 117 | + |
| 118 | + public boolean hasOpaqueFaces() { |
| 119 | + return Objects.requireNonNullElse(this.opaqueFaces, false); |
| 120 | + } |
| 121 | + |
| 122 | + public Quality getQuality() { |
| 123 | + return Objects.requireNonNullElse(this.quality, Quality.FAST); |
| 124 | + } |
| 125 | + |
| 126 | + public CullfaceMethod getCullfaceMethod() { |
| 127 | + return Objects.requireNonNullElse(this.cullfaceMethod, CullfaceMethod.NON_AIR); |
99 | 128 | } |
100 | 129 |
|
101 | 130 | } |
0 commit comments