diff --git a/build.gradle b/build.gradle index 8b5d349..6a48f21 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { - id "fabric-loom" version "1.5.+" - id "com.github.johnrengelman.shadow" version "7.1.2" + id "fabric-loom" version "1.6.+" + id "com.github.johnrengelman.shadow" version "7.1.+" id "com.modrinth.minotaur" version "2.+" } @@ -12,6 +12,7 @@ repositories { maven { url = "https://maven.gegy.dev/" } maven { url = "https://maven.terraformersmc.com/releases/" } maven { url = "https://maven.quiltmc.org/repository/release/" } + maven { url = "https://repo.sleeping.town/" } } configurations { @@ -25,12 +26,16 @@ dependencies { mappings("org.quiltmc:quilt-mappings:${project.minecraft_version}+build.${project.quilt_mappings}:intermediary-v2") modImplementation("net.fabricmc:fabric-loader:${project.loader_version}") - include(modImplementation("dev.lambdaurora:spruceui:${project.spruceui_version}")) modImplementation("com.terraformersmc:modmenu:${project.mod_menu_version}") + implementation("folk.sisby:kaleido-config:0.3.1+1.3.1") + include("folk.sisby:kaleido-config:0.3.1+1.3.1") Set apiModules = [ "fabric-networking-api-v1", - "fabric-resource-loader-v0" + "fabric-resource-loader-v0", + "fabric-screen-api-v1", + "fabric-key-binding-api-v1", + "fabric-lifecycle-events-v1", ] apiModules.forEach { diff --git a/gradle.properties b/gradle.properties index 22ba06d..a0f3969 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,17 +3,16 @@ org.gradle.jvmargs=-Xmx1G # minecraft, mappings and loader dependencies # check these on https://modmuss50.me/fabric.html -minecraft_version=1.20.4 -quilt_mappings=3 -loader_version=0.15.7 +minecraft_version=1.20.6 +quilt_mappings=6 +loader_version=0.15.11 # mod properties -mod_version=1.2.0+mc1.20.4 +mod_version=1.3.0+mc1.20.6 maven_group=rainglow archives_base_name=rainglow # other dependencies -java_version=17 -spruceui_version=5.0.3+1.20.4 -mod_menu_version=9.0.0 -fabric_api_version=0.96.4+1.20.4 +java_version=21 +mod_menu_version=10.0.0-beta.1 +fabric_api_version=0.98.0+1.20.6 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index fcb6fca..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -201,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..25da30d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/src/main/java/io/ix0rai/rainglow/Rainglow.java b/src/main/java/io/ix0rai/rainglow/Rainglow.java index 87862d1..7999547 100644 --- a/src/main/java/io/ix0rai/rainglow/Rainglow.java +++ b/src/main/java/io/ix0rai/rainglow/Rainglow.java @@ -1,18 +1,16 @@ package io.ix0rai.rainglow; import com.google.gson.Gson; +import folk.sisby.kaleido.lib.quiltconfig.api.serializers.TomlSerializer; +import folk.sisby.kaleido.lib.quiltconfig.implementor_api.ConfigEnvironment; import io.ix0rai.rainglow.config.RainglowConfig; import io.ix0rai.rainglow.data.*; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.data.DataTracker; -import net.minecraft.entity.data.TrackedData; -import net.minecraft.entity.data.TrackedDataHandlerRegistry; -import net.minecraft.entity.mob.SlimeEntity; -import net.minecraft.entity.passive.AllayEntity; -import net.minecraft.entity.passive.GlowSquidEntity; -import net.minecraft.item.Item; import net.minecraft.resource.ResourceType; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -20,36 +18,34 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.List; public class Rainglow implements ModInitializer { public static final String MOD_ID = "rainglow"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - public static final RainglowConfig CONFIG = new RainglowConfig(); + private static final String FORMAT = "toml"; + private static final ConfigEnvironment ENVIRONMENT = new ConfigEnvironment(FabricLoader.getInstance().getConfigDir(), FORMAT, TomlSerializer.INSTANCE); + public static final RainglowConfig CONFIG = RainglowConfig.create(ENVIRONMENT, "", MOD_ID, RainglowConfig.class); public static final Gson GSON = new Gson(); - private static final List COLOURS = new ArrayList<>(); - private static final Map GLOWSQUID_TEXTURES = new HashMap<>(); - private static final Map ALLAY_TEXTURES = new HashMap<>(); - private static final Map SLIME_TEXTURES = new HashMap<>(); - private static TrackedData glowSquidColour; - private static TrackedData allayColour; - private static TrackedData slimeColour; - public static final String CUSTOM_NBT_KEY = "Colour"; + public static final Identifier SERVER_MODE_DATA_ID = id("server_mode_data"); + public static final List RAINGLOW_DATAPACKS = new ArrayList<>(); @Override public void onInitialize() { - ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener((RainglowResourceReloader) () -> id("server_mode_data")); + ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener((RainglowResourceReloader) () -> SERVER_MODE_DATA_ID); + + PayloadTypeRegistry.playS2C().register(RainglowNetworking.ConfigSyncPayload.PACKET_ID, RainglowNetworking.ConfigSyncPayload.PACKET_CODEC); + PayloadTypeRegistry.playS2C().register(RainglowNetworking.ModeSyncPayload.PACKET_ID, RainglowNetworking.ModeSyncPayload.PACKET_CODEC); ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { - if (CONFIG.isServerSyncEnabled()) { - // send modes to client - RainglowNetworking.sendModeData(handler.player); + // send modes to client + RainglowNetworking.syncModes(handler.player); - // send config to client - RainglowNetworking.syncConfig(handler.player); - } + // send config to client + RainglowNetworking.syncConfig(handler.player); }); } @@ -57,77 +53,18 @@ public static Identifier id(String id) { return new Identifier(MOD_ID, id); } - public static void setMode(RainglowMode mode) { - GLOWSQUID_TEXTURES.clear(); - ALLAY_TEXTURES.clear(); - SLIME_TEXTURES.clear(); - COLOURS.clear(); - - List colours = mode.getColours(); - if (colours.isEmpty()) { - LOGGER.info("No colours were present in the internal collection, adding blue so that the game doesn't crash"); - colours.add(RainglowColour.BLUE); - } - colours.forEach(Rainglow::addColour); - } - - public static void refreshColours() { - // we only ever need to refresh the colours of custom mode, all other sets of colours are immutable - if (CONFIG.getMode().getId().equals("custom")) { - setMode(RainglowMode.byId("custom")); - } - } - - private static void addColour(RainglowColour colour) { - COLOURS.add(colour); - - GLOWSQUID_TEXTURES.put(colour.getId(), colour.getTexture(RainglowEntity.GLOW_SQUID)); - ALLAY_TEXTURES.put(colour.getId(), colour.getTexture(RainglowEntity.ALLAY)); - SLIME_TEXTURES.put(colour.getId(), colour.getTexture(RainglowEntity.SLIME)); - - if (COLOURS.size() >= 100) { - throw new RuntimeException("Too many colours registered! Only up to 99 are allowed"); - } - } - - public static Identifier getTexture(RainglowEntity entityType, String colour) { - if (entityType == RainglowEntity.GLOW_SQUID) return GLOWSQUID_TEXTURES.get(colour); - else if (entityType == RainglowEntity.ALLAY) return ALLAY_TEXTURES.get(colour); - else return SLIME_TEXTURES.get(colour); - } - - public static int getColourIndex(String colour) { - return COLOURS.indexOf(RainglowColour.get(colour)); - } - - public static RainglowColour.RGB getInkRgb(int index) { - return COLOURS.get(index).getInkRgb(); - } - - public static RainglowColour.RGB getPassiveParticleRGB(int index, RandomGenerator random) { - RainglowColour colour = COLOURS.get(index); - return random.nextBoolean() ? colour.getPassiveParticleRgb() : colour.getAltPassiveParticleRgb(); - } - - public static Item getItem(int index) { - return COLOURS.get(index).getItem(); - } - public static String generateRandomColourId(RandomGenerator random) { - return COLOURS.get(random.nextInt(COLOURS.size())).getId(); - } - - public static Identifier getDefaultTexture(RainglowEntity entityType) { - if (entityType == RainglowEntity.SLIME) return RainglowColour.LIME.getTexture(entityType); - else return RainglowColour.BLUE.getTexture(entityType); + var colours = CONFIG.getMode().getColours(); + return colours.get(random.nextInt(colours.size())).getId(); } - public static boolean colourUnloaded(String colour) { - return !COLOURS.contains(RainglowColour.get(colour)); + public static boolean colourUnloaded(RainglowEntity entityType, String colour) { + var colours = CONFIG.getMode().getColours(); + return !colours.contains(RainglowColour.get(colour)) && !colour.equals(entityType.getDefaultColour().getId()); } public static String translatableTextKey(String key) { - if (key.split("\\.").length != 2) throw new IllegalArgumentException("key must be in format \"category.key\""); + if (key.split("\\.").length < 2) throw new IllegalArgumentException("key must be in format \"category.key\": " + key); return MOD_ID + "." + key; } @@ -139,44 +76,15 @@ public static Text translatableText(String key) { return Text.translatable(translatableTextKey(key)); } - public static TrackedData getTrackedColourData(RainglowEntity entityType) { - // we cannot statically load the tracked data because then it gets registered too early - // it breaks the squids' other tracked data, their dark ticks after being hurt - // this is a workaround to make sure the data is registered at the right time - // we simply ensure it isn't loaded until it's needed, and that fixes the issue - - if (entityType == RainglowEntity.GLOW_SQUID) { - if (glowSquidColour == null) { - glowSquidColour = DataTracker.registerData(GlowSquidEntity.class, TrackedDataHandlerRegistry.STRING); - } - - return glowSquidColour; - } else if (entityType == RainglowEntity.ALLAY) { - if (allayColour == null) { - allayColour = DataTracker.registerData(AllayEntity.class, TrackedDataHandlerRegistry.STRING); - } - - return allayColour; - } else if (entityType == RainglowEntity.SLIME) { - if (slimeColour == null) { - slimeColour = DataTracker.registerData(SlimeEntity.class, TrackedDataHandlerRegistry.STRING); - } - - return slimeColour; - } - - throw new RuntimeException("called getTrackedColourData on an unsupported entity type!"); - } - - public static String getColour(RainglowEntity entityType, DataTracker tracker, RandomGenerator random) { + public static RainglowColour getColour(RainglowEntity entityType, DataTracker tracker, RandomGenerator random) { // generate random colour if the squid's colour isn't currently loaded - String colour = tracker.get(getTrackedColourData(entityType)); - if (colourUnloaded(colour)) { + String colour = tracker.get(entityType.getTrackedData()); + if (colourUnloaded(entityType, colour)) { // Use last generated colour if not null else generate a new colour - tracker.set(getTrackedColourData(entityType), generateRandomColourId(random)); - colour = tracker.get(getTrackedColourData(entityType)); + tracker.set(entityType.getTrackedData(), generateRandomColourId(random)); + colour = tracker.get(entityType.getTrackedData()); } - return colour; + return RainglowColour.get(colour); } } diff --git a/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java b/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java index 7d53184..c84c628 100644 --- a/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java +++ b/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java @@ -1,9 +1,12 @@ package io.ix0rai.rainglow.client; +import folk.sisby.kaleido.lib.quiltconfig.api.values.TrackedValue; +import folk.sisby.kaleido.lib.quiltconfig.api.values.ValueList; +import folk.sisby.kaleido.lib.quiltconfig.api.values.ValueMap; import io.ix0rai.rainglow.Rainglow; +import io.ix0rai.rainglow.data.RainglowColour; import io.ix0rai.rainglow.data.RainglowMode; import io.ix0rai.rainglow.data.RainglowResourceReloader; -import io.ix0rai.rainglow.data.RainglowColour; import io.ix0rai.rainglow.data.RainglowNetworking; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; @@ -11,56 +14,58 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.client.MinecraftClient; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import java.util.ArrayList; -import java.util.Collection; import java.util.List; @Environment(EnvType.CLIENT) public class RainglowClient implements ClientModInitializer { @Override public void onInitializeClient() { - ClientPlayNetworking.registerGlobalReceiver(RainglowNetworking.CONFIG_SYNC_ID, (client, handler, buf, responseSender) -> { - String mode = buf.readString(); - - List colourIds = buf.readList(PacketByteBuf::readString); - List colours = colourIds.stream().map(RainglowColour::get).toList(); - - client.execute(() -> { - // custom must be set before mode so that if the server sends a custom mode it is set correctly - // otherwise the client's custom would be used - Rainglow.CONFIG.setCustom(colours); - Rainglow.CONFIG.setMode(RainglowMode.byId(mode)); + ClientPlayNetworking.registerGlobalReceiver(RainglowNetworking.ConfigSyncPayload.PACKET_ID, (payload, context) -> { + MinecraftClient client = context.client(); + if (!client.isIntegratedServerRunning()) { + client.execute(() -> { + // custom must be set before mode so that if the server sends a custom mode it is set correctly + // otherwise the client's custom would be used + ValueList customColours = ValueList.create("", payload.customMode().stream().map(RainglowColour::getId).toArray(String[]::new)); + Rainglow.CONFIG.customColours.setOverride(customColours); + Rainglow.CONFIG.mode.setOverride(payload.currentMode()); + + var rarities = ValueMap.builder(0); + for (var entry : payload.rarities().entrySet()) { + rarities.put(entry.getKey().getId(), entry.getValue()); + } + Rainglow.CONFIG.rarities.setOverride(rarities.build()); - // lock the config from reloading on resource reload - Rainglow.CONFIG.setEditLocked(true); + var toggles = ValueMap.builder(true); + for (var entry : payload.enabledMobs().entrySet()) { + toggles.put(entry.getKey().getId(), entry.getValue()); + } + Rainglow.CONFIG.toggles.setOverride(toggles.build()); - // log - Rainglow.LOGGER.info("received config from server: set mode to " + mode + " and custom colours to " + colourIds); - }); + // log + Rainglow.LOGGER.info("received config from server: set mode to " + payload.currentMode() + " and custom colours to " + payload.customMode()); + }); + } }); - ClientPlayNetworking.registerGlobalReceiver(RainglowNetworking.MODE_SYNC_ID, (client, handler, buf, responseSender) -> { - Collection modes = RainglowNetworking.readModeData(buf); - + ClientPlayNetworking.registerGlobalReceiver(RainglowNetworking.ModeSyncPayload.PACKET_ID, (payload, context) -> { + MinecraftClient client = context.client(); client.execute(() -> { List newModeIds = new ArrayList<>(); // add modes that do not exist on the client to the map - for (RainglowMode mode : modes) { + for (RainglowMode mode : payload.modes()) { if (!mode.existsLocally()) { newModeIds.add(mode.getId()); RainglowMode.addMode(mode); } } - // now that we have modes, we can load the config - if (Rainglow.CONFIG.isUninitialised()) { - Rainglow.CONFIG.reloadFromFile(); - } // log if (!newModeIds.isEmpty()) { @@ -71,13 +76,8 @@ public void onInitializeClient() { ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> client.execute(() -> { - if (Rainglow.CONFIG.isEditLocked(client)) { - // unlock config - Rainglow.CONFIG.setEditLocked(false); - - // reset values to those configured in file - Rainglow.CONFIG.reloadFromFile(); - } + // reset values to those configured in file + Rainglow.CONFIG.values().forEach(TrackedValue::removeOverride); }) ); diff --git a/src/main/java/io/ix0rai/rainglow/config/ConfigIo.java b/src/main/java/io/ix0rai/rainglow/config/ConfigIo.java deleted file mode 100644 index e3f33f2..0000000 --- a/src/main/java/io/ix0rai/rainglow/config/ConfigIo.java +++ /dev/null @@ -1,152 +0,0 @@ -package io.ix0rai.rainglow.config; - -import io.ix0rai.rainglow.Rainglow; -import net.fabricmc.loader.api.FabricLoader; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ConfigIo { - private static final String CONFIG_FILE_NAME = "rainglow.toml"; - private static final Path CONFIG_FILE_PATH = Paths.get(FabricLoader.getInstance().getConfigDir().resolve(CONFIG_FILE_NAME).toUri()); - - private ConfigIo() { - } - - public static boolean parseTomlBoolean(String value) { - return value.equals("true"); - } - - public static int parseTomlInt(String value) { - return Integer.parseInt(value); - } - - public static String parseTomlString(String string) { - try { - return string.split("\"")[1].split("\"")[0]; - } catch (Exception e) { - Rainglow.LOGGER.warn("failed to parse toml string " + string + "; config will reset to default value"); - return ""; - } - } - - public static List parseTomlStringList(String list) { - List parsedList = new ArrayList<>(); - - // trim brackets - try { - String rawList = list.split("\\[")[1].split("]")[0]; - // separate by comma - String[] contents = rawList.split(","); - - for (String item : contents) { - // trim - item = item.trim(); - - // trim quotes and add to list - parsedList.add(item.split("\"")[1].split("\"")[0]); - } - } catch (Exception e) { - Rainglow.LOGGER.error("failed to parse toml list " + list + "; config will reset to default value"); - } - - return parsedList; - } - - public static Map readConfig() { - String content; - try { - content = Files.readString(CONFIG_FILE_PATH); - } catch (IOException e) { - Rainglow.LOGGER.warn("config file not found or corrupted; failed to read: creating new file with default values!"); - createConfigFile(); - return new HashMap<>(); - } - - String[] lines; - try { - lines = content.split("\n"); - } catch (Exception e) { - Rainglow.LOGGER.warn("config file not found or corrupted; failed to read: creating new file with default values!"); - createConfigFile(); - return new HashMap<>(); - } - - Map configData = new HashMap<>(); - - for (String line : lines) { - try { - if (line.isBlank() || line.startsWith("#")) { - continue; - } - - String[] splitLine = line.split("="); - - configData.put(splitLine[0].trim(), splitLine[1].trim()); - } catch (Exception e) { - Rainglow.LOGGER.warn("failed to read line \"" + line + "\" of config file; line will reset to default value"); - } - } - - return configData; - } - - public static void createConfigFile() { - try { - Files.createFile(CONFIG_FILE_PATH); - } catch (IOException e) { - Rainglow.LOGGER.warn("could not create config file!"); - } - } - - public static void writeString(String key, String string) { - write(key, "\"" + string + "\"", "string"); - } - - public static void writeBoolean(String key, boolean bool) { - write(key, bool ? "true" : "false", "boolean"); - } - - public static void writeInt(String key, int value) { - write(key, Integer.toString(value), "int"); - } - - public static void writeStringList(String key, List list) { - // convert to toml-friendly format - StringBuilder tomlCompatibleList = new StringBuilder("["); - for (int i = 0; i < list.size(); i ++) { - tomlCompatibleList.append("\"").append(list.get(i).toString()).append("\"").append(i == list.size() - 1 ? "" : ", "); - } - tomlCompatibleList.append("]"); - - write(key, tomlCompatibleList.toString(), "string list"); - } - - private static void write(String key, String value, String type) { - try { - String content = Files.readString(CONFIG_FILE_PATH); - String[] lines = content.split("\n"); - - for (int i = 0; i < lines.length; i++) { - if (lines[i].startsWith(key)) { - // if key is found replace line - lines[i] = key + " = " + value; - break; - } else if (i == lines.length - 1) { - // if key is not found append it to the end - lines[i] += (!lines[i].isBlank() ? "\n" : "") + key + " = " + value; - } - } - - Files.writeString(CONFIG_FILE_PATH, String.join("\n", lines)); - } catch (IOException e) { - Rainglow.LOGGER.warn("could not write object " + value + " of type " + type + " to config file under key \"" + key + "\"!"); - } - } -} diff --git a/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java b/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java index b0537a2..02df6b1 100644 --- a/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java @@ -1,89 +1,123 @@ package io.ix0rai.rainglow.config; -import dev.lambdaurora.spruceui.Position; -import dev.lambdaurora.spruceui.option.SpruceBooleanOption; -import dev.lambdaurora.spruceui.option.SpruceOption; -import dev.lambdaurora.spruceui.option.SpruceSimpleActionOption; -import dev.lambdaurora.spruceui.widget.container.SpruceOptionListWidget; import io.ix0rai.rainglow.Rainglow; import io.ix0rai.rainglow.data.RainglowColour; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; -import org.jetbrains.annotations.Nullable; +import net.minecraft.client.gui.screen.option.GameOptionsScreen; +import net.minecraft.client.gui.widget.button.ButtonWidget; +import net.minecraft.client.gui.widget.layout.HeaderFooterLayoutWidget; +import net.minecraft.client.gui.widget.layout.LinearLayoutWidget; +import net.minecraft.client.gui.widget.list.ButtonListWidget; +import net.minecraft.client.gui.widget.text.TextWidget; +import net.minecraft.client.option.Option; +import net.minecraft.client.toast.SystemToast; +import net.minecraft.client.toast.Toast; +import net.minecraft.text.CommonTexts; +import net.minecraft.text.Text; import java.util.ArrayList; import java.util.List; -public class CustomModeScreen extends RainglowScreen { - private final SpruceOption clearOption; - private final SpruceOption saveOption; - private final SpruceBooleanOption[] colourToggles = new SpruceBooleanOption[RainglowColour.values().length]; - private final boolean[] toggleStates = new boolean[RainglowColour.values().length]; - - public CustomModeScreen(@Nullable Screen parent) { - super(parent, Rainglow.translatableText("config.title")); - - // create toggles for each colour - for (int i = 0; i < RainglowColour.values().length; i ++) { - final RainglowColour colour = RainglowColour.values()[i]; - final int index = i; - - toggleStates[index] = Rainglow.CONFIG.getCustom().contains(colour); - - colourToggles[index] = new SpruceBooleanOption(Rainglow.translatableTextKey("colour." + colour.getId()), - () -> toggleStates[index], - enable -> toggleStates[index] = enable, - null, - true - ); - } - - // toggles all colours to false - this.clearOption = SpruceSimpleActionOption.of(Rainglow.translatableTextKey("config.clear"), - btn -> { - for (int i = 0; i < RainglowColour.values().length; i ++) { - toggleStates[i] = false; - } - - MinecraftClient client = MinecraftClient.getInstance(); - this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); - }); - - // writes all the toggled colours to the config and reloads custom mode - this.saveOption = SpruceSimpleActionOption.of(Rainglow.translatableTextKey("config.save"), - buttonWidget -> { - List newCustom = new ArrayList<>(); - - for (int i = 0; i < RainglowColour.values().length; i ++) { - if (toggleStates[i]) { - newCustom.add(RainglowColour.values()[i]); - } - } - - Rainglow.CONFIG.setCustom(newCustom); - Rainglow.CONFIG.saveCustom(); - this.closeScreen(); - } - ); - } - - @Override - protected void init() { - super.init(); - - // create a list of toggles for each colour - SpruceOptionListWidget options = new SpruceOptionListWidget(Position.of(0, 22), this.width, this.height - (35 + 22)); - for (int i = 0; i < RainglowColour.values().length; i += 2) { - SpruceOption secondToggle = null; - if (i + 1 < RainglowColour.values().length) { - secondToggle = colourToggles[i + 1]; - } - options.addOptionEntry(colourToggles[i], secondToggle); - } - this.addDrawableSelectableElement(options); - - // save and clear buttons - this.addDrawableSelectableElement(this.clearOption.createWidget(Position.of(this, this.width / 2 - 155, this.height - 29), 150)); - this.addDrawableSelectableElement(this.saveOption.createWidget(Position.of(this, this.width / 2 - 155 + 160, this.height - 29), 150)); - } +public class CustomModeScreen extends GameOptionsScreen implements ScreenWithUnsavedWarning { + private final ButtonWidget saveButton; + private final List> options = new ArrayList<>(); + private boolean isConfirming; + + private static final Text TITLE = Rainglow.translatableText("config.custom"); + + public CustomModeScreen(Screen parent) { + super(parent, MinecraftClient.getInstance().options, TITLE); + this.saveButton = ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> { + boolean hasColourSelected = false; + for (DeferredSaveOption option : this.options) { + if (option.deferredValue) { + hasColourSelected = true; + break; + } + } + + if (!hasColourSelected) { + sendNoColoursToast(); + } else { + this.save(); + } + }).build(); + this.saveButton.active = false; + } + + private void createColourToggles() { + this.options.clear(); + + for (RainglowColour colour : RainglowColour.values()) { + this.options.add(DeferredSaveOption.createDeferredBoolean( + "colour." + colour.getId(), + null, + Rainglow.CONFIG.customColours.getRealValue().contains(colour.getId()), + enabled -> { + if (enabled) { + Rainglow.CONFIG.customColours.getRealValue().add(colour.getId()); + } + }, + enabled -> this.saveButton.active = true + )); + } + } + + private void save() { + Rainglow.CONFIG.customColours.getRealValue().clear(); + + for (DeferredSaveOption option : this.options) { + option.save(); + } + + Rainglow.CONFIG.save(); + this.saveButton.active = false; + } + + @Override + public void init() { + HeaderFooterLayoutWidget headerFooterWidget = new HeaderFooterLayoutWidget(this, 61, 33); + headerFooterWidget.addToHeader(new TextWidget(TITLE, this.textRenderer), settings -> settings.alignHorizontallyCenter().setBottomPadding(28)); + + if (!this.isConfirming) { + ButtonListWidget buttonListWidget = headerFooterWidget.addToContents(new ButtonListWidget(this.client, this.width, this.height, this)); + createColourToggles(); + buttonListWidget.addEntries(this.options.toArray(new Option[0])); + + LinearLayoutWidget linearLayout = headerFooterWidget.addToFooter(LinearLayoutWidget.createHorizontal().setSpacing(8)); + linearLayout.add(ButtonWidget.builder(CommonTexts.DONE, button -> this.closeScreen()).build()); + linearLayout.add(this.saveButton); + } else { + this.setUpUnsavedWarning(headerFooterWidget, this.textRenderer, this.parent); + } + + headerFooterWidget.visitWidgets(this::addDrawableSelectableElement); + headerFooterWidget.arrangeElements(); + } + + private static void sendNoColoursToast() { + Toast toast = new SystemToast(SystemToast.Id.PACK_LOAD_FAILURE, Rainglow.translatableText("config.no_custom_colours"), Rainglow.translatableText("config.no_custom_colours_description")); + MinecraftClient.getInstance().getToastManager().add(toast); + } + + @Override + public void setConfirming(boolean confirming) { + this.isConfirming = confirming; + } + + @Override + public void clearAndInit() { + super.clearAndInit(); + } + + @Override + public void closeScreen() { + if (this.saveButton.active) { + this.isConfirming = true; + this.clearAndInit(); + } else { + MinecraftClient.getInstance().setScreen(this.parent); + } + } } diff --git a/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java b/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java new file mode 100644 index 0000000..ff1b927 --- /dev/null +++ b/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java @@ -0,0 +1,71 @@ +package io.ix0rai.rainglow.config; + +import com.mojang.serialization.Codec; +import io.ix0rai.rainglow.Rainglow; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.option.Option; + +import java.util.function.Consumer; + +public class DeferredSaveOption extends Option { + public T deferredValue; + private final Consumer clickCallback; + + public DeferredSaveOption(String key, TooltipSupplier tooltipSupplier, OptionTextGetter textGetter, Option.ValueSet values, T defaultValue, Consumer updateCallback, Consumer clickCallback) { + this(key, tooltipSupplier, textGetter, values, values.codec(), defaultValue, updateCallback, clickCallback); + } + + public DeferredSaveOption(String key, TooltipSupplier tooltipSupplier, OptionTextGetter textGetter, Option.ValueSet values, Codec codec, T defaultValue, Consumer updateCallback, Consumer clickCallback) { + super(key, tooltipSupplier, textGetter, values, codec, defaultValue, updateCallback); + this.deferredValue = this.value; + this.clickCallback = clickCallback; + } + + @Override + public void set(T value) { + T object = this.getValues().validate(value).orElseGet(() -> { + System.out.println("Illegal option value " + value + " for " + this.text); + return this.defaultValue; + }); + + if (!MinecraftClient.getInstance().isRunning()) { + this.deferredValue = object; + } else { + this.deferredValue = object; + if (!object.equals(this.value)) { + this.clickCallback.accept(object); + } + // note: update callback is called on save + } + } + + public static DeferredSaveOption createDeferredBoolean(String key, String tooltip, boolean defaultValue, Consumer updateCallback, Consumer clickCallback) { + return new DeferredSaveOption<>( + Rainglow.translatableTextKey(key), + tooltip != null ? Option.constantTooltip(Rainglow.translatableText(tooltip)) : Option.emptyTooltip(), + (text, value) -> value ? RainglowConfigScreen.YES : RainglowConfigScreen.NO, + BOOLEAN_VALUES, + defaultValue, + updateCallback, + clickCallback + ); + } + + public static DeferredSaveOption createDeferredRangedInt(String key, String tooltip, int defaultValue, int min, int max, Consumer updateCallback, Consumer clickCallback) { + return new DeferredSaveOption<>( + Rainglow.translatableTextKey(key), + tooltip != null ? Option.constantTooltip(Rainglow.translatableText(tooltip)) : Option.emptyTooltip(), + (text, value) -> Rainglow.translatableText(key + ".value", value), + new Option.IntRangeValueSet(min, max), + Codec.intRange(min, max), + defaultValue, + updateCallback, + clickCallback + ); + } + + public void save() { + this.value = this.deferredValue; + this.updateCallback.accept(this.value); + } +} diff --git a/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java b/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java index 3e379bb..e5c45ae 100644 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java +++ b/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java @@ -1,177 +1,85 @@ package io.ix0rai.rainglow.config; +import folk.sisby.kaleido.api.ReflectiveConfig; +import folk.sisby.kaleido.lib.quiltconfig.api.annotations.Comment; +import folk.sisby.kaleido.lib.quiltconfig.api.annotations.SerializedNameConvention; +import folk.sisby.kaleido.lib.quiltconfig.api.metadata.NamingSchemes; +import folk.sisby.kaleido.lib.quiltconfig.api.values.TrackedValue; +import folk.sisby.kaleido.lib.quiltconfig.api.values.ValueList; +import folk.sisby.kaleido.lib.quiltconfig.api.values.ValueMap; import io.ix0rai.rainglow.Rainglow; import io.ix0rai.rainglow.data.RainglowColour; import io.ix0rai.rainglow.data.RainglowEntity; import io.ix0rai.rainglow.data.RainglowMode; -import net.fabricmc.api.EnvType; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import java.util.ArrayList; -import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; +import java.util.stream.Collectors; + +@SerializedNameConvention(NamingSchemes.SNAKE_CASE) +public class RainglowConfig extends ReflectiveConfig { + @Comment("The currently active rainglow mode, which determines the possible colours for entities to spawn with.") + @Comment("If custom, will be reset to the default mode if you join a server that does not have the mode.") + public final TrackedValue mode = this.value("rainbow"); + @Comment("The rarity of coloured entities, with 0 making all entities vanilla and 100 making all entities coloured.") + public final TrackedValue> rarities = this.createMap(100); + @Comment("Toggles for disabling colours for each entity.") + public final TrackedValue> toggles = this.createMap(true); + @Comment("The custom colours to use when the mode is set to custom.") + public final TrackedValue> customColours = this.list("", RainglowMode.getDefaultCustom().stream().map(RainglowColour::getId).toArray(String[]::new)); -public class RainglowConfig { - public static final String MODE_KEY = "mode"; - public static final String CUSTOM_KEY = "custom"; - public static final String SERVER_SYNC_KEY = "enable_server_sync"; - - public static final String RARITY_KEY = "rarity"; - public static final Function TO_CONFIG_KEY = entity -> "enable_" + entity.getId(); - - private RainglowMode mode; - private List custom; - private int rarity; - private boolean enableServerSync; - private boolean editLocked = false; - private boolean isInitialised = false; - private final Map entityToggles = new EnumMap<>(RainglowEntity.class); - - public RainglowConfig() { - // we cannot load the config here because it would be loaded before modes, since it's statically initialised - } - - public void reloadFromFile() { - // read config from file - Map config = ConfigIo.readConfig(); - - // parse mode - RainglowMode rainglowMode = RainglowMode.getDefault(); - if (config.containsKey(MODE_KEY)) { - RainglowMode parsedMode = RainglowMode.byId(ConfigIo.parseTomlString(config.get(MODE_KEY))); - if (parsedMode != null) { - rainglowMode = parsedMode; - } - } - - // parse colours for custom mode - // note: we cannot get the default colours from the enum to start off as it's an immutable list - List customColours = new ArrayList<>(); - if (config.containsKey(CUSTOM_KEY)) { - List colours = ConfigIo.parseTomlStringList(config.get(CUSTOM_KEY)); - - for (String colour : colours) { - RainglowColour squidColour = RainglowColour.get(colour); - if (squidColour != null) { - customColours.add(squidColour); - } - } - } - - // parse server sync - boolean serverSync = true; - if (config.containsKey(SERVER_SYNC_KEY)) { - serverSync = ConfigIo.parseTomlBoolean(config.get(SERVER_SYNC_KEY)); - } - - // parse entity toggles - for (RainglowEntity entity : RainglowEntity.values()) { - String configKey = TO_CONFIG_KEY.apply(entity); - - if (config.containsKey(configKey)) { - entityToggles.put(entity, ConfigIo.parseTomlBoolean(config.get(configKey))); - } else { - entityToggles.put(entity, true); - } - } - - // parse rarity - int rarity = 100; - if (config.containsKey(RARITY_KEY)) { - rarity = ConfigIo.parseTomlInt(config.get(RARITY_KEY)); - } + public RainglowMode getMode() { + var mode = RainglowMode.get(this.mode.value()); - // reset colours if parsing failed - if (customColours.isEmpty()) { - customColours = RainglowMode.getDefaultCustom(); + if (mode == null) { + Rainglow.LOGGER.warn("unknown mode {}, defaulting to rainbow", this.mode.value()); + this.mode.setValue("rainbow"); + return getMode(); } - // set and write - this.mode = rainglowMode; - this.custom = customColours; - this.enableServerSync = serverSync; - this.rarity = rarity; - this.save(false); - - this.isInitialised = true; - } - - public RainglowMode getMode() { - return this.mode; + return mode; } public List getCustom() { - return this.custom; - } - - public int getRarity() { - return this.rarity; + return this.customColours.value().stream().map(RainglowColour::get).collect(Collectors.toList()); } - public boolean isServerSyncEnabled() { - return this.enableServerSync; - } - - public boolean isEditLocked(MinecraftClient client) { - // client can only be locked inside a multiplayer server - return !client.isInSingleplayer() && (client.getCurrentServerEntry() != null && this.editLocked); - } - - public boolean isUninitialised() { - return !this.isInitialised; - } - - public void setMode(RainglowMode mode) { - this.mode = mode; - Rainglow.setMode(mode); - } + public Map getToggles() { + Map map = new HashMap<>(); + for (RainglowEntity entity : RainglowEntity.values()) { + map.put(entity, this.isEntityEnabled(entity)); + } - public void setCustom(List custom) { - this.custom = custom; - Rainglow.refreshColours(); + return map; } - public void setRarity(int rarity) { - this.rarity = rarity; - } + public Map getRarities() { + Map map = new HashMap<>(); + for (RainglowEntity entity : RainglowEntity.values()) { + map.put(entity, this.getRarity(entity)); + } - public void setEditLocked(boolean editLocked) { - this.editLocked = editLocked; + return map; } public boolean isEntityEnabled(RainglowEntity entity) { - return this.entityToggles.get(entity); + return this.toggles.value().get(entity.getId()); } - public void setEntityEnabled(RainglowEntity entity, boolean enabled) { - this.entityToggles.put(entity, enabled); + public int getRarity(RainglowEntity entity) { + return this.rarities.value().get(entity.getId()); } - public void save(boolean log) { - if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER || !this.isEditLocked(MinecraftClient.getInstance())) { - ConfigIo.writeString(MODE_KEY, this.mode.getId()); - this.saveCustom(); - ConfigIo.writeBoolean(SERVER_SYNC_KEY, this.enableServerSync); - ConfigIo.writeInt(RARITY_KEY, this.rarity); - } - - // entity toggles cannot be locked by the server - this.writeEntityToggles(); - if (log) { - Rainglow.LOGGER.info("saved config!"); + /** + * creates a map of default values for each {@link RainglowEntity} + */ + private TrackedValue> createMap(T defaultValue) { + var builder = this.map(defaultValue); + for (RainglowEntity entity : RainglowEntity.values()) { + builder.put(entity.getId(), defaultValue); } - } - public void saveCustom() { - ConfigIo.writeStringList(CUSTOM_KEY, this.custom); - } - - private void writeEntityToggles() { - for (Map.Entry entry : entityToggles.entrySet()) { - ConfigIo.writeBoolean(TO_CONFIG_KEY.apply(entry.getKey()), entry.getValue()); - } + return builder.build(); } } diff --git a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java index 8b2792f..18dbbe8 100644 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java @@ -1,165 +1,179 @@ package io.ix0rai.rainglow.config; -import dev.lambdaurora.spruceui.Position; -import dev.lambdaurora.spruceui.option.SpruceBooleanOption; -import dev.lambdaurora.spruceui.option.SpruceCyclingOption; -import dev.lambdaurora.spruceui.option.SpruceIntegerInputOption; -import dev.lambdaurora.spruceui.option.SpruceOption; -import dev.lambdaurora.spruceui.option.SpruceSimpleActionOption; -import dev.lambdaurora.spruceui.widget.SpruceLabelWidget; -import dev.lambdaurora.spruceui.widget.container.SpruceOptionListWidget; import io.ix0rai.rainglow.Rainglow; import io.ix0rai.rainglow.data.RainglowColour; import io.ix0rai.rainglow.data.RainglowEntity; import io.ix0rai.rainglow.data.RainglowMode; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.toast.SystemToast; -import net.minecraft.client.toast.Toast; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.button.ButtonWidget; +import net.minecraft.client.gui.widget.button.CyclingButtonWidget; +import net.minecraft.client.gui.widget.layout.GridWidget; +import net.minecraft.client.gui.widget.layout.HeaderFooterLayoutWidget; +import net.minecraft.client.gui.widget.layout.LayoutSettings; +import net.minecraft.client.gui.widget.layout.LinearLayoutWidget; +import net.minecraft.client.gui.widget.text.TextWidget; +import net.minecraft.client.option.Option; +import net.minecraft.text.CommonTexts; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Language; import org.jetbrains.annotations.Nullable; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Supplier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; -public class RainglowConfigScreen extends RainglowScreen { - private final SpruceOption modeOption; - private final SpruceOption customOption; - private final SpruceOption[] entityToggles = new SpruceOption[RainglowEntity.values().length]; - private final SpruceOption resetOption; - private final SpruceOption saveOption; +public class RainglowConfigScreen extends Screen implements ScreenWithUnsavedWarning { + private static final Text TITLE = Rainglow.translatableText("config.title"); + public static final Text YES = Text.translatable("gui.yes").styled(style -> style.withColor(0x00FF00)); + public static final Text NO = Text.translatable("gui.no").styled(style -> style.withColor(0xFF0000)); + + private final Screen parent; + private final Map> toggles = new HashMap<>(); + private final Map> sliders = new HashMap<>(); + private final ButtonWidget saveButton; - private final SpruceOption colourRarityOption; private RainglowMode mode; - // colours to apply is saved in a variable so that it can be removed from the screen when cycling modes - private SpruceLabelWidget coloursToApplyLabel; + private boolean isConfirming; public RainglowConfigScreen(@Nullable Screen parent) { - super(parent, Rainglow.translatableText("config.title")); - this.mode = Rainglow.CONFIG.getMode(); - - // mode option cycles through available modes - // it also updates the label to show which colours will be applied - this.modeOption = new SpruceCyclingOption(Rainglow.translatableTextKey("config.mode"), - amount -> { - if (!Rainglow.CONFIG.isEditLocked(MinecraftClient.getInstance())) { - mode = mode.cycle(); - this.remove(this.coloursToApplyLabel); - this.coloursToApplyLabel = createColourListLabel(Rainglow.translatableTextKey("config.colours_to_apply"), this.mode, this.width / 2 - 125, this.height / 4 + 40); - this.addDrawable(this.coloursToApplyLabel); - } else { - sendConfigLockedToast(); - } - }, - option -> option.getDisplayText(mode.getText()), - Rainglow.translatableText("tooltip.mode", - List.of(RainglowMode.values()) - ) - ); - - // opens a screen to toggle which colours are applied in custom mode - this.customOption = SpruceSimpleActionOption.of(Rainglow.translatableTextKey("config.custom"), - btn -> MinecraftClient.getInstance().setScreen(new CustomModeScreen(this)) - ); - - // toggles whether entities are rainbow - for (int i = 0; i < RainglowEntity.values().length; i ++) { - RainglowEntity entity = RainglowEntity.values()[i]; - - this.entityToggles[i] = createEntityToggle( - entity, - () -> Rainglow.CONFIG.isEntityEnabled(entity), - enabled -> Rainglow.CONFIG.setEntityEnabled(entity, enabled) - ); - } - - this.colourRarityOption = new SpruceIntegerInputOption(Rainglow.translatableTextKey("config.rarity"), - Rainglow.CONFIG::getRarity, - Rainglow.CONFIG::setRarity, - Rainglow.translatableText("tooltip.rarity") - ); - - // resets the config to default values - this.resetOption = SpruceSimpleActionOption.reset(btn -> { - MinecraftClient client = MinecraftClient.getInstance(); - if (!Rainglow.CONFIG.isEditLocked(client)) { - this.mode = RainglowMode.getDefault(); - this.init(client, client.getWindow().getScaledWidth(), client.getWindow().getScaledHeight()); - } else { - sendConfigLockedToast(); - } - }); - - // saves values to config file - this.saveOption = SpruceSimpleActionOption.of(Rainglow.translatableTextKey("config.save"), - buttonWidget -> { - this.closeScreen(); - Rainglow.CONFIG.setMode(this.mode); - Rainglow.CONFIG.save(true); - } - ); + super(TITLE); + this.parent = parent; + this.mode = RainglowMode.get(Rainglow.CONFIG.mode.getRealValue()); + this.saveButton = ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> this.save()).build(); + this.saveButton.active = false; } - private SpruceBooleanOption createEntityToggle(RainglowEntity entity, Supplier getter, Consumer setter) { - return new SpruceBooleanOption(Rainglow.translatableTextKey("config." + "enable_" + entity.getId()), - getter, - setter, - null - ); + private TextWidget getInfoText() { + if (MinecraftClient.getInstance().isInSingleplayer()) { + return new TextWidget((Rainglow.RAINGLOW_DATAPACKS.size() == 1 ? Rainglow.translatableText("config.loaded_builtin", RainglowMode.values().size()) : Rainglow.translatableText("config.loaded_datapacks", RainglowMode.values().size(), Rainglow.RAINGLOW_DATAPACKS.size())), this.textRenderer).setTextColor(0x00FFFF); + } else if (MinecraftClient.getInstance().world != null) { + return new TextWidget(Rainglow.translatableText("config.server_locked"), this.textRenderer).setTextColor(0xFF0000); + } else { + return new TextWidget(Rainglow.translatableText("config.no_world"), this.textRenderer).setTextColor(0xFF0000); + } } @Override - protected void init() { - super.init(); + public void init() { + HeaderFooterLayoutWidget headerFooterWidget = new HeaderFooterLayoutWidget(this, 61, 33); + LinearLayoutWidget headerLayout = headerFooterWidget.addToHeader(LinearLayoutWidget.createVertical().setSpacing(8)); + + if (!this.isConfirming) { + // header + headerLayout.add(new TextWidget(TITLE, this.textRenderer), settings -> settings.alignHorizontallyCenter().alignVerticallyTop().setPadding(12)); + headerLayout.add(createModeButton(), LayoutSettings::alignVerticallyBottom); + headerLayout.add(getInfoText(), LayoutSettings::alignHorizontallyCenter); + + // contents + LinearLayoutWidget contentLayout = LinearLayoutWidget.createVertical(); - SpruceOptionListWidget optionList = new SpruceOptionListWidget(Position.of(0, 22), this.width, this.height - (35 + 22)); - for (int i = 0; i < RainglowEntity.values().length; i += 2) { - SpruceOption secondToggle = null; - int l = RainglowEntity.values().length; + GridWidget gridWidget = new GridWidget(); + gridWidget.getDefaultSettings().setHorizontalPadding(4).setBottomPadding(4).alignHorizontallyCenter(); - if (i + 1 < l) { - secondToggle = this.entityToggles[i + 1]; + GridWidget.AdditionHelper mainAdditionHelper = gridWidget.createAdditionHelper(2); + for (RainglowEntity entity : RainglowEntity.values()) { + DeferredSaveOption entityToggle = createEntityToggle(entity); + mainAdditionHelper.add(entityToggle.createButton(MinecraftClient.getInstance().options)); + entityToggle.set(entityToggle.deferredValue); + + mainAdditionHelper.add(createColourRaritySlider(entity).createButton(MinecraftClient.getInstance().options)); } - optionList.addOptionEntry(this.entityToggles[i], secondToggle); + contentLayout.add(gridWidget); + contentLayout.add(ButtonWidget.builder(Rainglow.translatableText("config.custom"), button -> MinecraftClient.getInstance().setScreen(new CustomModeScreen(this))).width(308).position(4, 0).build(), LayoutSettings.create().setPadding(4, 0)); + + headerFooterWidget.addToContents(contentLayout); + + // footer + LinearLayoutWidget linearLayout = headerFooterWidget.addToFooter(LinearLayoutWidget.createHorizontal().setSpacing(8)); + linearLayout.add(ButtonWidget.builder(CommonTexts.DONE, button -> this.closeScreen()).build()); + linearLayout.add(this.saveButton); + } else { + this.setUpUnsavedWarning(headerFooterWidget, this.textRenderer, this.parent); } - optionList.addOptionEntry(this.modeOption, this.customOption); - optionList.addSingleOptionEntry(this.colourRarityOption); - this.addDrawableSelectableElement(optionList); + headerFooterWidget.visitWidgets(this::addDrawableSelectableElement); + headerFooterWidget.arrangeElements(); + } + + private DeferredSaveOption createEntityToggle(RainglowEntity entity) { + return toggles.computeIfAbsent(entity, e -> DeferredSaveOption.createDeferredBoolean( + "config.enable_" + e.getId(), + "tooltip.entity_toggle", + Rainglow.CONFIG.toggles.getRealValue().get(e.getId()), + enabled -> Rainglow.CONFIG.toggles.getRealValue().put(e.getId(), enabled), + enabled -> this.saveButton.active = true + )); + } + + private DeferredSaveOption createColourRaritySlider(RainglowEntity entity) { + return sliders.computeIfAbsent(entity, e -> DeferredSaveOption.createDeferredRangedInt( + "config." + e.getId() + "_rarity", + "tooltip.rarity", + Rainglow.CONFIG.rarities.getRealValue().get(e.getId()), + 0, + 100, + rarity -> Rainglow.CONFIG.rarities.getRealValue().put(e.getId(), rarity), + rarity -> this.saveButton.active = true + )); + } + + public CyclingButtonWidget createModeButton() { + return CyclingButtonWidget.builder(RainglowMode::getText) + .values(RainglowMode.values()) + .initially(this.mode) + .tooltip(this::createColourListLabel) + .build( + 0, + 0, + 308, + 20, + Rainglow.translatableText("config.mode"), + (cyclingButtonWidget, mode) -> { + this.saveButton.active = true; + RainglowConfigScreen.this.mode = mode; + } + ); + } + + private void save() { + Collection> options = new ArrayList<>(this.sliders.values()); + options.addAll(this.toggles.values()); - // current colours label and colours to apply label - SpruceLabelWidget currentColoursLabel = createColourListLabel(Rainglow.translatableTextKey("config.current_colours"), Rainglow.CONFIG.getMode(), this.width / 2 - 290, this.height / 4 + 40); - this.addDrawable(currentColoursLabel); - this.coloursToApplyLabel = createColourListLabel(Rainglow.translatableTextKey("config.colours_to_apply"), this.mode, this.width / 2 - 125, this.height / 4 + 40); - this.addDrawable(this.coloursToApplyLabel); + for (Option option : options) { + if (option instanceof DeferredSaveOption) { + ((DeferredSaveOption) option).save(); + } + } - // reset and save buttons - this.addDrawableSelectableElement(this.resetOption.createWidget(Position.of(this, this.width / 2 - 155, this.height - 29), 150)); - this.addDrawableSelectableElement(this.saveOption.createWidget(Position.of(this, this.width / 2 - 155 + 160, this.height - 29), 150)); + Rainglow.CONFIG.mode.setValue(this.mode.getId()); + this.saveButton.active = false; } - private SpruceLabelWidget createColourListLabel(String translationKey, RainglowMode mode, int x, int y) { + private Tooltip createColourListLabel(RainglowMode mode) { // creates a label and appends all the colours that will be applied in the given mode - StringBuilder text = new StringBuilder(Language.getInstance().get(translationKey)); + StringBuilder text = new StringBuilder(Language.getInstance().get(Rainglow.translatableTextKey("config.colours_to_apply"))); int maxDisplayedColourCount = 16; + int maxColoursPerLine = 4; - for (int i = 0; i < mode.getColours().size(); i += 2) { - RainglowColour colour = mode.getColours().get(i); - + for (int i = 0; i < mode.getColours().size(); i += maxColoursPerLine) { if (i < maxDisplayedColourCount) { - String colour1 = Language.getInstance().get(Rainglow.translatableTextKey("colour." + colour.getId())); - String colour2 = ""; - if (i + 1 <= mode.getColours().size() - 1) { - colour2 = Language.getInstance().get(Rainglow.translatableTextKey("colour." + mode.getColours().get(i + 1).getId())); - } + text.append("\n"); - boolean appendComma = i + 2 < mode.getColours().size(); + int coloursLeft = mode.getColours().size() - i; + int coloursToDisplay = Math.min(coloursLeft, maxColoursPerLine); - text.append("\n").append(colour1).append(colour2.isEmpty() ? "" : ", ").append(colour2).append(appendComma ? "," : ""); + for (int j = 0; j < coloursToDisplay; j++) { + RainglowColour currentColour = mode.getColours().get(i + j); + text.append(Language.getInstance().get(Rainglow.translatableTextKey("colour." + currentColour.getId()))); + if (j < coloursToDisplay - 1) { + text.append(", "); + } + } } else { text.append("\n... ").append(mode.getColours().size() - maxDisplayedColourCount).append(" ").append(Language.getInstance().get(Rainglow.translatableTextKey("config.more"))); } @@ -167,11 +181,26 @@ private SpruceLabelWidget createColourListLabel(String translationKey, RainglowM // set colour to the mode's text colour Style style = Style.EMPTY.withColor(mode.getText().getStyle().getColor()); - return new SpruceLabelWidget(Position.of(this, x + 110, y), Text.literal(text.toString()).setStyle(style), 200, true); + return Tooltip.create(Text.literal(text.toString()).setStyle(style)); } - private static void sendConfigLockedToast() { - Toast toast = new SystemToast(SystemToast.C_ozahoshp.field_47585, Rainglow.translatableText("config.server_locked_title"), Rainglow.translatableText("config.server_locked_description")); - MinecraftClient.getInstance().getToastManager().add(toast); + @Override + public void closeScreen() { + if (this.saveButton.active) { + this.isConfirming = true; + this.clearAndInit(); + } else { + MinecraftClient.getInstance().setScreen(this.parent); + } + } + + @Override + public void setConfirming(boolean confirming) { + this.isConfirming = confirming; + } + + @Override + public void clearAndInit() { + super.clearAndInit(); } } diff --git a/src/main/java/io/ix0rai/rainglow/config/RainglowScreen.java b/src/main/java/io/ix0rai/rainglow/config/RainglowScreen.java deleted file mode 100644 index e5759a5..0000000 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowScreen.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.ix0rai.rainglow.config; - -import dev.lambdaurora.spruceui.screen.SpruceScreen; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.text.Text; -import org.jetbrains.annotations.Nullable; - -public abstract class RainglowScreen extends SpruceScreen { - protected final Screen parent; - - protected RainglowScreen(@Nullable Screen parent, Text title) { - super(title); - this.parent = parent; - } - - @Override - public void closeScreen() { - if (this.client != null) { - this.client.setScreen(this.parent); - } else { - super.closeScreen(); - } - } -} diff --git a/src/main/java/io/ix0rai/rainglow/config/ScreenWithUnsavedWarning.java b/src/main/java/io/ix0rai/rainglow/config/ScreenWithUnsavedWarning.java new file mode 100644 index 0000000..389d003 --- /dev/null +++ b/src/main/java/io/ix0rai/rainglow/config/ScreenWithUnsavedWarning.java @@ -0,0 +1,32 @@ +package io.ix0rai.rainglow.config; + +import io.ix0rai.rainglow.Rainglow; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.ButtonWidget; +import net.minecraft.client.gui.widget.layout.HeaderFooterLayoutWidget; +import net.minecraft.client.gui.widget.layout.LayoutSettings; +import net.minecraft.client.gui.widget.layout.LinearLayoutWidget; +import net.minecraft.client.gui.widget.text.TextWidget; +import net.minecraft.text.CommonTexts; + +public interface ScreenWithUnsavedWarning { + void setConfirming(boolean confirming); + + void clearAndInit(); + + default void setUpUnsavedWarning(HeaderFooterLayoutWidget headerFooterWidget, TextRenderer renderer, Screen parent) { + LinearLayoutWidget contentWidget = headerFooterWidget.addToContents(new LinearLayoutWidget(250, 100, LinearLayoutWidget.Orientation.VERTICAL).setSpacing(8)); + contentWidget.add(new TextWidget(Rainglow.translatableText("config.unsaved_warning"), renderer), LayoutSettings::alignHorizontallyCenter); + + LinearLayoutWidget buttons = new LinearLayoutWidget(250, 20, LinearLayoutWidget.Orientation.HORIZONTAL).setSpacing(8); + buttons.add(ButtonWidget.builder(Rainglow.translatableText("config.continue_editing"), (buttonWidget) -> { + this.setConfirming(false); + this.clearAndInit(); + }).build()); + buttons.add(ButtonWidget.builder(CommonTexts.YES, (buttonWidget) -> MinecraftClient.getInstance().setScreen(parent)).build()); + + contentWidget.add(buttons, LayoutSettings::alignHorizontallyCenter); + } +} diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java b/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java index 44d7813..f87b2e9 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java @@ -2,43 +2,49 @@ import net.minecraft.item.Item; import net.minecraft.item.Items; +import net.minecraft.network.PacketByteBuf; import net.minecraft.util.Identifier; +import net.minecraft.util.random.RandomGenerator; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.HashMap; +import java.util.Map; public enum RainglowColour { - BLACK(new RGB(0.0F, 0.0F, 0.0F), new RGB(0.0F, 0.0F, 0.0F), new RGB(0, 0, 0), Items.BLACK_DYE), - BLUE(new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 0.4F), new RGB(204, 31, 102), Items.BLUE_DYE), - BROWN(new RGB(1.0F, 0.5F, 0.0F), new RGB(1.0F, 0.4F, 0.4F), new RGB(149, 59, 35), Items.BROWN_DYE), // todo particles - CYAN(new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 0.4F), new RGB(204, 31, 102), Items.CYAN_DYE), // todo particles - GRAY(new RGB(0.6F, 0.6F, 0.6F), new RGB(0.4F, 0.4F, 0.4F), new RGB(100, 100, 100), Items.GRAY_DYE), - GREEN(new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 1.0F, 0.4F), new RGB(0, 200, 0), Items.GREEN_DYE), - INDIGO(new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 1.0F), new RGB(0, 0, 200), Items.AMETHYST_SHARD), - LIGHT_BLUE(new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 0.4F), new RGB(204, 31, 102), Items.LIGHT_BLUE_DYE), // todo particles - LIGHT_GRAY(new RGB(0.6F, 0.6F, 0.6F), new RGB(0.4F, 0.4F, 0.4F), new RGB(100, 100, 100), Items.LIGHT_GRAY_DYE), // todo particles - LIME(new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 1.0F, 0.4F), new RGB(0, 200, 0), Items.LIME_DYE), // todo particles - MAGENTA(new RGB(0.3F, 0F, 0.25F), new RGB(0.5F, 0.05F, 0.5F), new RGB(200, 0, 100), Items.MAGENTA_DYE), // todo particles - ORANGE(new RGB(1.0F, 0.5F, 0.0F), new RGB(1.0F, 0.4F, 0.4F), new RGB(200, 0, 0), Items.ORANGE_DYE), - PINK(new RGB(0.6F, 0F, 0.5F), new RGB(1.0F, 0.1F, 1.0F), new RGB(200, 0, 0), Items.PINK_DYE), - PURPLE(new RGB(0.3F, 0F, 0.25F), new RGB(0.5F, 0.05F, 0.5F), new RGB(200, 0, 100), Items.PURPLE_DYE), - RED(new RGB(1.0F, 1.0F, 0.8F), new RGB(1.0F, 0.4F, 0.4F), new RGB(200, 0, 0), Items.RED_DYE), - WHITE(new RGB(1.0F, 1.0F, 1.0F), new RGB(1.0F, 1.0F, 1.0F), new RGB(200, 200, 200), Items.WHITE_DYE), - YELLOW(new RGB(1.0F, 1.0F, 0.8F), new RGB(1.0F, 1.0F, 0.4F), new RGB(200, 0, 0), Items.YELLOW_DYE); + BLACK("black", new RGB(0.0F, 0.0F, 0.0F), new RGB(0.0F, 0.0F, 0.0F), new RGB(0, 0, 0), Items.BLACK_DYE), + BLUE("blue", new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 0.4F), new RGB(204, 31, 102), Items.BLUE_DYE), + BROWN("brown", new RGB(1.0F, 0.5F, 0.0F), new RGB(1.0F, 0.4F, 0.4F), new RGB(149, 59, 35), Items.BROWN_DYE), + CYAN("cyan", new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 0.4F), new RGB(204, 31, 102), Items.CYAN_DYE), + GRAY("gray", new RGB(0.6F, 0.6F, 0.6F), new RGB(0.4F, 0.4F, 0.4F), new RGB(100, 100, 100), Items.GRAY_DYE), + GREEN("green", new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 1.0F, 0.4F), new RGB(0, 200, 0), Items.GREEN_DYE), + INDIGO("indigo", new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 1.0F), new RGB(0, 0, 200), Items.AMETHYST_SHARD), + LIGHT_BLUE("light_blue", new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 0.4F, 0.4F), new RGB(204, 31, 102), Items.LIGHT_BLUE_DYE), + LIGHT_GRAY("light_gray", new RGB(0.6F, 0.6F, 0.6F), new RGB(0.4F, 0.4F, 0.4F), new RGB(100, 100, 100), Items.LIGHT_GRAY_DYE), + LIME("lime", new RGB(0.6F, 1.0F, 0.8F), new RGB(0.08F, 1.0F, 0.4F), new RGB(0, 200, 0), Items.LIME_DYE), + MAGENTA("magenta", new RGB(0.3F, 0F, 0.25F), new RGB(0.5F, 0.05F, 0.5F), new RGB(200, 0, 100), Items.MAGENTA_DYE), + ORANGE("orange", new RGB(1.0F, 0.5F, 0.0F), new RGB(1.0F, 0.4F, 0.4F), new RGB(200, 0, 0), Items.ORANGE_DYE), + PINK("pink", new RGB(0.6F, 0F, 0.5F), new RGB(1.0F, 0.1F, 1.0F), new RGB(200, 0, 0), Items.PINK_DYE), + PURPLE("purple", new RGB(0.3F, 0F, 0.25F), new RGB(0.5F, 0.05F, 0.5F), new RGB(200, 0, 100), Items.PURPLE_DYE), + RED("red", new RGB(1.0F, 1.0F, 0.8F), new RGB(1.0F, 0.4F, 0.4F), new RGB(200, 0, 0), Items.RED_DYE), + WHITE("white", new RGB(1.0F, 1.0F, 1.0F), new RGB(1.0F, 1.0F, 1.0F), new RGB(200, 200, 200), Items.WHITE_DYE), + YELLOW("yellow", new RGB(1.0F, 1.0F, 0.8F), new RGB(1.0F, 1.0F, 0.4F), new RGB(200, 0, 0), Items.YELLOW_DYE); private static final HashMap BY_ID = new HashMap<>(); static { Arrays.stream(values()).forEach(mode -> BY_ID.put(mode.getId(), mode)); } - private Identifier texture; + private final String id; + private final Map textures; private final RGB passiveParticleRgb; private final RGB altPassiveParticleRgb; private final RGB inkRgb; private final Item item; - RainglowColour(RGB passiveParticleRgb, RGB altPassiveParticleRgb, RGB inkRgb, Item item) { - this.texture = new Identifier("textures/entity/squid/" + this.getId() + ".png"); + RainglowColour(String id, RGB passiveParticleRgb, RGB altPassiveParticleRgb, RGB inkRgb, Item item) { + this.id = id; + this.textures = new HashMap<>(); this.passiveParticleRgb = passiveParticleRgb; this.altPassiveParticleRgb = altPassiveParticleRgb; this.inkRgb = inkRgb; @@ -46,23 +52,31 @@ public enum RainglowColour { } public Identifier getTexture(RainglowEntity entityType) { - // use minecraft's textures when possible, so we can ship fewer textures - if (entityType == RainglowEntity.GLOW_SQUID) { - String textureName = this.getId().equals("blue") ? "glow_squid" : this.getId(); - this.texture = new Identifier("textures/entity/squid/" + textureName + ".png"); - } else if (entityType == RainglowEntity.ALLAY) { - String textureName = this.getId().equals("blue") ? "allay" : this.getId(); - this.texture = new Identifier("textures/entity/allay/" + textureName + ".png"); - } else { - String textureName = this.getId().equals("lime") ? "slime" : this.getId(); - this.texture = new Identifier("textures/entity/slime/" + textureName + ".png"); + if (this.textures.isEmpty()) { + for (RainglowEntity entity : RainglowEntity.values()) { + // use minecraft's textures when possible, so we can ship fewer textures + switch (entity) { + case GLOW_SQUID -> { + String textureName = RainglowEntity.GLOW_SQUID.getDefaultColour() == this ? "glow_squid" : this.getId(); + this.textures.put(entity, new Identifier("textures/entity/squid/" + textureName + ".png")); + } + case ALLAY -> { + String textureName = RainglowEntity.ALLAY.getDefaultColour() == this ? "allay" : this.getId(); + this.textures.put(entity, new Identifier("textures/entity/allay/" + textureName + ".png")); + } + case SLIME -> { + String textureName = RainglowEntity.SLIME.getDefaultColour() == this ? "slime" : this.getId(); + this.textures.put(entity, new Identifier("textures/entity/slime/" + textureName + ".png")); + } + } + } } - return this.texture; + return this.textures.get(entityType); } public String getId() { - return this.name().toLowerCase(); + return this.id; } public RGB getPassiveParticleRgb() { @@ -86,10 +100,28 @@ public String toString() { return this.getId(); } + @Nullable public static RainglowColour get(String id) { return BY_ID.get(id); } + public static RainglowColour.RGB getInkRgb(int index) { + return RainglowColour.values()[index].getInkRgb(); + } + + public static RainglowColour.RGB getPassiveParticleRGB(int index, RandomGenerator random) { + RainglowColour colour = RainglowColour.values()[index]; + return random.nextBoolean() ? colour.getPassiveParticleRgb() : colour.getAltPassiveParticleRgb(); + } + public record RGB(float r, float g, float b) { } + + public static RainglowColour read(PacketByteBuf buf) { + return get(buf.readString()); + } + + public static void write(PacketByteBuf buf, RainglowColour entity) { + buf.writeString(entity.getId()); + } } diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java b/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java index 85e8445..b8eba45 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java @@ -1,17 +1,122 @@ package io.ix0rai.rainglow.data; +import io.ix0rai.rainglow.Rainglow; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityData; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; +import net.minecraft.entity.mob.SlimeEntity; +import net.minecraft.entity.passive.AllayEntity; +import net.minecraft.entity.passive.GlowSquidEntity; +import net.minecraft.item.Item; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; +import net.minecraft.util.random.RandomGenerator; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.function.Function; + public enum RainglowEntity { - GLOW_SQUID("glow_squid"), - ALLAY("allay"), - SLIME("slime"); + GLOW_SQUID("glow_squid", RainglowColour.BLUE, DataTracker.registerData(GlowSquidEntity.class, TrackedDataHandlerRegistry.STRING), GlowSquidEntityData::new), + ALLAY("allay", RainglowColour.BLUE, DataTracker.registerData(AllayEntity.class, TrackedDataHandlerRegistry.STRING), AllayEntityData::new), + SLIME("slime", RainglowColour.LIME, DataTracker.registerData(SlimeEntity.class, TrackedDataHandlerRegistry.STRING), SlimeEntityData::new); + + private static final HashMap BY_ID = new HashMap<>(); + static { + Arrays.stream(values()).forEach(mode -> BY_ID.put(mode.getId(), mode)); + } private final String id; + private final RainglowColour defaultColour; + private final TrackedData trackedData; + private final Function entityDataFactory; - RainglowEntity(String id) { + RainglowEntity(String id, RainglowColour defaultColour, TrackedData trackedData, Function entityDataFactory) { this.id = id; - } + this.defaultColour = defaultColour; + this.trackedData = trackedData; + this.entityDataFactory = entityDataFactory; + } public String getId() { return this.id; } + + public RainglowColour getDefaultColour() { + return this.defaultColour; + } + + public TrackedData getTrackedData() { + return this.trackedData; + } + + public Identifier getDefaultTexture() { + return this.defaultColour.getTexture(this); + } + + public EntityData createEntityData(RainglowColour colour) { + return this.entityDataFactory.apply(colour); + } + + public Item getItem(int index) { + if (index == -1) { + return this.getDefaultColour().getItem(); + } + + return RainglowColour.values()[index].getItem(); + } + + public RainglowColour readNbt(NbtCompound nbt, RandomGenerator random) { + String colour = nbt.getString(Rainglow.CUSTOM_NBT_KEY); + + if (Rainglow.colourUnloaded(this, colour)) { + colour = Rainglow.generateRandomColourId(random); + } + + return RainglowColour.get(colour); + } + + public static RainglowEntity read(PacketByteBuf buf) { + return get(buf.readString()); + } + + public static void write(PacketByteBuf buf, RainglowEntity entity) { + buf.writeString(entity.id); + } + + @Nullable + public static RainglowEntity get(String id) { + return BY_ID.get(id); + } + + @Unique + @SuppressWarnings("all") + public static RainglowEntity get(Entity entity) { + if (entity instanceof GlowSquidEntity) { + return GLOW_SQUID; + } else if (entity instanceof AllayEntity) { + return ALLAY; + } else if (entity instanceof SlimeEntity) { + return SLIME; + } + + return null; + } + + public void overrideTexture(Entity entity, CallbackInfoReturnable cir) { + RainglowColour colour = Rainglow.getColour(this, entity.getDataTracker(), entity.getWorld().getRandom()); + + // if the colour is default we don't need to override the method + // this optimises a tiny bit + if (Rainglow.CONFIG.isEntityEnabled(this) && colour != this.getDefaultColour()) { + Identifier texture = colour.getTexture(this); + cir.setReturnValue(texture != null ? texture : this.getDefaultTexture()); + } + } } diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java b/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java index 6fc5cf8..4c94a53 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java @@ -1,13 +1,14 @@ package io.ix0rai.rainglow.data; import io.ix0rai.rainglow.Rainglow; +import net.minecraft.network.PacketByteBuf; import net.minecraft.text.Style; import net.minecraft.text.Text; +import net.minecraft.text.TextCodecs; import net.minecraft.text.TextColor; import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; @@ -31,7 +32,7 @@ public RainglowMode(JsonMode mode, boolean existsLocally) { public RainglowMode(String id, List colourIds, Text text, boolean existsLocally) { if (!id.matches("^[a-z0-9_]+$")) { - throw new IllegalArgumentException("loaded rainglow mode with id " + id + " which contains invalid characters"); + Rainglow.LOGGER.error("loaded rainglow mode with id {} which contains invalid characters! (only lowercase letters, numbers, and underscores are allowed)", id); } this.id = id; @@ -45,6 +46,10 @@ public RainglowMode(String id, List colourIds, Text text, boolean exists this.colours.add(RainglowColour.get(colour)); } + if (this.colours.isEmpty() && !id.equals("all_colours") && !id.equals("custom")) { + Rainglow.LOGGER.error("cannot load mode with id {}: no colours found!", id); + } + this.text = text; this.existsLocally = existsLocally; @@ -61,23 +66,6 @@ public List getColours() { }; } - public RainglowMode cycle() { - // cycle to next in list, wrapping around to 0 if the next ordinal is larger than the map's size - Collection values = MODES.values(); - Iterator iterator = values.iterator(); - - // look for matching key and return next mode - while (iterator.hasNext()) { - RainglowMode mode = iterator.next(); - if (mode.id.equals(this.id) && iterator.hasNext()) { - return iterator.next(); - } - } - - // otherwise return first mode - return values.iterator().next(); - } - @Override public String toString() { return this.getId(); @@ -95,14 +83,10 @@ public boolean existsLocally() { return this.existsLocally; } - public static RainglowMode byId(String id) { + public static RainglowMode get(String id) { return MODES.get(id); } - public static RainglowMode getDefault() { - return MODES.get("rainbow"); - } - public static void addMode(RainglowMode mode) { MODES.put(mode.id, mode); } @@ -134,6 +118,21 @@ public static void printLoadedModes() { Rainglow.LOGGER.info("Loaded modes: [" + formatted + "]"); } + public static void write(PacketByteBuf buf, RainglowMode mode) { + buf.writeString(mode.getId()); + TextCodecs.UNLIMITED_TEXT_PACKET_CODEC.encode(buf, mode.getText()); + List colourIds = mode.getColours().stream().map(RainglowColour::getId).toList(); + buf.writeCollection(colourIds, PacketByteBuf::writeString); + } + + public static RainglowMode read(PacketByteBuf buf) { + String id = buf.readString(); + Text text = TextCodecs.UNLIMITED_TEXT_PACKET_CODEC.decode(buf); + List colourIds = buf.readList(PacketByteBuf::readString); + + return new RainglowMode(id, colourIds, text, RainglowMode.get(id) != null); + } + /** * represents modes loaded from json files diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowNetworking.java b/src/main/java/io/ix0rai/rainglow/data/RainglowNetworking.java index 4a62636..c0b17ae 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowNetworking.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowNetworking.java @@ -1,61 +1,71 @@ package io.ix0rai.rainglow.data; import io.ix0rai.rainglow.Rainglow; -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.payload.CustomPayload; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; -import net.minecraft.util.Identifier; import java.util.Collection; import java.util.List; +import java.util.Map; public class RainglowNetworking { - public static final Identifier CONFIG_SYNC_ID = Rainglow.id("config_sync"); - public static final Identifier MODE_SYNC_ID = Rainglow.id("mode_sync"); - public static void syncConfig(ServerPlayerEntity player) { - PacketByteBuf buf = PacketByteBufs.create(); - - // write current mode - buf.writeString(Rainglow.CONFIG.getMode().getId()); - - // write custom mode data - List colourIds = Rainglow.CONFIG.getCustom().stream().map(RainglowColour::getId).toList(); - buf.writeCollection(colourIds, PacketByteBuf::writeString); - // note: client does not need to know if server sync is enabled or not // they already know that it is enabled because they are receiving this packet - - ServerPlayNetworking.send(player, CONFIG_SYNC_ID, buf); + ServerPlayNetworking.send(player, new ConfigSyncPayload(Rainglow.CONFIG.mode.value(), Rainglow.CONFIG.getCustom(), Rainglow.CONFIG.getToggles(), Rainglow.CONFIG.getRarities())); } - public static void sendModeData(ServerPlayerEntity player) { - PacketByteBuf buf = PacketByteBufs.create(); + public record ConfigSyncPayload(String currentMode, List customMode, Map enabledMobs, Map rarities) implements CustomPayload { + public static final CustomPayload.Id PACKET_ID = new CustomPayload.Id<>(Rainglow.id("config_sync")); + public static final PacketCodec PACKET_CODEC = PacketCodec.create(ConfigSyncPayload::write, ConfigSyncPayload::read); - Collection modes = RainglowMode.values(); - buf.writeCollection(modes, RainglowNetworking::writeMode); + public void write(RegistryByteBuf buf) { + buf.writeString(this.currentMode); + buf.writeCollection(this.customMode, RainglowColour::write); + buf.writeMap(this.enabledMobs, RainglowEntity::write, PacketByteBuf::writeBoolean); + buf.writeMap(this.rarities, RainglowEntity::write, PacketByteBuf::writeVarInt); + } - ServerPlayNetworking.send(player, MODE_SYNC_ID, buf); - } + public static ConfigSyncPayload read(RegistryByteBuf buf) { + return new ConfigSyncPayload( + buf.readString(), + buf.readList(RainglowColour::read), + buf.readMap(RainglowEntity::read, PacketByteBuf::readBoolean), + buf.readMap(RainglowEntity::read, PacketByteBuf::readVarInt) + ); + } - public static Collection readModeData(PacketByteBuf buf) { - return buf.readList(RainglowNetworking::readMode); + @Override + public Id getId() { + return PACKET_ID; + } } - private static void writeMode(PacketByteBuf buf, RainglowMode mode) { - buf.writeString(mode.getId()); - buf.writeText(mode.getText()); - List colourIds = mode.getColours().stream().map(RainglowColour::getId).toList(); - buf.writeCollection(colourIds, PacketByteBuf::writeString); + public static void syncModes(ServerPlayerEntity player) { + ServerPlayNetworking.send(player, new ModeSyncPayload(RainglowMode.values())); } - private static RainglowMode readMode(PacketByteBuf buf) { - String id = buf.readString(); - Text text = buf.readText(); - List colourIds = buf.readList(PacketByteBuf::readString); + public record ModeSyncPayload(Collection modes) implements CustomPayload { + public static final CustomPayload.Id PACKET_ID = new CustomPayload.Id<>(Rainglow.id("mode_sync")); + public static final PacketCodec PACKET_CODEC = PacketCodec.create(ModeSyncPayload::write, ModeSyncPayload::read); + + public void write(RegistryByteBuf buf) { + buf.writeCollection(this.modes, RainglowMode::write); + } + + public static ModeSyncPayload read(RegistryByteBuf buf) { + return new ModeSyncPayload( + buf.readList(RainglowMode::read) + ); + } - return new RainglowMode(id, colourIds, text, RainglowMode.byId(id) != null); + @Override + public Id getId() { + return PACKET_ID; + } } } diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowResourceReloader.java b/src/main/java/io/ix0rai/rainglow/data/RainglowResourceReloader.java index 2d1befc..1fea62d 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowResourceReloader.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowResourceReloader.java @@ -1,13 +1,10 @@ package io.ix0rai.rainglow.data; import io.ix0rai.rainglow.Rainglow; -import net.fabricmc.api.EnvType; import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; -import net.fabricmc.loader.api.FabricLoader; import net.minecraft.resource.Resource; import net.minecraft.resource.ResourceManager; import net.minecraft.util.Identifier; -import net.minecraft.client.MinecraftClient; import java.io.IOException; import java.io.InputStream; @@ -27,6 +24,7 @@ default void reload(ResourceManager manager) { // this only clears modes that exist on both the server and the client // otherwise we would have to re-request the mode data packet on every reload RainglowMode.clearUniversalModes(); + Rainglow.RAINGLOW_DATAPACKS.clear(); // load custom modes from rainglow/custom_modes in the datapack // we only load files whose name ends with .json @@ -39,17 +37,16 @@ default void reload(ResourceManager manager) { Reader reader = new InputStreamReader(stream, StandardCharsets.UTF_8); RainglowMode.JsonMode result = Rainglow.GSON.fromJson(reader, RainglowMode.JsonMode.class); RainglowMode.addMode(new RainglowMode(result, true)); + + String name = entry.getValue().getSourceName(); + if (this.getFabricId().equals(Rainglow.SERVER_MODE_DATA_ID) && !Rainglow.RAINGLOW_DATAPACKS.contains(name)) { + Rainglow.RAINGLOW_DATAPACKS.add(name); + } } catch (IOException e) { throw new RuntimeException(e); } } this.log(); - - // load config - if (Rainglow.CONFIG.isUninitialised() || (FabricLoader.getInstance().getEnvironmentType().equals(EnvType.CLIENT) && !Rainglow.CONFIG.isEditLocked(MinecraftClient.getInstance()))) { - Rainglow.CONFIG.reloadFromFile(); - Rainglow.setMode(Rainglow.CONFIG.getMode()); - } } } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/AllayEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/AllayEntityMixin.java index 2c7ab16..0890197 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/AllayEntityMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/AllayEntityMixin.java @@ -6,6 +6,7 @@ import io.ix0rai.rainglow.data.RainglowEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; +import net.minecraft.entity.data.DataTracker.Builder; import net.minecraft.entity.passive.AllayEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.util.random.RandomGenerator; @@ -19,49 +20,46 @@ @Mixin(AllayEntity.class) public abstract class AllayEntityMixin extends Entity implements AllayVariantProvider { + @Unique + private static final RainglowEntity THIS = RainglowEntity.ALLAY; + protected AllayEntityMixin(EntityType entityType, World world) { super(entityType, world); throw new UnsupportedOperationException(); } @Inject(method = "initDataTracker", at = @At("TAIL")) - protected void initDataTracker(CallbackInfo ci) { - this.getDataTracker().startTracking(Rainglow.getTrackedColourData(RainglowEntity.ALLAY), RainglowColour.BLUE.getId()); + protected void initDataTracker(Builder builder, CallbackInfo ci) { + builder.add(THIS.getTrackedData(), THIS.getDefaultColour().getId()); } @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) public void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) { - String colour = Rainglow.getColour(RainglowEntity.ALLAY, this.getDataTracker(), this.getRandom()); - nbt.putString(Rainglow.CUSTOM_NBT_KEY, colour); + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.getRandom()); + nbt.putString(Rainglow.CUSTOM_NBT_KEY, colour.getId()); } @Inject(method = "readCustomDataFromNbt", at = @At("TAIL")) public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) { - String colour = nbt.getString(Rainglow.CUSTOM_NBT_KEY); - - if (Rainglow.colourUnloaded(colour)) { - colour = Rainglow.generateRandomColourId(this.getRandom()); - } - - this.setVariant(RainglowColour.get(colour)); + this.setVariant(THIS.readNbt(nbt, this.getRandom())); } // triggered when an allay duplicates, to apply the same colour as parent @Redirect(method = "duplicate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntity(Lnet/minecraft/entity/Entity;)Z")) public boolean spawnWithColour(World instance, Entity entity) { - RainglowColour colour = RainglowColour.get(Rainglow.getColour(RainglowEntity.ALLAY, this.getDataTracker(), this.getRandom())); - entity.getDataTracker().set(Rainglow.getTrackedColourData(RainglowEntity.ALLAY), colour.getId()); + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.getRandom()); + entity.getDataTracker().set(THIS.getTrackedData(), colour.getId()); return this.getWorld().spawnEntity(entity); } @Override public RainglowColour getVariant() { - return RainglowColour.get(Rainglow.getColour(RainglowEntity.ALLAY, this.getDataTracker(), this.getRandom())); + return Rainglow.getColour(THIS, this.getDataTracker(), this.getRandom()); } @Override public void setVariant(RainglowColour colour) { - this.getDataTracker().set(Rainglow.getTrackedColourData(RainglowEntity.ALLAY), colour.getId()); + this.getDataTracker().set(THIS.getTrackedData(), colour.getId()); } @Unique diff --git a/src/main/java/io/ix0rai/rainglow/mixin/DyeItemMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/DyeItemMixin.java index 664d6c3..95e8bc3 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/DyeItemMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/DyeItemMixin.java @@ -4,9 +4,6 @@ import io.ix0rai.rainglow.data.RainglowEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.data.DataTracker; -import net.minecraft.entity.mob.SlimeEntity; -import net.minecraft.entity.passive.AllayEntity; -import net.minecraft.entity.passive.GlowSquidEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.DyeItem; import net.minecraft.item.ItemStack; @@ -27,40 +24,21 @@ public class DyeItemMixin { @Inject(method = "useOnEntity", at = @At("TAIL"), cancellable = true) private void useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand, CallbackInfoReturnable cir) { String colour = getDye(stack); + RainglowEntity entityType = RainglowEntity.get(entity); - if (entity instanceof GlowSquidEntity glowSquid && glowSquid.isAlive() && !Rainglow.getColour(RainglowEntity.GLOW_SQUID, glowSquid.getDataTracker(), glowSquid.getRandom()).equals(colour)) { - glowSquid.getWorld().playSoundFromEntity(user, glowSquid, SoundEvents.BLOCK_AMETHYST_BLOCK_CHIME, SoundCategory.PLAYERS, 1.0f, 1.0f); + if (entityType != null && !Rainglow.colourUnloaded(entityType, colour) + && Rainglow.CONFIG.isEntityEnabled(entityType) + && !Rainglow.getColour(entityType, entity.getDataTracker(), entity.getWorld().getRandom()).getId().equals(colour)) { + entity.getWorld().playSoundFromEntity(user, entity, SoundEvents.BLOCK_AMETHYST_CLUSTER_BREAK, SoundCategory.PLAYERS, 5.0f, 1.0f); if (!user.getWorld().isClient()) { stack.decrement(1); } - DataTracker tracker = glowSquid.getDataTracker(); - tracker.set(Rainglow.getTrackedColourData(RainglowEntity.GLOW_SQUID), colour); - - cir.setReturnValue(ActionResult.success(user.getWorld().isClient())); - } else if (entity instanceof AllayEntity allayEntity && allayEntity.isAlive() && !Rainglow.getColour(RainglowEntity.ALLAY, allayEntity.getDataTracker(), allayEntity.getRandom()).equals(colour)) { - allayEntity.getWorld().playSoundFromEntity(user, allayEntity, SoundEvents.BLOCK_AMETHYST_BLOCK_CHIME, SoundCategory.PLAYERS, 1.0f, 1.0f); - if (!user.getWorld().isClient()) { - stack.decrement(1); - } - - DataTracker tracker = allayEntity.getDataTracker(); - tracker.set(Rainglow.getTrackedColourData(RainglowEntity.ALLAY), colour); - - cir.setReturnValue(ActionResult.success(user.getWorld().isClient())); - } else if (entity instanceof SlimeEntity slimeEntity && slimeEntity.isAlive() && !Rainglow.getColour(RainglowEntity.SLIME, slimeEntity.getDataTracker(), slimeEntity.getRandom()).equals(colour)) { - slimeEntity.getWorld().playSoundFromEntity(user, slimeEntity, SoundEvents.BLOCK_AMETHYST_BLOCK_CHIME, SoundCategory.PLAYERS, 1.0f, 1.0f); - if (!user.getWorld().isClient()) { - stack.decrement(1); - } - - DataTracker tracker = slimeEntity.getDataTracker(); - tracker.set(Rainglow.getTrackedColourData(RainglowEntity.SLIME), colour); + DataTracker tracker = entity.getDataTracker(); + tracker.set(entityType.getTrackedData(), colour); cir.setReturnValue(ActionResult.success(user.getWorld().isClient())); } - - cir.setReturnValue(ActionResult.PASS); } @Unique diff --git a/src/main/java/io/ix0rai/rainglow/mixin/GlowSquidEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/GlowSquidEntityMixin.java index ae90176..98a82a0 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/GlowSquidEntityMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/GlowSquidEntityMixin.java @@ -8,12 +8,14 @@ import net.minecraft.entity.mob.WaterCreatureEntity; import net.minecraft.entity.passive.GlowSquidEntity; import net.minecraft.entity.passive.SquidEntity; +import net.minecraft.entity.data.DataTracker.Builder; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleTypes; import net.minecraft.server.world.ServerWorld; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -21,32 +23,28 @@ @Mixin(GlowSquidEntity.class) public abstract class GlowSquidEntityMixin extends SquidEntity implements GlowSquidVariantProvider { + @Unique + private static final RainglowEntity THIS = RainglowEntity.GLOW_SQUID; + protected GlowSquidEntityMixin(EntityType entityType, World world) { super(entityType, world); throw new UnsupportedOperationException(); } @Inject(method = "initDataTracker", at = @At("TAIL")) - protected void initDataTracker(CallbackInfo ci) { - this.getDataTracker().startTracking(Rainglow.getTrackedColourData(RainglowEntity.GLOW_SQUID), RainglowColour.BLUE.getId()); + protected void initDataTracker(Builder builder, CallbackInfo ci) { + builder.add(THIS.getTrackedData(), THIS.getDefaultColour().getId()); } @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) public void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) { - String colour = Rainglow.getColour(RainglowEntity.GLOW_SQUID, this.getDataTracker(), this.getRandom()); - nbt.putString(Rainglow.CUSTOM_NBT_KEY, colour); + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.getRandom()); + nbt.putString(Rainglow.CUSTOM_NBT_KEY, colour.getId()); } @Inject(method = "readCustomDataFromNbt", at = @At("TAIL")) public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) { - String colour = nbt.getString(Rainglow.CUSTOM_NBT_KEY); - - // if read colour does not exist in the colour map, generate the squid a new one - if (Rainglow.colourUnloaded(colour)) { - colour = Rainglow.generateRandomColourId(this.getRandom()); - } - - this.setVariant(RainglowColour.get(colour)); + this.setVariant(THIS.readNbt(nbt, this.getRandom())); } /** @@ -55,22 +53,23 @@ public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) { */ @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;addParticle(Lnet/minecraft/particle/ParticleEffect;DDDDDD)V"), cancellable = true) public void tickMovement(CallbackInfo ci) { - String colour = Rainglow.getColour(RainglowEntity.GLOW_SQUID, this.getDataTracker(), this.getRandom()); - if (!colour.equals(RainglowColour.BLUE.getId())) { + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.getRandom()); + + if (colour != RainglowColour.BLUE) { // we add 100 to g to let the mixin know that we want to override the method - this.getWorld().addParticle(ParticleTypes.GLOW, this.getParticleX(0.6), this.getRandomBodyY(), this.getParticleZ(0.6), Rainglow.getColourIndex(colour) + 100, 0, 0); + this.getWorld().addParticle(ParticleTypes.GLOW, this.getParticleX(0.6), this.getRandomBodyY(), this.getParticleZ(0.6), colour.ordinal() + 100, 0, 0); ci.cancel(); } } @Override public RainglowColour getVariant() { - return RainglowColour.get(Rainglow.getColour(RainglowEntity.GLOW_SQUID, this.getDataTracker(), this.getRandom())); + return Rainglow.getColour(THIS, this.getDataTracker(), this.getRandom()); } @Override public void setVariant(RainglowColour colour) { - this.getDataTracker().set(Rainglow.getTrackedColourData(RainglowEntity.GLOW_SQUID), colour.getId()); + this.getDataTracker().set(THIS.getTrackedData(), colour.getId()); } @Mixin(SquidEntity.class) @@ -90,8 +89,8 @@ protected SquidEntityMixin(EntityType entityType, private int spawnParticles(ServerWorld instance, ParticleEffect particle, double x, double y, double z, int count, double deltaX, double deltaY, double deltaZ, double speed) { if (((Object) this) instanceof GlowSquidEntity) { // send in custom colour data - String colour = Rainglow.getColour(RainglowEntity.GLOW_SQUID, this.getDataTracker(), this.getRandom()); - int index = Rainglow.getColourIndex(colour); + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.getRandom()); + int index = colour.ordinal(); // round x to 1 decimal place and append index data to the next two return ((ServerWorld) this.getWorld()).spawnParticles(particle, (Math.round(x * 10)) / 10D + index / 1000D, y + 0.5, z, 0, deltaX, deltaY, deltaZ, speed); } else { diff --git a/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java index 678c5f4..495bf2d 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java @@ -1,26 +1,18 @@ package io.ix0rai.rainglow.mixin; import io.ix0rai.rainglow.Rainglow; -import io.ix0rai.rainglow.data.AllayEntityData; -import io.ix0rai.rainglow.data.AllayVariantProvider; import io.ix0rai.rainglow.data.RainglowColour; -import io.ix0rai.rainglow.data.GlowSquidEntityData; -import io.ix0rai.rainglow.data.GlowSquidVariantProvider; -import io.ix0rai.rainglow.data.SlimeEntityData; -import io.ix0rai.rainglow.data.SlimeVariantProvider; +import io.ix0rai.rainglow.data.RainglowEntity; import net.minecraft.entity.EntityData; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.SpawnReason; +import net.minecraft.entity.VariantProvider; import net.minecraft.entity.mob.MobEntity; -import net.minecraft.entity.mob.SlimeEntity; -import net.minecraft.entity.passive.AllayEntity; -import net.minecraft.entity.passive.GlowSquidEntity; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.util.random.RandomGenerator; import net.minecraft.world.LocalDifficulty; import net.minecraft.world.ServerWorldAccess; import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -35,24 +27,20 @@ protected MobEntityMixin(EntityType entityType, World world @SuppressWarnings("all") @Inject(method = "initialize", at = @At("RETURN"), cancellable = true) - public void initialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, EntityData entityData, NbtCompound entityNbt, CallbackInfoReturnable cir) { - if ((Object) this instanceof GlowSquidEntity glowSquid) { - String colour = Rainglow.generateRandomColourId(this.getRandom()); - ((GlowSquidVariantProvider) glowSquid).setVariant(getColourOrDefault(this.random, RainglowColour.BLUE, colour)); - cir.setReturnValue(new GlowSquidEntityData(getColourOrDefault(this.random, RainglowColour.BLUE, colour))); - } else if ((Object) this instanceof AllayEntity allay) { - String colour = Rainglow.generateRandomColourId(this.getRandom()); - ((AllayVariantProvider) allay).setVariant(getColourOrDefault(this.random, RainglowColour.BLUE, colour)); - cir.setReturnValue(new AllayEntityData(getColourOrDefault(this.random, RainglowColour.BLUE, colour))); - } else if ((Object) this instanceof SlimeEntity slime) { - String colour = Rainglow.generateRandomColourId(this.getRandom()); - ((SlimeVariantProvider) slime).setVariant(getColourOrDefault(this.random, RainglowColour.LIME, colour)); - cir.setReturnValue(new SlimeEntityData(getColourOrDefault(this.random, RainglowColour.LIME, colour))); + public void initialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, CallbackInfoReturnable cir) { + RainglowEntity entity = RainglowEntity.get(this); + if (entity != null) { + RainglowColour colour = generateColour(entity); + ((VariantProvider) this).setVariant(colour); + cir.setReturnValue(entity.createEntityData(colour)); } } @Unique - private static RainglowColour getColourOrDefault(RandomGenerator random, RainglowColour defaultColour, String randomColour) { - return random.nextInt(100) >= Rainglow.CONFIG.getRarity() ? defaultColour : RainglowColour.get(randomColour); + private RainglowColour generateColour(RainglowEntity entity) { + int i = random.nextInt(100); + int rarity = Rainglow.CONFIG.getRarity(entity); + + return i >= rarity ? entity.getDefaultColour() : RainglowColour.get(Rainglow.generateRandomColourId(this.random)); } } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/SlimeEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/SlimeEntityMixin.java index 695e561..97f2415 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/SlimeEntityMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/SlimeEntityMixin.java @@ -6,6 +6,7 @@ import io.ix0rai.rainglow.data.SlimeVariantProvider; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; +import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.mob.SlimeEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.particle.ParticleEffect; @@ -13,6 +14,7 @@ import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -21,11 +23,11 @@ @Mixin(SlimeEntity.class) public abstract class SlimeEntityMixin extends Entity implements SlimeVariantProvider { - @Shadow - protected abstract ParticleEffect getParticles(); + @Unique + private static final RainglowEntity THIS = RainglowEntity.SLIME; @Shadow - public abstract int getSize(); + protected abstract ParticleEffect getParticles(); protected SlimeEntityMixin(EntityType entityType, World world) { super(entityType, world); @@ -33,25 +35,19 @@ protected SlimeEntityMixin(EntityType entityType, World w } @Inject(method = "initDataTracker", at = @At("TAIL")) - protected void initDataTracker(CallbackInfo ci) { - this.getDataTracker().startTracking(Rainglow.getTrackedColourData(RainglowEntity.SLIME), RainglowColour.LIME.getId()); + protected void initDataTracker(DataTracker.Builder builder, CallbackInfo ci) { + builder.add(THIS.getTrackedData(), THIS.getDefaultColour().getId()); } @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) public void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) { - String colour = Rainglow.getColour(RainglowEntity.SLIME, this.getDataTracker(), this.random); - nbt.putString(Rainglow.CUSTOM_NBT_KEY, colour); + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.random); + nbt.putString(Rainglow.CUSTOM_NBT_KEY, colour.getId()); } @Inject(method = "readCustomDataFromNbt", at = @At("TAIL")) public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) { - String colour = nbt.getString(Rainglow.CUSTOM_NBT_KEY); - - if (Rainglow.colourUnloaded(colour)) { - colour = Rainglow.generateRandomColourId(this.random); - } - - this.setVariant(RainglowColour.get(colour)); + this.setVariant(THIS.readNbt(nbt, this.random)); } /** @@ -59,8 +55,8 @@ public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) { */ @Redirect(method = "remove", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;spawnEntity(Lnet/minecraft/entity/Entity;)Z")) public boolean spawnWithParentColour(World instance, Entity entity) { - RainglowColour colour = RainglowColour.get(Rainglow.getColour(RainglowEntity.SLIME, this.getDataTracker(), this.random)); - entity.getDataTracker().set(Rainglow.getTrackedColourData(RainglowEntity.SLIME), colour.getId()); + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.random); + entity.getDataTracker().set(THIS.getTrackedData(), colour.getId()); return this.getWorld().spawnEntity(entity); } @@ -70,31 +66,32 @@ public boolean spawnWithParentColour(World instance, Entity entity) { */ @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;addParticle(Lnet/minecraft/particle/ParticleEffect;DDDDDD)V"), slice = @Slice( - from = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/SlimeEntity;getSize()I"), + from = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/SlimeEntity;getDimensions(Lnet/minecraft/entity/EntityPose;)Lnet/minecraft/entity/EntityDimensions;"), to = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/SlimeEntity;playSound(Lnet/minecraft/sound/SoundEvent;FF)V") ) ) public void tick(CallbackInfo ci) { - int size = this.getSize(); - String colour = RainglowColour.get(Rainglow.getColour(RainglowEntity.SLIME, this.getDataTracker(), this.random)).getId(); - int index = Rainglow.getColourIndex(colour); + float size = this.getDimensions(this.getPose()).width(); + RainglowColour colour = Rainglow.getColour(THIS, this.getDataTracker(), this.random); + int index = colour.ordinal(); - for(int j = 0; j < size * 2; j ++) { + for (int j = 0; j < size / 2; j ++) { float f = this.random.nextFloat() * 6.2831855F; float g = this.random.nextFloat() * 0.5F + 0.5F; - float h = MathHelper.sin(f) * (float)size * 0.5F * g; - float k = MathHelper.cos(f) * (float)size * 0.5F * g; - this.getWorld().addParticle(this.getParticles(), this.getX() + (double)h, this.getY(), this.getZ() + (double)k, index, 100.0, 0.0); + float h = MathHelper.sin(f) * size * g; + float k = MathHelper.cos(f) * size * g; + // note: y velocity of 100 is a magic value + this.getWorld().addParticle(this.getParticles(), this.getX() + (double) h, this.getY(), this.getZ() + (double) k, index, 100.0, 0.0); } } @Override public RainglowColour getVariant() { - return RainglowColour.get(Rainglow.getColour(RainglowEntity.SLIME, this.getDataTracker(), this.random)); + return Rainglow.getColour(THIS, this.getDataTracker(), this.random); } @Override public void setVariant(RainglowColour colour) { - this.getDataTracker().set(Rainglow.getTrackedColourData(RainglowEntity.SLIME), colour.getId()); + this.getDataTracker().set(THIS.getTrackedData(), colour.getId()); } } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/AllayEntityRendererMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/AllayEntityRendererMixin.java index b1ae55c..7df11b2 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/client/AllayEntityRendererMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/AllayEntityRendererMixin.java @@ -1,9 +1,7 @@ package io.ix0rai.rainglow.mixin.client; -import io.ix0rai.rainglow.Rainglow; -import io.ix0rai.rainglow.data.RainglowColour; import io.ix0rai.rainglow.data.RainglowEntity; -import net.minecraft.client.render.entity.AllayRenderer; +import net.minecraft.client.render.entity.AllayEntityRenderer; import net.minecraft.entity.passive.AllayEntity; import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; @@ -11,18 +9,10 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(AllayRenderer.class) +@Mixin(AllayEntityRenderer.class) public class AllayEntityRendererMixin { - @Inject(method = "getTexture*", at = @At("HEAD"), cancellable = true) public void getTexture(AllayEntity allayEntity, CallbackInfoReturnable cir) { - String colour = Rainglow.getColour(RainglowEntity.ALLAY, allayEntity.getDataTracker(), allayEntity.getRandom()); - - // if the colour is blue we don't need to override the method - // this optimises a tiny bit - if (Rainglow.CONFIG.isEntityEnabled(RainglowEntity.ALLAY) && !colour.equals(RainglowColour.BLUE.getId())) { - Identifier texture = Rainglow.getTexture(RainglowEntity.ALLAY, colour); - cir.setReturnValue(texture != null ? texture : Rainglow.getDefaultTexture(RainglowEntity.ALLAY)); - } + RainglowEntity.ALLAY.overrideTexture(allayEntity, cir); } } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/GlowParticleMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/GlowParticleMixin.java index df4dea5..60e163e 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/client/GlowParticleMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/GlowParticleMixin.java @@ -32,7 +32,7 @@ public void createParticle(DefaultParticleType defaultParticleType, ClientWorld GlowParticle glowParticle = new GlowParticle(clientWorld, d, e, f, 0.5 - GlowParticle.RANDOM.nextDouble(), h, 0.5 - GlowParticle.RANDOM.nextDouble(), this.spriteProvider); // we check the g value to see what the colour is - RainglowColour.RGB rgb = Rainglow.getPassiveParticleRGB((int) g, GlowParticle.RANDOM); + RainglowColour.RGB rgb = RainglowColour.getPassiveParticleRGB((int) g, GlowParticle.RANDOM); glowParticle.setColor(rgb.r(), rgb.g(), rgb.b()); // set velocities - I don't entirely understand why this is necessary, it's copied from vanilla code diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/GlowSquidEntityRendererMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/GlowSquidEntityRendererMixin.java index 53627a5..183d38a 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/client/GlowSquidEntityRendererMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/GlowSquidEntityRendererMixin.java @@ -1,7 +1,5 @@ package io.ix0rai.rainglow.mixin.client; -import io.ix0rai.rainglow.Rainglow; -import io.ix0rai.rainglow.data.RainglowColour; import io.ix0rai.rainglow.data.RainglowEntity; import net.minecraft.client.render.entity.GlowSquidEntityRenderer; import net.minecraft.entity.passive.GlowSquidEntity; @@ -19,13 +17,6 @@ public class GlowSquidEntityRendererMixin { */ @Inject(method = "getTexture*", at = @At("HEAD"), cancellable = true) public void getTexture(GlowSquidEntity glowSquidEntity, CallbackInfoReturnable cir) { - String colour = Rainglow.getColour(RainglowEntity.GLOW_SQUID, glowSquidEntity.getDataTracker(), glowSquidEntity.getRandom()); - - // if the colour is blue we don't need to override the method - // this optimises a tiny bit - if (Rainglow.CONFIG.isEntityEnabled(RainglowEntity.GLOW_SQUID) && !colour.equals(RainglowColour.BLUE.getId())) { - Identifier texture = Rainglow.getTexture(RainglowEntity.GLOW_SQUID, colour); - cir.setReturnValue(texture != null ? texture : Rainglow.getDefaultTexture(RainglowEntity.GLOW_SQUID)); - } + RainglowEntity.GLOW_SQUID.overrideTexture(glowSquidEntity, cir); } } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeEntityRendererMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeEntityRendererMixin.java index a40d18f..fe16520 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeEntityRendererMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeEntityRendererMixin.java @@ -1,9 +1,6 @@ package io.ix0rai.rainglow.mixin.client; -import io.ix0rai.rainglow.Rainglow; -import io.ix0rai.rainglow.data.RainglowColour; import io.ix0rai.rainglow.data.RainglowEntity; -import io.ix0rai.rainglow.data.RainglowMode; import net.minecraft.client.render.entity.SlimeEntityRenderer; import net.minecraft.entity.mob.SlimeEntity; import net.minecraft.util.Identifier; @@ -16,12 +13,6 @@ public class SlimeEntityRendererMixin { @Inject(method = "getTexture*", at = @At("HEAD"), cancellable = true) public void getTexture(SlimeEntity entity, CallbackInfoReturnable cir) { - String colour = Rainglow.getColour(RainglowEntity.SLIME, entity.getDataTracker(), entity.getRandom()); - - // don't override if the colour is lime, use the default texture - if (Rainglow.CONFIG.isEntityEnabled(RainglowEntity.SLIME) && !colour.equals(RainglowColour.LIME.getId()) || Rainglow.CONFIG.getMode().equals(RainglowMode.byId("vanilla"))) { - Identifier texture = Rainglow.getTexture(RainglowEntity.SLIME, colour); - cir.setReturnValue(texture != null ? texture : Rainglow.getDefaultTexture(RainglowEntity.SLIME)); - } + RainglowEntity.SLIME.overrideTexture(entity, cir); } } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeParticleMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeParticleMixin.java index 6b6f56c..83327e6 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeParticleMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/SlimeParticleMixin.java @@ -25,7 +25,7 @@ public void createParticle(DefaultParticleType defaultParticleType, ClientWorld cir.setReturnValue(new ItemBreakParticle(clientWorld, d, e, f, new ItemStack(Items.SLIME_BALL))); // 99.9d and 100.1d are used to account for floating point errors } else if (h >= 99.9d && h <= 100.1d) { - ItemStack stack = Rainglow.getItem((int) g).getDefaultStack(); + ItemStack stack = RainglowEntity.SLIME.getItem((int) g).getDefaultStack(); cir.setReturnValue(new ItemBreakParticle(clientWorld, d, e, f, stack)); } else { cir.setReturnValue(null); diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/SquidInkParticleMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/SquidInkParticleMixin.java index 11f77e6..a6ae80b 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/client/SquidInkParticleMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/SquidInkParticleMixin.java @@ -45,12 +45,12 @@ public void createParticle(DefaultParticleType defaultParticleType, ClientWorld // when we catch an exception we use white as it looks the most normal RainglowColour.RGB rgb; try { - rgb = Rainglow.getInkRgb(colourIndex); + rgb = RainglowColour.getInkRgb(colourIndex); } catch (IndexOutOfBoundsException ignored) { rgb = RainglowColour.WHITE.getInkRgb(); } - cir.setReturnValue(new SquidInkParticle(clientWorld, d, e, f, g, h, i, ColorUtil.ARGB32.getArgb(255, (int) rgb.r(), (int) rgb.g(), (int) rgb.b()), this.spriteProvider)); + cir.setReturnValue(new SquidInkParticle(clientWorld, d, e, f, g, h, i, ColorUtil.Argb32.of(255, (int) rgb.r(), (int) rgb.g(), (int) rgb.b()), this.spriteProvider)); } } } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/screen/CyclingValueSetMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/screen/CyclingValueSetMixin.java new file mode 100644 index 0000000..5acb14f --- /dev/null +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/screen/CyclingValueSetMixin.java @@ -0,0 +1,23 @@ +package io.ix0rai.rainglow.mixin.client.screen; + +import com.llamalad7.mixinextras.sugar.Local; +import io.ix0rai.rainglow.config.DeferredSaveOption; +import net.minecraft.client.option.Option; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(Option.CyclingValueSet.class) +public interface CyclingValueSetMixin { + @ModifyArg( + method = "method_42723", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/gui/widget/button/CyclingButtonWidget$Builder;initially(Ljava/lang/Object;)Lnet/minecraft/client/gui/widget/button/CyclingButtonWidget$Builder;" + ), + index = 0 + ) + private T updateOptionValue(T value, @Local(argsOnly = true) Option option) { + return option instanceof DeferredSaveOption deferred ? deferred.deferredValue : value; + } +} diff --git a/src/main/java/io/ix0rai/rainglow/mixin/client/screen/SliderValueImplMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/client/screen/SliderValueImplMixin.java new file mode 100644 index 0000000..dc24cdd --- /dev/null +++ b/src/main/java/io/ix0rai/rainglow/mixin/client/screen/SliderValueImplMixin.java @@ -0,0 +1,23 @@ +package io.ix0rai.rainglow.mixin.client.screen; + +import com.llamalad7.mixinextras.sugar.Local; +import io.ix0rai.rainglow.config.DeferredSaveOption; +import net.minecraft.client.option.Option; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(Option.OptionSliderWidgetImpl.class) +public class SliderValueImplMixin { + @ModifyArg( + method = "", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/option/Option$SliderValueSet;toSliderValue(Ljava/lang/Object;)D" + ), + index = 0 + ) + private static T updateOptionValue(T value, @Local(argsOnly = true) Option option) { + return option instanceof DeferredSaveOption deferred ? deferred.deferredValue : value; + } +} diff --git a/src/main/resources/assets/minecraft/models/item/amethyst_shard.json b/src/main/resources/assets/minecraft/models/item/amethyst_shard.json new file mode 100644 index 0000000..ac79550 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/amethyst_shard.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/amethyst_shard", + "particle": "minecraft:block/slime_block/indigo" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/black_dye.json b/src/main/resources/assets/minecraft/models/item/black_dye.json new file mode 100644 index 0000000..a98d66a --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/black_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/black_dye", + "particle": "minecraft:block/slime_block/black" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/blue_dye.json b/src/main/resources/assets/minecraft/models/item/blue_dye.json new file mode 100644 index 0000000..bd67d1f --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/blue_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/blue_dye", + "particle": "minecraft:block/slime_block/blue" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/brown_dye.json b/src/main/resources/assets/minecraft/models/item/brown_dye.json new file mode 100644 index 0000000..4437d6b --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/brown_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/brown_dye", + "particle": "minecraft:block/slime_block/brown" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/cyan_dye.json b/src/main/resources/assets/minecraft/models/item/cyan_dye.json new file mode 100644 index 0000000..2e7c220 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/cyan_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/cyan_dye", + "particle": "minecraft:block/slime_block/cyan" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/gray_dye.json b/src/main/resources/assets/minecraft/models/item/gray_dye.json new file mode 100644 index 0000000..0447947 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/gray_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/gray_dye", + "particle": "minecraft:block/slime_block/gray" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/green_dye.json b/src/main/resources/assets/minecraft/models/item/green_dye.json new file mode 100644 index 0000000..5e0915e --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/green_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/green_dye", + "particle": "minecraft:block/slime_block/green" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/light_blue_dye.json b/src/main/resources/assets/minecraft/models/item/light_blue_dye.json new file mode 100644 index 0000000..76cf813 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/light_blue_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/light_blue_dye", + "particle": "minecraft:block/slime_block/light_blue" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/light_gray_dye.json b/src/main/resources/assets/minecraft/models/item/light_gray_dye.json new file mode 100644 index 0000000..f3ea813 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/light_gray_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/light_gray_dye", + "particle": "minecraft:block/slime_block/light_gray" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/lime_dye.json b/src/main/resources/assets/minecraft/models/item/lime_dye.json new file mode 100644 index 0000000..f94c7ef --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/lime_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/lime_dye", + "particle": "minecraft:block/slime_block" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/magenta_dye.json b/src/main/resources/assets/minecraft/models/item/magenta_dye.json new file mode 100644 index 0000000..021065d --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/magenta_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/magenta_dye", + "particle": "minecraft:block/slime_block/magenta" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/orange_dye.json b/src/main/resources/assets/minecraft/models/item/orange_dye.json new file mode 100644 index 0000000..2fa13e4 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/orange_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/orange_dye", + "particle": "minecraft:block/slime_block/orange" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/pink_dye.json b/src/main/resources/assets/minecraft/models/item/pink_dye.json new file mode 100644 index 0000000..4bf3791 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/pink_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/pink_dye", + "particle": "minecraft:block/slime_block/pink" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/purple_dye.json b/src/main/resources/assets/minecraft/models/item/purple_dye.json new file mode 100644 index 0000000..9c1f87d --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/purple_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/purple_dye", + "particle": "minecraft:block/slime_block/purple" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/red_dye.json b/src/main/resources/assets/minecraft/models/item/red_dye.json new file mode 100644 index 0000000..f976836 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/red_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/red_dye", + "particle": "minecraft:block/slime_block/red" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/white_dye.json b/src/main/resources/assets/minecraft/models/item/white_dye.json new file mode 100644 index 0000000..cbd98a7 --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/white_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/white_dye", + "particle": "minecraft:block/slime_block/white" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/models/item/yellow_dye.json b/src/main/resources/assets/minecraft/models/item/yellow_dye.json new file mode 100644 index 0000000..f64fb1b --- /dev/null +++ b/src/main/resources/assets/minecraft/models/item/yellow_dye.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "minecraft:item/yellow_dye", + "particle": "minecraft:block/slime_block/yellow" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/black.png b/src/main/resources/assets/minecraft/textures/block/slime_block/black.png new file mode 100644 index 0000000..19544b2 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/black.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/blue.png b/src/main/resources/assets/minecraft/textures/block/slime_block/blue.png new file mode 100644 index 0000000..49266fc Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/blue.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/brown.png b/src/main/resources/assets/minecraft/textures/block/slime_block/brown.png new file mode 100644 index 0000000..0c21e20 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/brown.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/cyan.png b/src/main/resources/assets/minecraft/textures/block/slime_block/cyan.png new file mode 100644 index 0000000..e3b5864 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/cyan.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/gray.png b/src/main/resources/assets/minecraft/textures/block/slime_block/gray.png new file mode 100644 index 0000000..623f2b0 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/gray.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/green.png b/src/main/resources/assets/minecraft/textures/block/slime_block/green.png new file mode 100644 index 0000000..70c758a Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/green.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/indigo.png b/src/main/resources/assets/minecraft/textures/block/slime_block/indigo.png new file mode 100644 index 0000000..fdd982b Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/indigo.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/light_blue.png b/src/main/resources/assets/minecraft/textures/block/slime_block/light_blue.png new file mode 100644 index 0000000..1d566d3 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/light_blue.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/light_gray.png b/src/main/resources/assets/minecraft/textures/block/slime_block/light_gray.png new file mode 100644 index 0000000..4d38929 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/light_gray.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/magenta.png b/src/main/resources/assets/minecraft/textures/block/slime_block/magenta.png new file mode 100644 index 0000000..6b24506 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/magenta.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/orange.png b/src/main/resources/assets/minecraft/textures/block/slime_block/orange.png new file mode 100644 index 0000000..143103d Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/orange.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/pink.png b/src/main/resources/assets/minecraft/textures/block/slime_block/pink.png new file mode 100644 index 0000000..1b1a2a8 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/pink.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/purple.png b/src/main/resources/assets/minecraft/textures/block/slime_block/purple.png new file mode 100644 index 0000000..9e07bbd Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/purple.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/red.png b/src/main/resources/assets/minecraft/textures/block/slime_block/red.png new file mode 100644 index 0000000..b1de0c9 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/red.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/white.png b/src/main/resources/assets/minecraft/textures/block/slime_block/white.png new file mode 100644 index 0000000..ad739c5 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/white.png differ diff --git a/src/main/resources/assets/minecraft/textures/block/slime_block/yellow.png b/src/main/resources/assets/minecraft/textures/block/slime_block/yellow.png new file mode 100644 index 0000000..48465e5 Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/slime_block/yellow.png differ diff --git a/src/main/resources/assets/rainglow/custom_modes/vanilla.json b/src/main/resources/assets/rainglow/custom_modes/vanilla.json deleted file mode 100644 index bbafc01..0000000 --- a/src/main/resources/assets/rainglow/custom_modes/vanilla.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": "vanilla", - "textColour": "FFFFFF", - "colourIds": [ - "blue" - ] -} diff --git a/src/main/resources/assets/rainglow/lang/de_de.json b/src/main/resources/assets/rainglow/lang/de_de.json index 8f59465..2cf0cc1 100644 --- a/src/main/resources/assets/rainglow/lang/de_de.json +++ b/src/main/resources/assets/rainglow/lang/de_de.json @@ -11,13 +11,9 @@ "rainglow.config.enable_slime": "Regenbogenfarbener Schleim", "rainglow.config.enable_allay": "Regenbogenfarbene Hilfsgeister", "rainglow.config.server_locked_title": "Konfiguration vom Server gesperrt", - "rainglow.config.server_locked_description": "Du kannst dies nicht ändern, solange der Server diese Konfiguration gesperrt hat!", - "rainglow.tooltip.mode": "Der Modus bestimmt, welche Farben gerade aktiviert sind", - "rainglow.config.cannot_be_loaded_outside_world": "Die Rainglow Konfiguration kann nicht außerhalb einer Welt geladen werden!", "rainglow.mode.rainbow": "Regenbogen", "rainglow.mode.all_colours": "Alle Farben", "rainglow.mode.monochrome": "Monochrom", - "rainglow.mode.vanilla": "Standard", "rainglow.mode.custom": "Benutzerdefiniert", "rainglow.mode.trans_pride": "Transgender Pride!", "rainglow.mode.lesbian_pride": "Lesbian Pride!", @@ -44,5 +40,6 @@ "rainglow.colour.light_gray": "Hellgrau", "rainglow.colour.lime": "Hellgrün", "rainglow.colour.magenta": "Magenta", - "rainglow.colour.indigo": "Indigo" + "rainglow.colour.indigo": "Indigo", + "rainglow.tooltip.rarity": "Rarity determines what percent chance mobs have to spawn with a colour." } diff --git a/src/main/resources/assets/rainglow/lang/en_us.json b/src/main/resources/assets/rainglow/lang/en_us.json index d209973..9904bc3 100644 --- a/src/main/resources/assets/rainglow/lang/en_us.json +++ b/src/main/resources/assets/rainglow/lang/en_us.json @@ -10,16 +10,22 @@ "rainglow.config.enable_glow_squid": "Rainbow squids", "rainglow.config.enable_slime": "Rainbow slimes", "rainglow.config.enable_allay": "Rainbow allays", - "rainglow.config.server_locked_title": "Config is locked by server", - "rainglow.config.server_locked_description": "You can't change the mode while the config is locked!", - "rainglow.config.rarity": "Colour Rarity", - "rainglow.tooltip.rarity": "Rarity determines what percent chance mobs have to spawn with a colour", - "rainglow.tooltip.mode": "Rainglow Mode dictates which colours are currently available for squids", - "rainglow.config.cannot_be_loaded_outside_world": "Rainglow config cannot be edited through the GUI before loading a world!", + "rainglow.config.server_locked": "Config is server-locked: these values are your local config.", + "rainglow.config.no_custom_colours": "Cannot save with no colours selected!", + "rainglow.config.no_custom_colours_description": "Please select at least one colour to save the settings.", + "rainglow.config.no_world": "No world loaded: only default modes are available.", + "rainglow.config.unsaved_warning": "Config is not saved and changes will be lost! Leave without saving?", + "rainglow.config.continue_editing": "Continue editing", + "rainglow.config.loaded_datapacks": "Loaded %s modes from %s datapacks.", + "rainglow.config.loaded_builtin": "Loaded %s built-in modes.", + "rainglow.config.slime_rarity.value": "Slime rarity: %s", + "rainglow.tooltip.rarity": "Rarity determines what percent chance mobs have to spawn with a colour.", + "rainglow.tooltip.entity_toggle": "Enable or disable rainbow colours for this entity.", + "rainglow.config.allay_rarity.value": "Allay rarity: %s", + "rainglow.config.glow_squid_rarity.value": "Glow squid rarity: %s", "rainglow.mode.rainbow": "Rainbow", "rainglow.mode.all_colours": "All Colours", "rainglow.mode.monochrome": "Monochrome", - "rainglow.mode.vanilla": "Vanilla", "rainglow.mode.custom": "Custom", "rainglow.mode.trans_pride": "Transgender Pride!", "rainglow.mode.lesbian_pride": "Lesbian Pride!", diff --git a/src/main/resources/assets/rainglow/lang/fr_fr.json b/src/main/resources/assets/rainglow/lang/fr_fr.json index 6394fc3..82d6615 100644 --- a/src/main/resources/assets/rainglow/lang/fr_fr.json +++ b/src/main/resources/assets/rainglow/lang/fr_fr.json @@ -11,13 +11,9 @@ "rainglow.config.enable_slime": "Slimes arc-en-ciel", "rainglow.config.enable_allay": "Allays arc-en-ciel", "rainglow.config.server_locked_title": "La configuration est verrouillée par le serveur", - "rainglow.config.server_locked_description": "Vous ne pouvez pas changer le mode tant que la configuration est verrouillée !", - "rainglow.tooltip.mode": "Le mode Rainglow dicte quelles couleurs sont actuellement disponibles pour les poulpes", - "rainglow.config.cannot_be_loaded_outside_world": "La configuration de Rainglow ne peut pas être modifiée par l'interface utilisateur tant qu'un monde n'est pas chargé !", "rainglow.mode.rainbow": "Arc-en-ciel", "rainglow.mode.all_colours": "Toutes les Couleurs", "rainglow.mode.monochrome": "Monochrome", - "rainglow.mode.vanilla": "Vanille", "rainglow.mode.custom": "Personnalisé", "rainglow.mode.trans_pride": "Fierté Transgenre !", "rainglow.mode.lesbian_pride": "Fierté Lesbienne !", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index a33a321..e183bb0 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -11,8 +11,9 @@ ], "contact": { - "website": "https://modrinth.com/mod/rainglow", - "repo": "https://github.com/ix0rai/rainglow" + "homepage": "https://modrinth.com/mod/rainglow", + "sources": "https://github.com/ix0rai/rainglow", + "issues": "https://github.com/ix0rai/rainglow/issues" }, "license": "MIT", @@ -39,7 +40,7 @@ "fabricloader": ">=0.14.19", "fabric-resource-loader-v0": "*", "fabric-networking-api-v1": "*", - "minecraft": ">=1.20.2" + "minecraft": ">=1.20.6" }, "suggests": { diff --git a/src/main/resources/rainglow.accesswidener b/src/main/resources/rainglow.accesswidener index 686ef2c..9225a7c 100644 --- a/src/main/resources/rainglow.accesswidener +++ b/src/main/resources/rainglow.accesswidener @@ -2,6 +2,15 @@ accessWidener v1 named accessible class net/minecraft/client/particle/GlowParticle$GlowFactory +extendable class net/minecraft/client/option/Option +accessible class net/minecraft/client/option/Option$ValueSet +accessible field net/minecraft/client/option/Option value Ljava/lang/Object; +accessible field net/minecraft/client/option/Option defaultValue Ljava/lang/Object; +accessible field net/minecraft/client/option/Option updateCallback Ljava/util/function/Consumer; +accessible field net/minecraft/client/option/Option text Lnet/minecraft/text/Text; +accessible field net/minecraft/client/option/Option valueToText Ljava/util/function/Function; +accessible class net/minecraft/client/option/Option$CyclingValueSet + accessible method net/minecraft/client/particle/GlowParticle (Lnet/minecraft/client/world/ClientWorld;DDDDDDLnet/minecraft/client/particle/SpriteProvider;)V accessible field net/minecraft/client/particle/GlowParticle RANDOM Lnet/minecraft/util/random/RandomGenerator; diff --git a/src/main/resources/rainglow.mixins.json b/src/main/resources/rainglow.mixins.json index 6258dd8..7571fc2 100644 --- a/src/main/resources/rainglow.mixins.json +++ b/src/main/resources/rainglow.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8", "package": "io.ix0rai.rainglow.mixin", - "compatibilityLevel": "JAVA_17", + "compatibilityLevel": "JAVA_21", "mixins": [ "AllayEntityMixin", "DyeItemMixin", @@ -17,7 +17,9 @@ "client.GlowSquidEntityRendererMixin", "client.SlimeEntityRendererMixin", "client.SlimeParticleMixin", - "client.SquidInkParticleMixin" + "client.SquidInkParticleMixin", + "client.screen.CyclingValueSetMixin", + "client.screen.SliderValueImplMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/rainglow.toml b/src/main/resources/rainglow.toml deleted file mode 100644 index bf90fda..0000000 --- a/src/main/resources/rainglow.toml +++ /dev/null @@ -1 +0,0 @@ -mode = "rainbow" \ No newline at end of file