diff --git a/gradle.properties b/gradle.properties index a9ba895..54aa476 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,8 +4,8 @@ org.gradle.jvmargs=-Xmx1G # minecraft, mappings and loader dependencies # check these on https://modmuss50.me/fabric.html minecraft_version=1.20.6 -quilt_mappings=3 -loader_version=0.15.7 +quilt_mappings=6 +loader_version=0.15.11 # mod properties mod_version=1.2.0+mc1.20.6 @@ -15,4 +15,4 @@ archives_base_name=rainglow # other dependencies java_version=21 mod_menu_version=9.0.0 -fabric_api_version=0.97.8+1.20.6 +fabric_api_version=0.98.0+1.20.6 diff --git a/src/main/java/io/ix0rai/rainglow/Rainglow.java b/src/main/java/io/ix0rai/rainglow/Rainglow.java index 87862d1..90d9f31 100644 --- a/src/main/java/io/ix0rai/rainglow/Rainglow.java +++ b/src/main/java/io/ix0rai/rainglow/Rainglow.java @@ -4,6 +4,7 @@ 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.minecraft.entity.data.DataTracker; @@ -42,10 +43,13 @@ public class Rainglow implements ModInitializer { public void onInitialize() { ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener((RainglowResourceReloader) () -> id("server_mode_data")); + 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); + RainglowNetworking.syncModes(handler.player); // send config to client RainglowNetworking.syncConfig(handler.player); diff --git a/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java b/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java index 7d53184..99a3a33 100644 --- a/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java +++ b/src/main/java/io/ix0rai/rainglow/client/RainglowClient.java @@ -3,7 +3,6 @@ import io.ix0rai.rainglow.Rainglow; 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,62 +10,62 @@ 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) -> { + try (MinecraftClient client = context.client()) { + 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(payload.customMode()); + Rainglow.CONFIG.setMode(RainglowMode.byId(payload.currentMode())); + + for (var entry : payload.enabledMobs().entrySet()) { + Rainglow.CONFIG.setEntityEnabled(entry.getKey(), entry.getValue()); + } - // lock the config from reloading on resource reload - Rainglow.CONFIG.setEditLocked(true); + // lock the config from reloading on resource reload + Rainglow.CONFIG.setEditLocked(true); - // 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); - - client.execute(() -> { - List newModeIds = new ArrayList<>(); - - // add modes that do not exist on the client to the map - for (RainglowMode mode : modes) { - if (!mode.existsLocally()) { - newModeIds.add(mode.getId()); - RainglowMode.addMode(mode); + ClientPlayNetworking.registerGlobalReceiver(RainglowNetworking.ModeSyncPayload.PACKET_ID, (payload, context) -> { + try (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 : 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(); - } + // now that we have modes, we can load the config + if (Rainglow.CONFIG.isUninitialised()) { + Rainglow.CONFIG.reloadFromFile(); + } - // log - if (!newModeIds.isEmpty()) { - Rainglow.LOGGER.info("received new modes from server: " + newModeIds); - } - }); + // log + if (!newModeIds.isEmpty()) { + Rainglow.LOGGER.info("received new modes from server: " + newModeIds); + } + }); + } }); ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> diff --git a/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java b/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java index 9f18df3..08e1e26 100644 --- a/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/CustomModeScreen.java @@ -5,86 +5,92 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.option.SimpleOptionsScreen; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.option.Option; +import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; public class CustomModeScreen extends SimpleOptionsScreen { - 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, MinecraftClient.getInstance().options, Rainglow.translatableText("config.title"), - - ); - - // todo subclass option to allow saving via a save button - // ephemeral value, not saved until a specific method is called (will happen on save pressed) - - // 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 CustomModeScreen(Screen parent, GameOptions gameOptions, Text title, Option[] options) { + super(parent, gameOptions, title, options); + } +// 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, MinecraftClient.getInstance().options, Rainglow.translatableText("config.title"), +// +// ); +// +// // todo subclass option to allow saving via a save button +// // ephemeral value, not saved until a specific method is called (will happen on save pressed) +// +// // 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)); +// } } diff --git a/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java b/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java index df95d9d..42444f2 100644 --- a/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java +++ b/src/main/java/io/ix0rai/rainglow/config/DeferredSaveOption.java @@ -1,7 +1,50 @@ package io.ix0rai.rainglow.config; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.option.GameOptions; import net.minecraft.client.option.Option; +import net.minecraft.text.Text; + +import java.util.Objects; +import java.util.function.Consumer; public class DeferredSaveOption extends Option { - private final T deferredValue; + private T deferredValue; + + public DeferredSaveOption(String key, TooltipSupplier tooltipSupplier, OptionTextGetter textGetter, Option.ValueSet values, T defaultValue, Consumer updateCallback) { + super(key, tooltipSupplier, textGetter, values, defaultValue, updateCallback); + this.deferredValue = this.value; + } + + @Override + public void set(T value) { + T object = (T) 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 { + if (!Objects.equals(this.value, object)) { + this.deferredValue = object; + this.updateCallback.accept(this.deferredValue); + } + } + } + + public static DeferredSaveOption createBoolean(boolean defaultValue, String key) { + return new DeferredSaveOption<>( + "rainglow.config." + key, + Option.constantTooltip(Text.translatable("rainglow.config.tooltip." + key)), + (text, value) -> GameOptions.getGenericValueText(text, Text.translatable("ramel.config.value." + key, value)), + Option.BOOLEAN_VALUES, + defaultValue, + value -> { + } + ); + } + + public void save() { + this.value = this.deferredValue; + } } diff --git a/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java b/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java index 3e379bb..1838f6f 100644 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java +++ b/src/main/java/io/ix0rai/rainglow/config/RainglowConfig.java @@ -8,6 +8,7 @@ import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; +import javax.swing.text.html.parser.Entity; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; @@ -150,6 +151,10 @@ public void setEntityEnabled(RainglowEntity entity, boolean enabled) { this.entityToggles.put(entity, enabled); } + public Map getEntityToggles() { + return this.entityToggles; + } + public void save(boolean log) { if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER || !this.isEditLocked(MinecraftClient.getInstance())) { ConfigIo.writeString(MODE_KEY, this.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 5e2f017..91d97d3 100644 --- a/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java +++ b/src/main/java/io/ix0rai/rainglow/config/RainglowConfigScreen.java @@ -6,6 +6,8 @@ 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.SimpleOptionsScreen; +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; @@ -18,125 +20,90 @@ import java.util.function.Consumer; import java.util.function.Supplier; -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 SimpleOptionsScreen { +// 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; - private final SpruceOption colourRarityOption; + //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 SpruceLabelWidget coloursToApplyLabel; public RainglowConfigScreen(@Nullable Screen parent) { - super(parent, Rainglow.translatableText("config.title")); - Option.ofBoolean() - 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(parent, MinecraftClient.getInstance().options, Rainglow.translatableText("config.title"), + new Option[]{ + DeferredSaveOption.ofBoolean("gaming", false) } ); - } - - private SpruceBooleanOption createEntityToggle(RainglowEntity entity, Supplier getter, Consumer setter) { - return new SpruceBooleanOption(Rainglow.translatableTextKey("config." + "enable_" + entity.getId()), - getter, - setter, - null - ); - } - - @Override - protected void init() { - super.init(); - - 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; - if (i + 1 < l) { - secondToggle = this.entityToggles[i + 1]; - } - - optionList.addOptionEntry(this.entityToggles[i], secondToggle); - } - - optionList.addOptionEntry(this.modeOption, this.customOption); - optionList.addSingleOptionEntry(this.colourRarityOption); - this.addDrawableSelectableElement(optionList); - - // 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); + this.mode = Rainglow.CONFIG.getMode(); - // 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)); +// // 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); +// } +// ); } - private SpruceLabelWidget createColourListLabel(String translationKey, RainglowMode mode, int x, int y) { + private TextWidget createColourListLabel(String translationKey, RainglowMode mode, int x, int y) { // creates a label and appends all the colours that will be applied in the given mode StringBuilder text = new StringBuilder(Language.getInstance().get(translationKey)); int maxDisplayedColourCount = 16; @@ -161,7 +128,7 @@ 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 new TextWidget(Text.literal(text.toString()).setStyle(style), MinecraftClient.getInstance().textRenderer); } private static void sendConfigLockedToast() { diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java b/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java index 44d7813..15de842 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowColour.java @@ -2,42 +2,46 @@ import net.minecraft.item.Item; import net.minecraft.item.Items; +import net.minecraft.network.PacketByteBuf; import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.HashMap; 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), // todo particles + 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), // todo particles + 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), // todo particles + 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), // todo particles + 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), // todo particles + 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), // todo particles + 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 final String id; private Identifier texture; 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) { + RainglowColour(String id, RGB passiveParticleRgb, RGB altPassiveParticleRgb, RGB inkRgb, Item item) { + this.id = id; this.texture = new Identifier("textures/entity/squid/" + this.getId() + ".png"); this.passiveParticleRgb = passiveParticleRgb; this.altPassiveParticleRgb = altPassiveParticleRgb; @@ -62,7 +66,7 @@ public Identifier getTexture(RainglowEntity entityType) { } public String getId() { - return this.name().toLowerCase(); + return this.id; } public RGB getPassiveParticleRgb() { @@ -86,10 +90,19 @@ public String toString() { return this.getId(); } + @Nullable public static RainglowColour get(String id) { return BY_ID.get(id); } 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..76039b8 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowEntity.java @@ -1,10 +1,21 @@ package io.ix0rai.rainglow.data; +import net.minecraft.network.PacketByteBuf; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashMap; + public enum RainglowEntity { GLOW_SQUID("glow_squid"), ALLAY("allay"), SLIME("slime"); + private static final HashMap BY_ID = new HashMap<>(); + static { + Arrays.stream(values()).forEach(mode -> BY_ID.put(mode.getId(), mode)); + } + private final String id; RainglowEntity(String id) { @@ -14,4 +25,17 @@ public enum RainglowEntity { public String getId() { return this.id; } + + 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); + } } diff --git a/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java b/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java index 6fc5cf8..796ab91 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowMode.java @@ -1,8 +1,10 @@ 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; @@ -134,6 +136,22 @@ 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()); + buf.writeString(mode.getText().toString()); + 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.byId(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..ff6513d 100644 --- a/src/main/java/io/ix0rai/rainglow/data/RainglowNetworking.java +++ b/src/main/java/io/ix0rai/rainglow/data/RainglowNetworking.java @@ -4,58 +4,68 @@ 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.getMode().getId(), Rainglow.CONFIG.getCustom(), Rainglow.CONFIG.getEntityToggles())); } - public static void sendModeData(ServerPlayerEntity player) { - PacketByteBuf buf = PacketByteBufs.create(); + public record ConfigSyncPayload(String currentMode, List customMode, Map enabledMobs) 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); + } - 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) + ); + } - 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/mixin/GlowSquidEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/GlowSquidEntityMixin.java index ae90176..f5d7025 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/GlowSquidEntityMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/GlowSquidEntityMixin.java @@ -18,6 +18,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.minecraft.entity.data.DataTracker.Builder; @Mixin(GlowSquidEntity.class) public abstract class GlowSquidEntityMixin extends SquidEntity implements GlowSquidVariantProvider { @@ -27,8 +28,8 @@ protected GlowSquidEntityMixin(EntityType entityType, Wor } @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(Rainglow.getTrackedColourData(RainglowEntity.GLOW_SQUID), RainglowColour.BLUE.getId()); } @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) diff --git a/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java index 678c5f4..40f43a0 100644 --- a/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java +++ b/src/main/java/io/ix0rai/rainglow/mixin/MobEntityMixin.java @@ -21,6 +21,7 @@ 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,7 +36,7 @@ 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) { + public void initialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, CallbackInfoReturnable cir) { if ((Object) this instanceof GlowSquidEntity glowSquid) { String colour = Rainglow.generateRandomColourId(this.getRandom()); ((GlowSquidVariantProvider) glowSquid).setVariant(getColourOrDefault(this.random, RainglowColour.BLUE, colour)); diff --git a/src/main/java/io/ix0rai/rainglow/mixin/SlimeEntityMixin.java b/src/main/java/io/ix0rai/rainglow/mixin/SlimeEntityMixin.java index 695e561..0a32703 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; @@ -33,8 +34,8 @@ 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(Rainglow.getTrackedColourData(RainglowEntity.SLIME), RainglowColour.LIME.getId()); } @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) diff --git a/src/main/resources/rainglow.accesswidener b/src/main/resources/rainglow.accesswidener index e19e9f7..654039e 100644 --- a/src/main/resources/rainglow.accesswidener +++ b/src/main/resources/rainglow.accesswidener @@ -1,7 +1,13 @@ 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 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;