From 6b8c5740fa30cb32e6c47cc2d4e5e678492a1081 Mon Sep 17 00:00:00 2001 From: Matt Sturgeon Date: Sun, 31 Dec 2023 12:48:36 +0000 Subject: [PATCH 1/2] Server whitelist/blacklist config Allow switching between whitelist, blacklist, & no restriction. --- CHANGELOG.md | 1 + .../main/java/net/xolt/freecam/Freecam.java | 41 ++++++++++++++++++- .../net/xolt/freecam/config/ModConfig.java | 26 ++++++++++++ .../resources/assets/freecam/lang/en_us.json | 11 +++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b14f2b32..eb9f4eed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and Freecam's versioning is based on [Semantic Versioning](https://semver.org/sp ### Added - Added a way to configure key bindings from Freecam's config menu ([#143](https://github.com/MinecraftFreecam/Freecam/pull/143)). +- Added an optional server whitelist/blacklist ([#146](https://github.com/MinecraftFreecam/Freecam/pull/146)). ### Changed diff --git a/common/src/main/java/net/xolt/freecam/Freecam.java b/common/src/main/java/net/xolt/freecam/Freecam.java index c2ad9186..295071ee 100644 --- a/common/src/main/java/net/xolt/freecam/Freecam.java +++ b/common/src/main/java/net/xolt/freecam/Freecam.java @@ -3,6 +3,7 @@ import net.minecraft.client.CameraType; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.player.Input; import net.minecraft.client.player.KeyboardInput; import net.minecraft.client.renderer.texture.Tickable; @@ -33,8 +34,9 @@ public class Freecam { private static CameraType rememberedF5 = null; public static void preTick(Minecraft mc) { - // Disable if the previous tick asked us to - if (disableNextTick && isEnabled()) { + // Disable if the previous tick asked us to, + // or Freecam is restricted on the current server + if ((disableNextTick || isRestrictedOnServer()) && isEnabled()) { toggle(); } disableNextTick = false; @@ -85,6 +87,13 @@ public static boolean resetTripodHandler() { } public static void toggle() { + if (isRestrictedOnServer()) { + if (ModConfig.INSTANCE.notification.notifyFreecam) { + MC.player.displayClientMessage(Component.translatable("msg.freecam.restrictedByConfig", MC.getCurrentServer().ip), true); + } + return; + } + if (tripodEnabled) { toggleTripod(activeTripod); return; @@ -106,6 +115,13 @@ private static void toggleTripod(TripodSlot tripod) { return; } + if (isRestrictedOnServer()) { + if (ModConfig.INSTANCE.notification.notifyTripod) { + MC.player.displayClientMessage(Component.translatable("msg.freecam.restrictedByConfig", MC.getCurrentServer().ip), true); + } + return; + } + if (tripodEnabled) { if (activeTripod == tripod) { onDisableTripod(); @@ -295,4 +311,25 @@ public static boolean isEnabled() { public static boolean isPlayerControlEnabled() { return playerControlEnabled; } + + public static boolean isRestrictedOnServer() { + ServerData server = MC.getCurrentServer(); + ModConfig.ServerRestriction mode = ModConfig.INSTANCE.servers.mode; + if (mode == ModConfig.ServerRestriction.NONE || server == null || MC.isSingleplayer()) { + return false; + } + + String ip = server.ip.trim().toLowerCase(); + return switch (mode) { + case WHITELIST -> ModConfig.INSTANCE.servers.whitelist.stream() + .map(String::trim) + .map(String::toLowerCase) + .noneMatch(ip::equals); + case BLACKLIST -> ModConfig.INSTANCE.servers.blacklist.stream() + .map(String::trim) + .map(String::toLowerCase) + .anyMatch(ip::equals); + default -> throw new IllegalStateException("Unexpected mode value in Freecam.isRestrictedOnServer: " + mode); + }; + } } diff --git a/common/src/main/java/net/xolt/freecam/config/ModConfig.java b/common/src/main/java/net/xolt/freecam/config/ModConfig.java index 0fe50e1f..0df68616 100644 --- a/common/src/main/java/net/xolt/freecam/config/ModConfig.java +++ b/common/src/main/java/net/xolt/freecam/config/ModConfig.java @@ -12,6 +12,10 @@ import net.xolt.freecam.config.gui.ModBindingsConfig; import net.xolt.freecam.config.gui.VariantTooltip; import net.xolt.freecam.variant.api.BuildVariant; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; @Config(name = "freecam") public class ModConfig implements ConfigData { @@ -109,6 +113,19 @@ public static class UtilityConfig { public InteractionMode interactionMode = InteractionMode.CAMERA; } + @ConfigEntry.Gui.Tooltip + @ConfigEntry.Gui.CollapsibleObject + public ServerConfig servers = new ServerConfig(); + public static class ServerConfig { + @ConfigEntry.Gui.Tooltip(count = 2) + @ConfigEntry.Gui.EnumHandler(option = EnumDisplayOption.BUTTON) + public ServerRestriction mode = ServerRestriction.NONE; + + // These must be mutable lists, so no Collections.emptyList() + public List whitelist = new ArrayList<>(); + public List blacklist = new ArrayList<>(); + } + @ConfigEntry.Gui.Tooltip @ConfigEntry.Gui.CollapsibleObject public NotificationConfig notification = new NotificationConfig(); @@ -169,4 +186,13 @@ public enum Perspective implements SelectionListEntry.Translatable { return key; } } + + public enum ServerRestriction implements SelectionListEntry.Translatable { + NONE, WHITELIST, BLACKLIST; + + @Override + public @NotNull String getKey() { + return "text.autoconfig.freecam.option.servers.mode." + toString().toLowerCase(); + } + } } diff --git a/common/src/main/resources/assets/freecam/lang/en_us.json b/common/src/main/resources/assets/freecam/lang/en_us.json index 7f9aff19..8cae3a9d 100644 --- a/common/src/main/resources/assets/freecam/lang/en_us.json +++ b/common/src/main/resources/assets/freecam/lang/en_us.json @@ -6,6 +6,7 @@ "key.freecam.configGui": "Config GUI", "msg.freecam.enable": "Freecam has been enabled.", "msg.freecam.disable": "Freecam has been disabled.", + "msg.freecam.restrictedByConfig": "Freecam is restricted on the current server (%s).", "msg.freecam.openTripod": "Opening camera %s", "msg.freecam.closeTripod": "Closing camera %s", "msg.freecam.tripodReset": "Reset camera %s", @@ -68,6 +69,16 @@ "text.autoconfig.freecam.option.utility.interactionMode.@Tooltip": "The source of block/entity interactions.", "text.autoconfig.freecam.option.utility.interactionMode.camera": "Camera", "text.autoconfig.freecam.option.utility.interactionMode.player": "Player", + "text.autoconfig.freecam.option.servers": "Multiplayer Options", + "text.autoconfig.freecam.option.servers.@Tooltip": "Options relating to multiplayer servers.", + "text.autoconfig.freecam.option.servers.mode": "Restriction mode", + "text.autoconfig.freecam.option.servers.mode.@Tooltip[0]": "Allow or disallow use of freecam on certain servers.", + "text.autoconfig.freecam.option.servers.mode.@Tooltip[1]": "(using either a whitelist or blacklist).", + "text.autoconfig.freecam.option.servers.mode.none": "No restriction", + "text.autoconfig.freecam.option.servers.mode.whitelist": "Whitelist", + "text.autoconfig.freecam.option.servers.mode.blacklist": "Blacklist", + "text.autoconfig.freecam.option.servers.whitelist": "Whitelist:", + "text.autoconfig.freecam.option.servers.blacklist": "Blacklist:", "text.autoconfig.freecam.option.notification": "Notification Options", "text.autoconfig.freecam.option.notification.@Tooltip": "Show or hide notifications.", "text.autoconfig.freecam.option.notification.notifyFreecam": "Freecam Notifications", From 2cf0ca8a8dd068c42cca328f2a381271de153f36 Mon Sep 17 00:00:00 2001 From: Matt Sturgeon Date: Sun, 31 Dec 2023 13:55:08 +0000 Subject: [PATCH 2/2] Only show relevant server whitelists Show Whitelist config in whitelist mode, and Blacklist in blacklist mode. Don't show either in "no restriction" mode. --- .../config/gui/AutoConfigExtensions.java | 9 ++++ .../gui/ServerRestrictionDependencies.java | 50 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 common/src/main/java/net/xolt/freecam/config/gui/ServerRestrictionDependencies.java diff --git a/common/src/main/java/net/xolt/freecam/config/gui/AutoConfigExtensions.java b/common/src/main/java/net/xolt/freecam/config/gui/AutoConfigExtensions.java index 3cb927d9..b33dd917 100644 --- a/common/src/main/java/net/xolt/freecam/config/gui/AutoConfigExtensions.java +++ b/common/src/main/java/net/xolt/freecam/config/gui/AutoConfigExtensions.java @@ -8,6 +8,10 @@ import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; import net.minecraft.network.chat.Component; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.function.Predicate; + /** * Extensions and modifications to AutoConfig. * @@ -26,5 +30,10 @@ public static void apply(Class configClass) { ModBindingsConfigImpl.apply(registry); VariantTooltipImpl.apply(registry); BoundedContinuousImpl.apply(registry); + ServerRestrictionDependencies.apply(registry); + } + + static Predicate isField(Class declaringClass, String... fieldNames) { + return field -> field.getDeclaringClass().equals(declaringClass) && Arrays.asList(fieldNames).contains(field.getName()); } } diff --git a/common/src/main/java/net/xolt/freecam/config/gui/ServerRestrictionDependencies.java b/common/src/main/java/net/xolt/freecam/config/gui/ServerRestrictionDependencies.java new file mode 100644 index 00000000..d33ba6bf --- /dev/null +++ b/common/src/main/java/net/xolt/freecam/config/gui/ServerRestrictionDependencies.java @@ -0,0 +1,50 @@ +package net.xolt.freecam.config.gui; + +import me.shedaniel.autoconfig.gui.registry.GuiRegistry; +import me.shedaniel.clothconfig2.gui.entries.SelectionListEntry; +import net.xolt.freecam.config.ModConfig; + +import static net.xolt.freecam.config.ModConfig.ServerRestriction.BLACKLIST; +import static net.xolt.freecam.config.ModConfig.ServerRestriction.WHITELIST; +import static net.xolt.freecam.config.gui.AutoConfigExtensions.isField; + +class ServerRestrictionDependencies { + + private static SelectionListEntry mode; + + @SuppressWarnings("UnstableApiUsage") + static void apply(GuiRegistry registry) { + // Capture a reference to the mode entry + registry.registerPredicateTransformer( + (guis, i18n, field, config, defaults, guiProvider) -> { + //noinspection unchecked + mode = guis.stream() + .filter(SelectionListEntry.class::isInstance) + .map(SelectionListEntry.class::cast) + .filter(entry -> entry.getValue() instanceof ModConfig.ServerRestriction) + .reduce((prev, next) -> { throw new IllegalStateException("Multiple SelectionListEntries added to %s.mode".formatted(ModConfig.ServerConfig.class.getSimpleName())); }) + .orElseThrow(() -> new IllegalStateException("No SelectionListEntries added to %s.mode".formatted(ModConfig.ServerConfig.class.getSimpleName()))); + return guis; + }, + isField(ModConfig.ServerConfig.class, "mode") + ); + + // Whitelist dependency + registry.registerPredicateTransformer( + (guis, i18n, field, config, defaults, guiProvider) -> { + guis.forEach(gui -> gui.setDisplayRequirement(() -> mode == null || mode.getValue() == WHITELIST)); + return guis; + }, + isField(ModConfig.ServerConfig.class, "whitelist") + ); + + // Blacklist dependency + registry.registerPredicateTransformer( + (guis, i18n, field, config, defaults, guiProvider) -> { + guis.forEach(gui -> gui.setDisplayRequirement(() -> mode == null || mode.getValue() == BLACKLIST)); + return guis; + }, + isField(ModConfig.ServerConfig.class, "blacklist") + ); + } +}