From 1a407000610426b692ac69209fa7ac52f0ead4ee Mon Sep 17 00:00:00 2001 From: ix0rai Date: Thu, 6 Jun 2024 14:34:21 -0500 Subject: [PATCH 1/2] initial work --- .../java/io/ix0rai/rainglow/Rainglow.java | 8 +- .../rainglow/config/PerWorldConfig.java | 120 +++++++++++++++--- .../rainglow/config/RainglowConfigScreen.java | 76 +++++++---- .../ix0rai/rainglow/data/RainglowColour.java | 42 +++--- .../ix0rai/rainglow/data/RainglowEntity.java | 2 +- .../io/ix0rai/rainglow/data/RainglowMode.java | 30 +++-- .../ix0rai/rainglow/mixin/MobEntityMixin.java | 2 +- .../custom_modes/nonbinary_pride.json | 2 +- .../custom_modes/nonbinary_pride.json | 2 +- 9 files changed, 210 insertions(+), 74 deletions(-) diff --git a/src/main/java/io/ix0rai/rainglow/Rainglow.java b/src/main/java/io/ix0rai/rainglow/Rainglow.java index b4c5f6a..c5366e0 100644 --- a/src/main/java/io/ix0rai/rainglow/Rainglow.java +++ b/src/main/java/io/ix0rai/rainglow/Rainglow.java @@ -57,13 +57,13 @@ public static Identifier id(String id) { return new Identifier(MOD_ID, id); } - public static String generateRandomColourId(World world, RandomGenerator random) { - var colours = MODE_CONFIG.getMode(world).getColours(); + public static String generateRandomColourId(World world, RandomGenerator random, RainglowEntity entity) { + var colours = MODE_CONFIG.getMode(world, entity).getColours(); return colours.get(random.nextInt(colours.size())).getId(); } public static boolean colourUnloaded(World world, RainglowEntity entityType, String colour) { - var colours = MODE_CONFIG.getMode(world).getColours(); + var colours = MODE_CONFIG.getMode(world, entityType).getColours(); return !colours.contains(RainglowColour.get(colour)) && !colour.equals(entityType.getDefaultColour().getId()); } @@ -85,7 +85,7 @@ public static RainglowColour getColour(World world, RainglowEntity entityType, D String colour = tracker.get(entityType.getTrackedData()); if (colourUnloaded(world, entityType, colour)) { // Use last generated colour if not null else generate a new colour - tracker.set(entityType.getTrackedData(), generateRandomColourId(world, random)); + tracker.set(entityType.getTrackedData(), generateRandomColourId(world, random, entityType)); colour = tracker.get(entityType.getTrackedData()); } diff --git a/src/main/java/io/ix0rai/rainglow/config/PerWorldConfig.java b/src/main/java/io/ix0rai/rainglow/config/PerWorldConfig.java index 47ca576..0ffb2e5 100644 --- a/src/main/java/io/ix0rai/rainglow/config/PerWorldConfig.java +++ b/src/main/java/io/ix0rai/rainglow/config/PerWorldConfig.java @@ -8,41 +8,91 @@ import folk.sisby.kaleido.lib.quiltconfig.api.values.TrackedValue; import folk.sisby.kaleido.lib.quiltconfig.api.values.ValueMap; import io.ix0rai.rainglow.Rainglow; +import io.ix0rai.rainglow.data.RainglowEntity; import io.ix0rai.rainglow.data.RainglowMode; import io.ix0rai.rainglow.mixin.MinecraftServerAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; @SerializedNameConvention(NamingSchemes.SNAKE_CASE) public class PerWorldConfig extends ReflectiveConfig { @Comment("The mode used for each non-local world.") @Comment("Note that for singleplayer worlds, the mode is saved in the world folder in the file \"config/rainglow.json\".") - public final TrackedValue> modesByWorld = this.map("").build(); + public final TrackedValue>> modesByWorld = this.map(ValueMap.builder("").build()).build(); - public RainglowMode getMode(World world) { + // todo hot garbage + public Map getModes(World world) { + var saveName = getSaveName(world); + Either, ValueMap> modes = null; + + if (saveName.right().isPresent()) { + modes = Either.right(modesByWorld.value().get(saveName.right().get())); + } else if (saveName.left().isPresent()) { + Path path = getJsonPath(saveName.left().get()); + if (Files.exists(path)) { + try { + var data = readJson(path); + modes = Either.left(data.entities); + } catch (Exception e) { + Rainglow.LOGGER.error("Failed to load Rainglow config for world " + saveName.left().get(), e); + } + } else { + save(saveName.left().get(), RainglowMode.get(Rainglow.CONFIG.defaultMode.value()), null); + } + } + + if (modes == null) { + var map = new HashMap(); + for (RainglowEntity entity : RainglowEntity.values()) { + map.put(entity, RainglowMode.get(Rainglow.CONFIG.defaultMode.value())); + } + + return map; + } else { + if (modes.left().isPresent()) { + var map = new HashMap(); + for (RainglowEntity entity : RainglowEntity.values()) { + map.put(entity, RainglowMode.get(modes.left().get().get(entity.getId()))); + } + + return map; + } else { + var map = new HashMap(); + for (RainglowEntity entity : RainglowEntity.values()) { + map.put(entity, RainglowMode.get(modes.right().get().get(entity.getId()))); + } + + return map; + } + } + } + + public RainglowMode getMode(World world, RainglowEntity entity) { var saveName = getSaveName(world); String mode = null; if (saveName.right().isPresent()) { - mode = modesByWorld.value().get(saveName.right().get()); + mode = modesByWorld.value().get(entity.getId()).get(saveName.right().get()); } else if (saveName.left().isPresent()) { Path path = getJsonPath(saveName.left().get()); if (Files.exists(path)) { try { - var data = Rainglow.GSON.fromJson(Files.readString(path), RainglowJson.class); - if (data != null) { - mode = data.mode; - } + var data = readJson(path); + mode = data.entities.get(entity.getId()); } catch (Exception e) { Rainglow.LOGGER.error("Failed to load Rainglow config for world " + saveName.left().get(), e); } } else { - save(saveName.left().get(), RainglowMode.get(Rainglow.CONFIG.defaultMode.value())); + save(saveName.left().get(), RainglowMode.get(Rainglow.CONFIG.defaultMode.value()), entity); } } @@ -53,18 +103,47 @@ public RainglowMode getMode(World world) { } } - public void setMode(World world, RainglowMode mode) { - var saveName = getSaveName(world); - if (saveName.right().isPresent()) { - modesByWorld.value().put(saveName.right().get(), mode.getId()); - } else if (saveName.left().isPresent()) { - save(saveName.left().get(), mode); + private static RainglowJson readJson(Path path) { + if (Files.exists(path)) { + try { + return Rainglow.GSON.fromJson(Files.readString(path), RainglowJson.class); + } catch (Exception e) { + Rainglow.LOGGER.error("Failed to load Rainglow config for world " + path, e); + } + } + + return new RainglowJson(RainglowMode.get(Rainglow.CONFIG.defaultMode.value())); + } + + public void setMode(World world, RainglowMode mode, @Nullable RainglowEntity entity) { + Consumer setter = (id) -> { + var saveName = getSaveName(world); + if (saveName.right().isPresent()) { + modesByWorld.value().get(id).put(saveName.right().get(), mode.getId()); + } else if (saveName.left().isPresent()) { + save(saveName.left().get(), mode, entity); + } + }; + + if (entity != null) { + setter.accept(entity.getId()); + } else { + for (RainglowEntity e : RainglowEntity.values()) { + setter.accept(e.getId()); + } } } - private static void save(Path worldPath, RainglowMode mode) { + private static void save(Path worldPath, RainglowMode mode, @Nullable RainglowEntity entity) { Path path = getJsonPath(worldPath); - var data = new RainglowJson(mode.getId()); + RainglowJson data; + + if (Files.exists(path) && entity != null) { + data = readJson(path); + data.entities.put(entity.getId(), mode.getId()); + } else { + data = new RainglowJson(mode); + } try { Path configPath = getConfigFolderPath(worldPath); @@ -108,7 +187,12 @@ private static Path getWorldPath(MinecraftServer server) { return ((MinecraftServerAccessor) server).getSession().method_54543().path(); } - private record RainglowJson(String mode) { - + private record RainglowJson(Map entities) { + public RainglowJson(RainglowMode mode) { + this(new HashMap<>()); + for (RainglowEntity entity : RainglowEntity.values()) { + this.entities.put(entity.getId(), mode.getId()); + } + } } } diff --git a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java index 1b5c1c3..5163ddf 100644 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java @@ -7,6 +7,7 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ClickableWidget; import net.minecraft.client.gui.widget.button.ButtonWidget; import net.minecraft.client.gui.widget.button.CyclingButtonWidget; import net.minecraft.client.gui.widget.layout.GridWidget; @@ -16,6 +17,7 @@ import net.minecraft.client.gui.widget.text.TextWidget; import net.minecraft.client.option.Option; import net.minecraft.text.CommonTexts; +import net.minecraft.text.MutableText; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Language; @@ -42,7 +44,14 @@ public class RainglowConfigScreen extends Screen implements ScreenWithUnsavedWar public RainglowConfigScreen(@Nullable Screen parent) { super(TITLE); this.parent = parent; - this.mode = getMode(); + if (MinecraftClient.getInstance().world != null) { + var modes = Rainglow.MODE_CONFIG.getModes(MinecraftClient.getInstance().world); + // if all modes are the same, set the mode to that mode, otherwise set it to null + this.mode = modes.entrySet().stream().allMatch(entry -> entry.getValue().equals(modes.get(RainglowEntity.GLOW_SQUID))) ? modes.get(RainglowEntity.GLOW_SQUID) : null; + } else { + this.mode = RainglowMode.get(Rainglow.CONFIG.defaultMode.getRealValue()); + } + this.saveButton = ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> this.save()).build(); this.saveButton.active = false; } @@ -51,15 +60,15 @@ private void setMode(RainglowMode mode) { if (MinecraftClient.getInstance().world == null) { Rainglow.CONFIG.defaultMode.setValue(mode.getId()); } else { - Rainglow.MODE_CONFIG.setMode(MinecraftClient.getInstance().world, mode); + Rainglow.MODE_CONFIG.setMode(MinecraftClient.getInstance().world, mode, null); } } - private RainglowMode getMode() { + private RainglowMode getMode(RainglowEntity entity) { if (MinecraftClient.getInstance().world == null) { return RainglowMode.get(Rainglow.CONFIG.defaultMode.getRealValue()); } else { - return Rainglow.MODE_CONFIG.getMode(MinecraftClient.getInstance().world); + return Rainglow.MODE_CONFIG.getMode(MinecraftClient.getInstance().world, entity); } } @@ -81,8 +90,14 @@ public void init() { 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); + LinearLayoutWidget modeLayout = headerLayout.add(LinearLayoutWidget.createHorizontal().setSpacing(8), LayoutSettings::alignVerticallyBottom); + modeLayout.add(createModeButton(), LayoutSettings::alignVerticallyBottom); + // todo link to page with per-entity mode editing + modeLayout.add(ButtonWidget.builder(Text.literal("grind"), button -> { + //this.mode = RainglowMode.get("grind"); + // this.saveButton.active = true; + }).width(100).build(), LayoutSettings::alignVerticallyBottom); + headerLayout.add(getInfoText(), settings -> settings.alignHorizontallyCenter().alignVerticallyBottom().setBottomPadding(1)); // contents LinearLayoutWidget contentLayout = LinearLayoutWidget.createVertical(); @@ -138,22 +153,39 @@ private DeferredSaveOption createColourRaritySlider(RainglowEntity enti )); } - 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; - } - ); + public ClickableWidget createModeButton() { + if (mode != null) { + return CyclingButtonWidget.builder(RainglowMode::getText) + .values(RainglowMode.values()) + .initially(this.mode) + .tooltip(this::createColourListLabel) + .build( + 0, + 0, + 200, + 20, + Rainglow.translatableText("config.mode"), + (cyclingButtonWidget, mode) -> { + this.saveButton.active = true; + this.mode = mode; + } + ); + } else { + return ButtonWidget.builder(Text.literal("Mode: Mixed"), button -> { + this.mode = RainglowMode.get(Rainglow.CONFIG.defaultMode.getRealValue()); + this.saveButton.active = true; + this.clearAndInit(); + }).tooltip(createTooltip()).width(200).build(); + } + } + + private Tooltip createTooltip() { + MutableText text = Text.empty().append("Modes:"); + for (RainglowEntity entity : RainglowEntity.values()) { + text.append("\n").append(Text.translatable("entity.minecraft." + entity.getId())).append(": ").append(this.getMode(entity).getText()); + } + + return Tooltip.create(text); } private void save() { diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java b/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java index f87b2e9..71cc309 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java @@ -12,23 +12,23 @@ import java.util.Map; public enum RainglowColour { - 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); + BLACK("black", 0x000000, 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", 0x0000FF, 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", 0x964B00, 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", 0x00FFFF, 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", 0x808080, 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", 0x0A5C36, 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", 0x4B0082, 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", 0xADD8E6, 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", 0xd3d3d3, 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", 0x32CD32, 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", 0xFF00FF, 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", 0xFFA500, 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", 0xFFC0CB, 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", 0x800080, 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", 0xFF0000, 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", 0xFFFFFF, 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", 0xFFFF00, 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 { @@ -36,14 +36,16 @@ public enum RainglowColour { } private final String id; + private final int hex; private final Map textures; private final RGB passiveParticleRgb; private final RGB altPassiveParticleRgb; private final RGB inkRgb; private final Item item; - RainglowColour(String id, RGB passiveParticleRgb, RGB altPassiveParticleRgb, RGB inkRgb, Item item) { + RainglowColour(String id, int hex, RGB passiveParticleRgb, RGB altPassiveParticleRgb, RGB inkRgb, Item item) { this.id = id; + this.hex = hex; this.textures = new HashMap<>(); this.passiveParticleRgb = passiveParticleRgb; this.altPassiveParticleRgb = altPassiveParticleRgb; @@ -79,6 +81,10 @@ public String getId() { return this.id; } + public int getHex() { + return this.hex; + } + public RGB getPassiveParticleRgb() { return this.passiveParticleRgb; } diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java b/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java index d29a220..d601c78 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java @@ -77,7 +77,7 @@ public RainglowColour readNbt(World world, NbtCompound nbt, RandomGenerator rand String colour = nbt.getString(Rainglow.CUSTOM_NBT_KEY); if (Rainglow.colourUnloaded(world, this, colour)) { - colour = Rainglow.generateRandomColourId(world, random); + colour = Rainglow.generateRandomColourId(world, random, this); } return RainglowColour.get(colour); diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java b/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java index 4c94a53..ab4c6ac 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java @@ -2,10 +2,10 @@ import io.ix0rai.rainglow.Rainglow; import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.MutableText; import net.minecraft.text.Style; import net.minecraft.text.Text; -import net.minecraft.text.TextCodecs; -import net.minecraft.text.TextColor; +import net.minecraft.util.Language; import java.util.ArrayList; import java.util.Collection; @@ -25,12 +25,11 @@ public RainglowMode(JsonMode mode, boolean existsLocally) { this( mode.id, mode.colourIds, - Rainglow.translatableText("mode." + mode.id).copy().setStyle(Style.EMPTY.withColor(TextColor.fromRgb(Integer.parseInt(mode.textColour, 16)))), existsLocally ); } - public RainglowMode(String id, List colourIds, Text text, boolean existsLocally) { + public RainglowMode(String id, List colourIds, boolean existsLocally) { if (!id.matches("^[a-z0-9_]+$")) { Rainglow.LOGGER.error("loaded rainglow mode with id {} which contains invalid characters! (only lowercase letters, numbers, and underscores are allowed)", id); } @@ -50,7 +49,24 @@ public RainglowMode(String id, List colourIds, Text text, boolean exists Rainglow.LOGGER.error("cannot load mode with id {}: no colours found!", id); } - this.text = text; + // todo possible improvements: split remainder between first and last section, ignore spaces in char count and sections, split sections at spaces + if (!colours.isEmpty()) { + String fullText = Language.getInstance().get(Rainglow.translatableTextKey("mode." + id)); + int textLength = fullText.length(); + int charsPerSection = textLength / colours.size(); + int extraCharsOnLastSection = textLength % colours.size(); + + MutableText formatted = Text.empty(); + for (int i = 0; i < colours.size(); i++) { + int start = i * charsPerSection; + int end = start + charsPerSection + (i == colours.size() - 1 ? extraCharsOnLastSection : 0); + formatted.append(Text.literal(fullText.substring(start, end)).setStyle(Style.EMPTY.withColor((colours.get(i).getHex())))); + } + + this.text = formatted; + } else { + this.text = Rainglow.translatableText("mode." + id); + } this.existsLocally = existsLocally; MODES.put(this.id, this); @@ -120,17 +136,15 @@ public static void printLoadedModes() { 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); + return new RainglowMode(id, colourIds, RainglowMode.get(id) != null); } diff --git a/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java index de59dc9..080fab5 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java @@ -41,6 +41,6 @@ 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.getWorld(), this.random)); + return i >= rarity ? entity.getDefaultColour() : RainglowColour.get(Rainglow.generateRandomColourId(this.getWorld(), this.random, entity)); } } diff --git a/src/main/resources/assets/rainglow/custom_modes/nonbinary_pride.json b/src/main/resources/assets/rainglow/custom_modes/nonbinary_pride.json index 1c8b04c..b71ce6a 100644 --- a/src/main/resources/assets/rainglow/custom_modes/nonbinary_pride.json +++ b/src/main/resources/assets/rainglow/custom_modes/nonbinary_pride.json @@ -1,6 +1,6 @@ { "id": "enby_pride", - "textColour": "705CA8", + "textColour": "9888C4", "colourIds": [ "yellow", "white", diff --git a/src/main/resources/data/rainglow/custom_modes/nonbinary_pride.json b/src/main/resources/data/rainglow/custom_modes/nonbinary_pride.json index 1c8b04c..b71ce6a 100644 --- a/src/main/resources/data/rainglow/custom_modes/nonbinary_pride.json +++ b/src/main/resources/data/rainglow/custom_modes/nonbinary_pride.json @@ -1,6 +1,6 @@ { "id": "enby_pride", - "textColour": "705CA8", + "textColour": "9888C4", "colourIds": [ "yellow", "white", From fbccae9194e1b1a7a92ead042be5971269e7c2b2 Mon Sep 17 00:00:00 2001 From: ix0rai Date: Thu, 6 Jun 2024 15:10:20 -0500 Subject: [PATCH 2/2] initial per-entity mode config screen --- .../rainglow/config/ModeConfigScreen.java | 112 ++++++++++++++++++ .../rainglow/config/RainglowConfigScreen.java | 7 +- 2 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/ix0rai/rainglow/config/ModeConfigScreen.java diff --git a/src/main/java/io/ix0rai/rainglow/config/ModeConfigScreen.java b/src/main/java/io/ix0rai/rainglow/config/ModeConfigScreen.java new file mode 100644 index 0000000..aab2a85 --- /dev/null +++ b/src/main/java/io/ix0rai/rainglow/config/ModeConfigScreen.java @@ -0,0 +1,112 @@ +package io.ix0rai.rainglow.config; + +import io.ix0rai.rainglow.Rainglow; +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.gui.screen.option.GameOptionsScreen; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.gui.widget.button.ButtonWidget; +import net.minecraft.client.gui.widget.button.CyclingButtonWidget; +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.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.HashMap; +import java.util.List; +import java.util.Map; + +public class ModeConfigScreen extends GameOptionsScreen implements ScreenWithUnsavedWarning { + private final ButtonWidget saveButton; + private final Map updatedModes = new HashMap<>(); + private boolean isConfirming; + + private static final Text TITLE = Rainglow.translatableText("config.custom"); + + public ModeConfigScreen(Screen parent) { + super(parent, MinecraftClient.getInstance().options, TITLE); + this.saveButton = ButtonWidget.builder(Rainglow.translatableText("config.save"), button -> this.save()).build(); + this.saveButton.active = false; + } + + private ClickableWidget createEntityCyclingWidget(RainglowEntity entity) { + Text text = Text.translatable("entity.minecraft." + entity.getId()); + + return CyclingButtonWidget.builder(RainglowMode::getText) + .values(RainglowMode.values()) + // todo this will crash if the world is null + .initially(Rainglow.MODE_CONFIG.getMode(MinecraftClient.getInstance().world, entity)) + .tooltip(RainglowConfigScreen::createColourListLabel) + .build( + text, + (cyclingButtonWidget, mode) -> { + this.saveButton.active = true; + this.updatedModes.put(entity, mode); + } + ); + } + + private void save() { + for (Map.Entry entry : this.updatedModes.entrySet()) { + Rainglow.MODE_CONFIG.setMode(MinecraftClient.getInstance().world, entry.getValue(), entry.getKey()); + } + + 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)); + for (RainglowEntity entity : RainglowEntity.values()) { + buttonListWidget.method_58227(List.of(this.createEntityCyclingWidget(entity))); + } + + 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/RainglowConfigScreen.java b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java index 5163ddf..df742f2 100644 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java @@ -94,8 +94,7 @@ public void init() { modeLayout.add(createModeButton(), LayoutSettings::alignVerticallyBottom); // todo link to page with per-entity mode editing modeLayout.add(ButtonWidget.builder(Text.literal("grind"), button -> { - //this.mode = RainglowMode.get("grind"); - // this.saveButton.active = true; + this.client.setScreen(new ModeConfigScreen(this)); }).width(100).build(), LayoutSettings::alignVerticallyBottom); headerLayout.add(getInfoText(), settings -> settings.alignHorizontallyCenter().alignVerticallyBottom().setBottomPadding(1)); @@ -158,7 +157,7 @@ public ClickableWidget createModeButton() { return CyclingButtonWidget.builder(RainglowMode::getText) .values(RainglowMode.values()) .initially(this.mode) - .tooltip(this::createColourListLabel) + .tooltip(RainglowConfigScreen::createColourListLabel) .build( 0, 0, @@ -202,7 +201,7 @@ private void save() { this.saveButton.active = false; } - private Tooltip createColourListLabel(RainglowMode mode) { + static 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(Rainglow.translatableTextKey("config.colours_to_apply"))); int maxDisplayedColourCount = 16;