Skip to content

Commit 0cf4d50

Browse files
committed
removed top face culling method off setting
renamed TopFaceCullingMethod to CullfaceMethod renamed java-ish to standard added vanilla config removed default quality lang keys
1 parent 499b964 commit 0cf4d50

29 files changed

Lines changed: 618 additions & 312 deletions

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1-
Literally just a version bump. Nothing at all changed. If you're still playing on 1.21.6 through 8, you can safely ignore this patch.
1+
hi it's me again
2+
***
3+
4+
## 🔧 Changes
5+
[Sodium] recently brought about a new config API specifically designed with Sodium addons in mind. With this, I've removed the janky mixin and replaced it with a clean, professional-looking tab in the video settings screen!
6+
7+
In similar news, 1.21.11 removed the Fast, Fancy and Fabulous graphics profiles and turned them into presets for functionally separate, individual options.
8+
9+
You can now configure all the features of **Blocky Bubbles** without Sodium!

build.gradle

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ publishMods {
4848
for (String version : modrinth_versions.toString().split(' '))
4949
minecraftVersions.add(version)
5050

51-
requires("fabric-api")
52-
requires("sodium")
51+
requires "fabric-api"
52+
optional "sodium"
5353
}
5454

5555
discord {
@@ -65,7 +65,9 @@ dependencies {
6565
modImplementation "net.fabricmc:fabric-loader:${loader_version}"
6666
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}"
6767
modImplementation "com.terraformersmc:modmenu:${modmenu_version}"
68-
modImplementation "net.caffeinemc:sodium-fabric:${sodium_version}"
68+
modCompileOnly "net.caffeinemc:sodium-fabric-api:${sodium_version}"
69+
70+
// modRuntimeOnly "net.caffeinemc:sodium-fabric:${sodium_version}"
6971
}
7072

7173
def javaVersion = JavaVersion.VERSION_21
@@ -75,17 +77,21 @@ processResources {
7577
inputs.property("id", project.mod_id)
7678
inputs.property("name", project.mod_name)
7779
inputs.property("version", project.mod_version)
80+
inputs.property("description", project.mod_description)
7881
inputs.property("target", project.target_version)
7982
inputs.property("loader", project.loader_version)
80-
inputs.property("java_version", javaVersionNumber)
83+
inputs.property("java", javaVersionNumber)
84+
inputs.property("repository", project.repository_url)
8185

8286
def map = [
8387
"id": inputs.properties.id,
8488
"name": inputs.properties.name,
8589
"version": inputs.properties.version,
90+
"description": inputs.properties.description,
8691
"target": inputs.properties.target,
8792
"loader": inputs.properties.loader,
88-
"java_version": inputs.properties.java_version
93+
"java": inputs.properties.java,
94+
"repository": inputs.properties.repository
8995
]
9096

9197
filesMatching("fabric.mod.json") {

gradle.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ mpp_version=1.1.0
88
mod_version=2.0.0
99
mod_name=Blocky Bubbles
1010
mod_id=blocky-bubbles
11+
mod_description=Ports the Fast Bubbles setting from Bedrock Edition!
1112

1213
update_name_suffix=
1314
maven_group=com.axialeaa
1415

15-
target_version=~1.21.11
16+
target_version=1.21.11
1617
build_version=1.21.11
1718
modrinth_versions=1.21.11
1819
fabric_version=0.139.5+1.21.11

src/main/java/com/axialeaa/blockybubbles/BlockyBubbles.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.axialeaa.blockybubbles;
22

3+
import com.axialeaa.blockybubbles.config.BlockyBubblesConfig;
34
import net.fabricmc.api.ClientModInitializer;
45
import net.fabricmc.loader.api.FabricLoader;
56
import net.minecraft.resources.Identifier;
@@ -14,6 +15,8 @@ public class BlockyBubbles implements ClientModInitializer {
1415
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME);
1516
public static final FabricLoader LOADER = FabricLoader.getInstance();
1617

18+
private static BlockyBubblesConfig config = null;
19+
1720
@Override
1821
public void onInitializeClient() {
1922
LOGGER.info("{} initialized! The bubbles were told \"be there or be square\" and they were not there...", MOD_NAME);
@@ -23,4 +26,11 @@ public static Identifier id(String path) {
2326
return Identifier.fromNamespaceAndPath(MOD_ID, path);
2427
}
2528

29+
public static BlockyBubblesConfig getConfig() {
30+
if (config == null)
31+
config = BlockyBubblesConfig.loadFromFile();
32+
33+
return config;
34+
}
35+
2636
}
Lines changed: 124 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,130 @@
11
package com.axialeaa.blockybubbles.config;
22

33
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);
99128
}
100129

101130
}

0 commit comments

Comments
 (0)