From 40d75007f9d632d0d8938145b8b6f81638e6a01a Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:33:55 +0100 Subject: [PATCH 01/23] Update ModConfigDTO.java --- .../net/xolt/freecam/config/model/ModConfigDTO.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/net/xolt/freecam/config/model/ModConfigDTO.java b/common/src/main/java/net/xolt/freecam/config/model/ModConfigDTO.java index 89a9f3604..301b5f7a0 100644 --- a/common/src/main/java/net/xolt/freecam/config/model/ModConfigDTO.java +++ b/common/src/main/java/net/xolt/freecam/config/model/ModConfigDTO.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import net.minecraft.world.level.block.Block; import net.xolt.freecam.config.MCAwareModConfig; +import net.xolt.freecam.network.ServerPolicies; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -50,17 +51,17 @@ public double getVerticalSpeed() { @Override public boolean ignoreAllCollision() { - return collision.ignoreAll; + return ServerPolicies.allowClipping() && collision.ignoreAll; } @Override public boolean shouldCheckInitialCollision() { - return collision.alwaysCheck || !collision.ignoreAll; + return !ServerPolicies.allowClipping() || collision.alwaysCheck || !collision.ignoreAll; } @Override public boolean ignoreCollisionWith(Block block) { - return collision.ignoreAll || collisionPredicate.shouldIgnore(block); + return ServerPolicies.allowClipping() && (collision.ignoreAll || collisionPredicate.shouldIgnore(block)); } @Override @@ -80,7 +81,7 @@ public boolean shouldShowHand() { @Override public boolean isFullBrightEnabled() { - return visual.fullBright; + return ServerPolicies.allowFullbright() && visual.fullBright; } @Override @@ -100,11 +101,11 @@ public boolean shouldFreezePlayer() { @Override public boolean shouldPreventInteractions() { - return !utility.allowInteract; + return !ServerPolicies.allowInteract() || !utility.allowInteract; } public boolean allowInteractionsFrom(InteractionMode mode) { - return utility.allowInteract && utility.interactionMode == mode; + return ServerPolicies.allowInteract() && utility.allowInteract && utility.interactionMode == mode; } @Override From 5b1994d7baa7d65b9fbedfb0724a8cfda0f0a07d Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:35:09 +0100 Subject: [PATCH 02/23] Update ClientPacketListenerMixin.java --- .../mixins/ClientPacketListenerMixin.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java b/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java index 270968f77..705ee669f 100644 --- a/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java +++ b/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java @@ -7,6 +7,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//? if <1.20.5 { +/*import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; +import net.xolt.freecam.network.ServerPolicies; +*///? } + @Mixin(ClientPacketListener.class) public class ClientPacketListenerMixin { @@ -14,7 +20,24 @@ public class ClientPacketListenerMixin { @Inject(method = "handleRespawn", at = @At("TAIL")) private void onPlayerRespawn(CallbackInfo ci) { if (Freecam.isEnabled()) { - Freecam.toggle(); + Freecam.disable(); } } + + // Older Minecraft versions expose custom payloads as an identifier plus + // a raw FriendlyByteBuf. Modern versions register a typed payload in the + // loader-specific entrypoint instead. + //? if <1.20.5 { + /*@Inject(method = "handleCustomPayload", at = @At("HEAD")) + private void onCustomPayload(ClientboundCustomPayloadPacket packet, CallbackInfo ci) { + if (!ServerPolicies.CHANNEL.equals(packet.getIdentifier().toString())) { + return; + } + + FriendlyByteBuf data = packet.getData(); + byte[] bytes = new byte[data.readableBytes()]; + data.getBytes(data.readerIndex(), bytes); + ServerPolicies.applyBytes(bytes); + } + *///? } } From 7fa308d50009dca2ace90ed2b26ae846d987d8ba Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:36:09 +0100 Subject: [PATCH 03/23] Update GameRendererMixin.java --- .../main/java/net/xolt/freecam/mixins/GameRendererMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java b/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java index 375429015..4fc5020ba 100644 --- a/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java +++ b/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java @@ -24,10 +24,10 @@ private void onRenderItemInHand(CallbackInfo ci) { } } - // Disables block outlines when allowInteract is disabled. + // Disables block outlines when interactions are disabled. @Inject(method = "shouldRenderBlockOutline", at = @At("HEAD"), cancellable = true) private void onShouldRenderBlockOutline(CallbackInfoReturnable cir) { - if (Freecam.isEnabled() && !Freecam.isPlayerControlEnabled() && ModConfig.get().shouldPreventInteractions()) { + if (Freecam.shouldPreventInteractions()) { cir.setReturnValue(false); } } From b0b167ba7ee5b8fcffa4bf114f30bb72146a7459 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:37:14 +0100 Subject: [PATCH 04/23] Update MinecraftMixin.java --- .../java/net/xolt/freecam/mixins/MinecraftMixin.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/net/xolt/freecam/mixins/MinecraftMixin.java b/common/src/main/java/net/xolt/freecam/mixins/MinecraftMixin.java index 83a69d076..25f3e7f94 100644 --- a/common/src/main/java/net/xolt/freecam/mixins/MinecraftMixin.java +++ b/common/src/main/java/net/xolt/freecam/mixins/MinecraftMixin.java @@ -28,7 +28,15 @@ private void onDoAttack(CallbackInfoReturnable ci) { } } - // Prevents item pick when allowInteract is disabled. + // Prevents item use when interactions are disabled. + @Inject(method = "startUseItem", at = @At("HEAD"), cancellable = true) + private void onUseItem(CallbackInfo ci) { + if (freecam$disableInteract()) { + ci.cancel(); + } + } + + // Prevents item pick when interactions are disabled. //~ if >=26.1 pickBlock -> pickBlockOrEntity @Inject(method = "pickBlockOrEntity", at = @At("HEAD"), cancellable = true) private void onDoItemPick(CallbackInfo ci) { @@ -75,6 +83,6 @@ private void onDisconnect(CallbackInfo ci) { @Unique private static boolean freecam$disableInteract() { - return Freecam.isEnabled() && !Freecam.isPlayerControlEnabled() && ModConfig.get().shouldPreventInteractions(); + return Freecam.shouldPreventInteractions(); } } From 299fcbf2d063b30bea4c492b8c1c0999c449101b Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:38:46 +0100 Subject: [PATCH 05/23] Update MultiPlayerGameModeMixin.java --- .../mixins/MultiPlayerGameModeMixin.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/common/src/main/java/net/xolt/freecam/mixins/MultiPlayerGameModeMixin.java b/common/src/main/java/net/xolt/freecam/mixins/MultiPlayerGameModeMixin.java index f72f81793..42c6d593b 100644 --- a/common/src/main/java/net/xolt/freecam/mixins/MultiPlayerGameModeMixin.java +++ b/common/src/main/java/net/xolt/freecam/mixins/MultiPlayerGameModeMixin.java @@ -9,30 +9,28 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; import net.xolt.freecam.Freecam; -import net.xolt.freecam.config.ModConfig; 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.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import static net.xolt.freecam.Freecam.MC; //? if <=1.18.2 { /*import net.minecraft.client.multiplayer.ClientLevel; *///? } -import static net.xolt.freecam.Freecam.MC; - @Mixin(MultiPlayerGameMode.class) public class MultiPlayerGameModeMixin { // Prevents interacting with blocks when allowInteract is disabled. @Inject(method = "useItemOn", at = @At("HEAD"), cancellable = true) private void onInteractBlock(LocalPlayer player, - //? if <= 1.18.2 - //ClientLevel level, - InteractionHand hand, - BlockHitResult hitResult, - CallbackInfoReturnable cir) { + //? if <=1.18.2 + //ClientLevel level, + InteractionHand hand, + BlockHitResult hitResult, + CallbackInfoReturnable cir) { if (freecam$disableInteract()) { cir.setReturnValue(InteractionResult.PASS); } @@ -65,13 +63,13 @@ private void onInteractEntityAtLocation(Player player, Entity entity, EntityHitR // Prevents attacking self. @Inject(method = "attack", at = @At("HEAD"), cancellable = true) private void onAttackEntity(Player player, Entity target, CallbackInfo ci) { - if (target == MC.player) { + if (target == MC.player || freecam$disableInteract()) { ci.cancel(); } } @Unique private static boolean freecam$disableInteract() { - return Freecam.isEnabled() && !Freecam.isPlayerControlEnabled() && ModConfig.get().shouldPreventInteractions(); + return Freecam.shouldPreventInteractions(); } } From 00fb95683f3012d60f9b697646a46cedb002dfa5 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:40:42 +0100 Subject: [PATCH 06/23] Create ServerPolicies.java --- .../xolt/freecam/network/ServerPolicies.java | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 common/src/main/java/net/xolt/freecam/network/ServerPolicies.java diff --git a/common/src/main/java/net/xolt/freecam/network/ServerPolicies.java b/common/src/main/java/net/xolt/freecam/network/ServerPolicies.java new file mode 100644 index 000000000..5d13ec202 --- /dev/null +++ b/common/src/main/java/net/xolt/freecam/network/ServerPolicies.java @@ -0,0 +1,103 @@ +package net.xolt.freecam.network; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.charset.StandardCharsets; + +public final class ServerPolicies { + public static final String CHANNEL = "freecam:server_config"; + private static final Logger LOGGER = LoggerFactory.getLogger(ServerPolicies.class); + private static final Policies ALLOW_ALL = new Policies(true, true, true, true); + private static volatile Policies current = ALLOW_ALL; + + public static boolean allowFreecam() { + return current.allowFreecam; + } + + public static boolean allowClipping() { + return current.allowClipping; + } + + public static boolean allowFullbright() { + return current.allowFullbright; + } + + public static boolean allowInteract() { + return current.allowInteract; + } + + public static void reset() { + current = ALLOW_ALL; + } + + public static boolean applyBytes(byte[] payload) { + return applyJson(new String(payload, StandardCharsets.UTF_8)); + } + + public static boolean applyJson(String json) { + try { + JsonElement rootElement = parse(json); + if (!rootElement.isJsonObject()) { + throw new JsonParseException("root must be a JSON object"); + } + + JsonObject root = rootElement.getAsJsonObject(); + Policies parsed = new Policies( + readBoolean(root, "allowFreecam"), + readBoolean(root, "allowClipping"), + readBoolean(root, "allowFullbright"), + readBoolean(root, "allowInteract") + ); + current = parsed; + LOGGER.debug("Applied server Freecam policies: {}", parsed); + return true; + } catch (JsonParseException | IllegalStateException | ClassCastException e) { + LOGGER.warn("Ignoring invalid {} payload: {}", CHANNEL, e.getMessage()); + return false; + } + } + + private static JsonElement parse(String json) { + return new JsonParser().parse(json); + } + + private static boolean readBoolean(JsonObject root, String key) { + JsonElement value = root.get(key); + if (value == null) { + return true; + } + if (!value.isJsonPrimitive() || !value.getAsJsonPrimitive().isBoolean()) { + throw new JsonParseException("'" + key + "' must be a boolean"); + } + return value.getAsBoolean(); + } + + private static final class Policies { + private final boolean allowFreecam; + private final boolean allowClipping; + private final boolean allowFullbright; + private final boolean allowInteract; + + private Policies(boolean allowFreecam, boolean allowClipping, boolean allowFullbright, boolean allowInteract) { + this.allowFreecam = allowFreecam; + this.allowClipping = allowClipping; + this.allowFullbright = allowFullbright; + this.allowInteract = allowInteract; + } + + @Override + public String toString() { + return "Policies{" + + "allowFreecam=" + allowFreecam + + ", allowClipping=" + allowClipping + + ", allowFullbright=" + allowFullbright + + ", allowInteract=" + allowInteract + + '}'; + } + } +} From ea48b70f03a372dc1fddcc8740808df2137bd70a Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:41:20 +0100 Subject: [PATCH 07/23] Create ServerPolicyPayload.java --- .../freecam/network/ServerPolicyPayload.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java diff --git a/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java b/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java new file mode 100644 index 000000000..2ec0ec182 --- /dev/null +++ b/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java @@ -0,0 +1,47 @@ +//? if >=1.20.5 { +package net.xolt.freecam.network; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.EncoderException; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.Identifier; +import net.xolt.freecam.Freecam; + +import java.nio.charset.StandardCharsets; + +public record ServerPolicyPayload(String json) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(identifier()); + public static final StreamCodec STREAM_CODEC = new StreamCodec<>() { + @Override + public ServerPolicyPayload decode(ByteBuf buffer) { + byte[] bytes = new byte[buffer.readableBytes()]; + buffer.readBytes(bytes); + return new ServerPolicyPayload(new String(bytes, StandardCharsets.UTF_8)); + } + + @Override + public void encode(ByteBuf buffer, ServerPolicyPayload payload) { + byte[] bytes = payload.json().getBytes(StandardCharsets.UTF_8); + if (bytes.length > ServerPolicies.MAX_PAYLOAD_BYTES) { + throw new EncoderException( + "Freecam server_config payload exceeds " + ServerPolicies.MAX_PAYLOAD_BYTES + " bytes" + ); + } + buffer.writeBytes(bytes); + } + }; + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } + + private static Identifier identifier() { + //? if >=1.21 { + return Identifier.fromNamespaceAndPath(Freecam.MOD_ID, "server_config"); + //? } else + //return new ResourceLocation(Freecam.MOD_ID, "server_config"); + } +} +//? } From 72bafdf91b453edaab26fb63478956ffb60c061c Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:43:14 +0100 Subject: [PATCH 08/23] Update Freecam.java --- .../main/java/net/xolt/freecam/Freecam.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/net/xolt/freecam/Freecam.java b/common/src/main/java/net/xolt/freecam/Freecam.java index 4acac43f7..cf3eb0655 100644 --- a/common/src/main/java/net/xolt/freecam/Freecam.java +++ b/common/src/main/java/net/xolt/freecam/Freecam.java @@ -11,6 +11,7 @@ import net.xolt.freecam.config.ModBindings; import net.xolt.freecam.config.ModConfig; import net.xolt.freecam.config.keys.Tickable; +import net.xolt.freecam.network.ServerPolicies; import net.xolt.freecam.tripod.TripodRegistry; import net.xolt.freecam.tripod.TripodSlot; import net.xolt.freecam.util.FreeCamera; @@ -47,7 +48,7 @@ public static void preTick(Minecraft mc) { // Disable if the previous tick asked us to, // or Freecam is restricted on the current server if ((disableNextTick || isRestrictedOnServer()) && isEnabled()) { - toggle(); + disable(); } disableNextTick = false; @@ -83,8 +84,9 @@ public static void postTick(Minecraft mc) { @ApiStatus.Internal public static void onDisconnect() { if (isEnabled()) { - toggle(); + disable(); } + ServerPolicies.reset(); tripods.clear(); } @@ -282,6 +284,18 @@ private static void onDisabled() { } } + @ApiStatus.Internal + public static void disable() { + if (tripodEnabled) { + onDisableTripod(); + } else if (freecamEnabled) { + onDisableFreecam(); + } + freecamEnabled = false; + tripodEnabled = false; + onDisabled(); + } + private static void resetCamera(TripodSlot tripod) { if (tripodEnabled && activeTripod != TripodSlot.NONE && activeTripod == tripod && freeCamera != null) { moveToPlayer(); @@ -371,11 +385,22 @@ public static boolean isPlayerControlEnabled() { return playerControlEnabled; } + @ApiStatus.Internal + public static boolean shouldPreventInteractions() { + if (!isEnabled()) { + return false; + } + if (!ServerPolicies.allowInteract()) { + return true; + } + return !isPlayerControlEnabled() && ModConfig.get().shouldPreventInteractions(); + } + @ApiStatus.Experimental @ApiStatus.AvailableSince("1.2.4") public static boolean isRestrictedOnServer() { ServerData server = MC.getCurrentServer(); return server != null && !MC.hasSingleplayerServer() - && ModConfig.get().isRestrictedOnServer(server.ip); + && (!ServerPolicies.allowFreecam() || ModConfig.get().isRestrictedOnServer(server.ip)); } } From f061cd554bbce72ce768f7e30b376b00bfcb8e84 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:44:20 +0100 Subject: [PATCH 09/23] Create FabricServerPolicyNetworking.java --- .../fabric/FabricServerPolicyNetworking.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java diff --git a/fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java b/fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java new file mode 100644 index 000000000..2ca3f0e80 --- /dev/null +++ b/fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java @@ -0,0 +1,23 @@ +//? if >=1.20.5 { +package net.xolt.freecam.fabric; + +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.xolt.freecam.network.ServerPolicies; +import net.xolt.freecam.network.ServerPolicyPayload; + +public final class FabricServerPolicyNetworking { + + public static void register() { + //~ if >=26.1 playS2C -> clientboundPlay + PayloadTypeRegistry.clientboundPlay().register( + ServerPolicyPayload.TYPE, + ServerPolicyPayload.STREAM_CODEC + ); + ClientPlayNetworking.registerGlobalReceiver( + ServerPolicyPayload.TYPE, + (payload, context) -> ServerPolicies.applyJson(payload.json()) + ); + } +} +//? } From a5041678e4e76392e79ec86950a8a96c29b20f6d Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:44:54 +0100 Subject: [PATCH 10/23] Update FreecamFabric.java --- fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java b/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java index dc07b37b1..2a0cd03ff 100644 --- a/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java +++ b/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java @@ -11,6 +11,7 @@ public class FreecamFabric implements ClientModInitializer { @Override public void onInitializeClient() { ModConfig.setup(); + FabricServerPolicyNetworking.register(); ModBindings.forEach(KeyMappingHelper::registerKeyMapping); ClientTickEvents.START_CLIENT_TICK.register(Freecam::preTick); ClientTickEvents.END_CLIENT_TICK.register(Freecam::postTick); From e6b5f8af825a5926b24385a3674d03fc8e0d1986 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:46:07 +0100 Subject: [PATCH 11/23] Update FreecamNeoforge.java --- .../xolt/freecam/forge/FreecamNeoforge.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java b/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java index 59b2fe7f8..9cb4b8b05 100644 --- a/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java +++ b/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java @@ -11,10 +11,19 @@ import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; import net.neoforged.neoforge.client.gui.IConfigScreenFactory; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.xolt.freecam.Freecam; import net.xolt.freecam.config.ModBindings; import net.xolt.freecam.config.ModConfig; import net.xolt.freecam.config.gui.ConfigScreenProvider; +import net.xolt.freecam.network.ServerPolicies; +import net.xolt.freecam.network.ServerPolicyPayload; + +//? if >=1.21.11 +import net.neoforged.neoforge.client.network.event.RegisterClientPayloadHandlersEvent; + @Mod(value = Freecam.MOD_ID, dist = Dist.CLIENT) @EventBusSubscriber( @@ -43,6 +52,31 @@ public static void registerKeymappings(RegisterKeyMappingsEvent event) { ModBindings.forEach(event::register); } + @SubscribeEvent + public static void registerPayloads(RegisterPayloadHandlersEvent event) { + PayloadRegistrar registrar = event.registrar("1").optional(); + //? if >=1.21.11 { + registrar.playToClient(ServerPolicyPayload.TYPE, ServerPolicyPayload.STREAM_CODEC); + //? } else { + /*registrar.playToClient( + ServerPolicyPayload.TYPE, + ServerPolicyPayload.STREAM_CODEC, + FreecamNeoforge::handleServerPolicy + ); + *///? } + } + + //? if >=1.21.11 { + @SubscribeEvent + public static void registerClientPayloads(RegisterClientPayloadHandlersEvent event) { + event.register(ServerPolicyPayload.TYPE, FreecamNeoforge::handleServerPolicy); + } + //? } + + private static void handleServerPolicy(ServerPolicyPayload payload, IPayloadContext context) { + ServerPolicies.applyJson(payload.json()); + } + //? neoforge: <21 { /*@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) public static class GlobalEventHandler { From 92dc8c4b7310dff66a0ca7c7dfdbef2214e1bdeb Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:50:05 +0100 Subject: [PATCH 12/23] Update GameRendererMixin.java --- .../main/java/net/xolt/freecam/mixins/GameRendererMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java b/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java index 4fc5020ba..0eb2f2c04 100644 --- a/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java +++ b/common/src/main/java/net/xolt/freecam/mixins/GameRendererMixin.java @@ -24,7 +24,7 @@ private void onRenderItemInHand(CallbackInfo ci) { } } - // Disables block outlines when interactions are disabled. + // Disables block outlines when allowInteract is disabled. @Inject(method = "shouldRenderBlockOutline", at = @At("HEAD"), cancellable = true) private void onShouldRenderBlockOutline(CallbackInfoReturnable cir) { if (Freecam.shouldPreventInteractions()) { From 2f2055b4ceb7fc4b8b7a124c99a68fa368842d8b Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:50:39 +0100 Subject: [PATCH 13/23] Update ClientPacketListenerMixin.java --- .../net/xolt/freecam/mixins/ClientPacketListenerMixin.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java b/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java index 705ee669f..b9c714555 100644 --- a/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java +++ b/common/src/main/java/net/xolt/freecam/mixins/ClientPacketListenerMixin.java @@ -24,9 +24,6 @@ private void onPlayerRespawn(CallbackInfo ci) { } } - // Older Minecraft versions expose custom payloads as an identifier plus - // a raw FriendlyByteBuf. Modern versions register a typed payload in the - // loader-specific entrypoint instead. //? if <1.20.5 { /*@Inject(method = "handleCustomPayload", at = @At("HEAD")) private void onCustomPayload(ClientboundCustomPayloadPacket packet, CallbackInfo ci) { From 6f1bb05493e0cba8eeafc5e71eb14a3633b40711 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:51:35 +0100 Subject: [PATCH 14/23] Update ServerPolicyPayload.java --- .../java/net/xolt/freecam/network/ServerPolicyPayload.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java b/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java index 2ec0ec182..6b5a1d36f 100644 --- a/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java +++ b/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java @@ -23,11 +23,6 @@ public ServerPolicyPayload decode(ByteBuf buffer) { @Override public void encode(ByteBuf buffer, ServerPolicyPayload payload) { byte[] bytes = payload.json().getBytes(StandardCharsets.UTF_8); - if (bytes.length > ServerPolicies.MAX_PAYLOAD_BYTES) { - throw new EncoderException( - "Freecam server_config payload exceeds " + ServerPolicies.MAX_PAYLOAD_BYTES + " bytes" - ); - } buffer.writeBytes(bytes); } }; From 05263aed09250bf47866908722013757979b57f5 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:52:35 +0100 Subject: [PATCH 15/23] 1.20.5 and above only --- fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java b/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java index 2a0cd03ff..4685ab46a 100644 --- a/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java +++ b/fabric/src/main/java/net/xolt/freecam/fabric/FreecamFabric.java @@ -11,6 +11,7 @@ public class FreecamFabric implements ClientModInitializer { @Override public void onInitializeClient() { ModConfig.setup(); + //? if >=1.20.5 FabricServerPolicyNetworking.register(); ModBindings.forEach(KeyMappingHelper::registerKeyMapping); ClientTickEvents.START_CLIENT_TICK.register(Freecam::preTick); From 81f00d9dec2d2896cbdd28d88aa5e6fd66f2d0f2 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:04:36 +0100 Subject: [PATCH 16/23] Update ServerPolicyPayload.java --- .../main/java/net/xolt/freecam/network/ServerPolicyPayload.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java b/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java index 6b5a1d36f..3823481ab 100644 --- a/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java +++ b/common/src/main/java/net/xolt/freecam/network/ServerPolicyPayload.java @@ -5,6 +5,7 @@ import io.netty.handler.codec.EncoderException; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +//~ if >=1.21.11 ResourceLocation -> Identifier import net.minecraft.resources.Identifier; import net.xolt.freecam.Freecam; From 02c08187749f31ef94a0e5b02f1601ceb1e00aad Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:05:34 +0100 Subject: [PATCH 17/23] Create ForgeServerPolicyNetworking.java --- .../forge/ForgeServerPolicyNetworking.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java diff --git a/forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java b/forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java new file mode 100644 index 000000000..7558f0eec --- /dev/null +++ b/forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java @@ -0,0 +1,43 @@ +//? if >=1.20.5 { +package net.xolt.freecam.forge; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraftforge.network.ChannelBuilder; +import net.xolt.freecam.Freecam; +import net.xolt.freecam.network.ServerPolicies; +import net.xolt.freecam.network.ServerPolicyPayload; + +import java.nio.charset.StandardCharsets; + +public final class ForgeServerPolicyNetworking { + private static final StreamCodec STREAM_CODEC = new StreamCodec<>() { + @Override + public ServerPolicyPayload decode(RegistryFriendlyByteBuf buffer) { + byte[] bytes = new byte[buffer.readableBytes()]; + buffer.readBytes(bytes); + return new ServerPolicyPayload(new String(bytes, StandardCharsets.UTF_8)); + } + + @Override + public void encode(RegistryFriendlyByteBuf buffer, ServerPolicyPayload payload) { + buffer.writeBytes(payload.json().getBytes(StandardCharsets.UTF_8)); + } + }; + + public static void register() { + ChannelBuilder.named(Freecam.MOD_ID + ":server_policies") + .networkProtocolVersion(1) + .optional() + .payloadChannel() + .play() + .clientbound() + .addMain( + ServerPolicyPayload.TYPE, + STREAM_CODEC, + (payload, context) -> ServerPolicies.applyJson(payload.json()) + ) + .build(); + } +} +//? } From 353020511fc65486e6f85238e014a65861c40bd8 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:06:05 +0100 Subject: [PATCH 18/23] Update FreecamForge.java --- forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java b/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java index 3acea5cb2..e2110c2f2 100644 --- a/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java +++ b/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java @@ -23,6 +23,10 @@ @Mod.EventBusSubscriber(bus = Bus.MOD, value = Dist.CLIENT) @SuppressWarnings("unused") public class FreecamForge { + public FreecamForge() { + //? if >=1.20.5 + ForgeServerPolicyNetworking.register(); + } @SubscribeEvent public static void clientSetup(FMLClientSetupEvent event) { From 46e21a793083e3661c041aa7a7a62c794eddfaf3 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:36:50 +0100 Subject: [PATCH 19/23] Delete forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java --- .../forge/ForgeServerPolicyNetworking.java | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java diff --git a/forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java b/forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java deleted file mode 100644 index 7558f0eec..000000000 --- a/forge/src/main/java/net/xolt/freecam/forge/ForgeServerPolicyNetworking.java +++ /dev/null @@ -1,43 +0,0 @@ -//? if >=1.20.5 { -package net.xolt.freecam.forge; - -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraftforge.network.ChannelBuilder; -import net.xolt.freecam.Freecam; -import net.xolt.freecam.network.ServerPolicies; -import net.xolt.freecam.network.ServerPolicyPayload; - -import java.nio.charset.StandardCharsets; - -public final class ForgeServerPolicyNetworking { - private static final StreamCodec STREAM_CODEC = new StreamCodec<>() { - @Override - public ServerPolicyPayload decode(RegistryFriendlyByteBuf buffer) { - byte[] bytes = new byte[buffer.readableBytes()]; - buffer.readBytes(bytes); - return new ServerPolicyPayload(new String(bytes, StandardCharsets.UTF_8)); - } - - @Override - public void encode(RegistryFriendlyByteBuf buffer, ServerPolicyPayload payload) { - buffer.writeBytes(payload.json().getBytes(StandardCharsets.UTF_8)); - } - }; - - public static void register() { - ChannelBuilder.named(Freecam.MOD_ID + ":server_policies") - .networkProtocolVersion(1) - .optional() - .payloadChannel() - .play() - .clientbound() - .addMain( - ServerPolicyPayload.TYPE, - STREAM_CODEC, - (payload, context) -> ServerPolicies.applyJson(payload.json()) - ) - .build(); - } -} -//? } From d9c1f623d2b6c8cf935456dde4e36105755b6592 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:37:08 +0100 Subject: [PATCH 20/23] Update FreecamNeoforge.java --- .../xolt/freecam/forge/FreecamNeoforge.java | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java b/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java index 9cb4b8b05..59b2fe7f8 100644 --- a/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java +++ b/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java @@ -11,19 +11,10 @@ import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; import net.neoforged.neoforge.client.gui.IConfigScreenFactory; -import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; -import net.neoforged.neoforge.network.handling.IPayloadContext; -import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.xolt.freecam.Freecam; import net.xolt.freecam.config.ModBindings; import net.xolt.freecam.config.ModConfig; import net.xolt.freecam.config.gui.ConfigScreenProvider; -import net.xolt.freecam.network.ServerPolicies; -import net.xolt.freecam.network.ServerPolicyPayload; - -//? if >=1.21.11 -import net.neoforged.neoforge.client.network.event.RegisterClientPayloadHandlersEvent; - @Mod(value = Freecam.MOD_ID, dist = Dist.CLIENT) @EventBusSubscriber( @@ -52,31 +43,6 @@ public static void registerKeymappings(RegisterKeyMappingsEvent event) { ModBindings.forEach(event::register); } - @SubscribeEvent - public static void registerPayloads(RegisterPayloadHandlersEvent event) { - PayloadRegistrar registrar = event.registrar("1").optional(); - //? if >=1.21.11 { - registrar.playToClient(ServerPolicyPayload.TYPE, ServerPolicyPayload.STREAM_CODEC); - //? } else { - /*registrar.playToClient( - ServerPolicyPayload.TYPE, - ServerPolicyPayload.STREAM_CODEC, - FreecamNeoforge::handleServerPolicy - ); - *///? } - } - - //? if >=1.21.11 { - @SubscribeEvent - public static void registerClientPayloads(RegisterClientPayloadHandlersEvent event) { - event.register(ServerPolicyPayload.TYPE, FreecamNeoforge::handleServerPolicy); - } - //? } - - private static void handleServerPolicy(ServerPolicyPayload payload, IPayloadContext context) { - ServerPolicies.applyJson(payload.json()); - } - //? neoforge: <21 { /*@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) public static class GlobalEventHandler { From ed1cbfb3cf36fa1f500cdf2248baf03af201384f Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:37:56 +0100 Subject: [PATCH 21/23] Update FreecamForge.java --- forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java b/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java index e2110c2f2..3acea5cb2 100644 --- a/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java +++ b/forge/src/main/java/net/xolt/freecam/forge/FreecamForge.java @@ -23,10 +23,6 @@ @Mod.EventBusSubscriber(bus = Bus.MOD, value = Dist.CLIENT) @SuppressWarnings("unused") public class FreecamForge { - public FreecamForge() { - //? if >=1.20.5 - ForgeServerPolicyNetworking.register(); - } @SubscribeEvent public static void clientSetup(FMLClientSetupEvent event) { From af49817e19e88e0f815f7d73ff5772227232733e Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Mon, 27 Jul 2026 16:40:31 +0100 Subject: [PATCH 22/23] Update FreecamNeoforge.java --- .../xolt/freecam/forge/FreecamNeoforge.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java b/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java index 59b2fe7f8..9cb4b8b05 100644 --- a/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java +++ b/neoforge/src/main/java/net/xolt/freecam/forge/FreecamNeoforge.java @@ -11,10 +11,19 @@ import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; import net.neoforged.neoforge.client.gui.IConfigScreenFactory; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.xolt.freecam.Freecam; import net.xolt.freecam.config.ModBindings; import net.xolt.freecam.config.ModConfig; import net.xolt.freecam.config.gui.ConfigScreenProvider; +import net.xolt.freecam.network.ServerPolicies; +import net.xolt.freecam.network.ServerPolicyPayload; + +//? if >=1.21.11 +import net.neoforged.neoforge.client.network.event.RegisterClientPayloadHandlersEvent; + @Mod(value = Freecam.MOD_ID, dist = Dist.CLIENT) @EventBusSubscriber( @@ -43,6 +52,31 @@ public static void registerKeymappings(RegisterKeyMappingsEvent event) { ModBindings.forEach(event::register); } + @SubscribeEvent + public static void registerPayloads(RegisterPayloadHandlersEvent event) { + PayloadRegistrar registrar = event.registrar("1").optional(); + //? if >=1.21.11 { + registrar.playToClient(ServerPolicyPayload.TYPE, ServerPolicyPayload.STREAM_CODEC); + //? } else { + /*registrar.playToClient( + ServerPolicyPayload.TYPE, + ServerPolicyPayload.STREAM_CODEC, + FreecamNeoforge::handleServerPolicy + ); + *///? } + } + + //? if >=1.21.11 { + @SubscribeEvent + public static void registerClientPayloads(RegisterClientPayloadHandlersEvent event) { + event.register(ServerPolicyPayload.TYPE, FreecamNeoforge::handleServerPolicy); + } + //? } + + private static void handleServerPolicy(ServerPolicyPayload payload, IPayloadContext context) { + ServerPolicies.applyJson(payload.json()); + } + //? neoforge: <21 { /*@EventBusSubscriber(bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) public static class GlobalEventHandler { From 7a2984f663d1b940a5a982117fb1dee8f9794408 Mon Sep 17 00:00:00 2001 From: personalized-advertising <265311956+personalized-advertising@users.noreply.github.com> Date: Mon, 27 Jul 2026 20:52:21 +0100 Subject: [PATCH 23/23] Update FabricServerPolicyNetworking.java --- .../freecam/fabric/FabricServerPolicyNetworking.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java b/fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java index 2ca3f0e80..9d06405cc 100644 --- a/fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java +++ b/fabric/src/main/java/net/xolt/freecam/fabric/FabricServerPolicyNetworking.java @@ -9,11 +9,18 @@ public final class FabricServerPolicyNetworking { public static void register() { - //~ if >=26.1 playS2C -> clientboundPlay + /*? if >=26.1 {*/ PayloadTypeRegistry.clientboundPlay().register( ServerPolicyPayload.TYPE, ServerPolicyPayload.STREAM_CODEC ); + /*?} else {*/ + /*PayloadTypeRegistry.playS2C().register( + ServerPolicyPayload.TYPE, + ServerPolicyPayload.STREAM_CODEC + );*/ + /*?}*/ + ClientPlayNetworking.registerGlobalReceiver( ServerPolicyPayload.TYPE, (payload, context) -> ServerPolicies.applyJson(payload.json())