diff --git a/src/main/java/com/minelittlepony/api/pony/IPony.java b/src/main/java/com/minelittlepony/api/pony/IPony.java index 1f7dcbde..e5878d08 100644 --- a/src/main/java/com/minelittlepony/api/pony/IPony.java +++ b/src/main/java/com/minelittlepony/api/pony/IPony.java @@ -36,6 +36,11 @@ public interface IPony { */ boolean isPerformingRainboom(LivingEntity entity); + /** + * Returns whether this is one of the default ponies assigned to a player without a custom skin. + */ + boolean isDefault(); + /** * Unlike sneaking, crouching is a more specific animation parameter that controls whether the player is visible * nose to the ground, crouching the sand. diff --git a/src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java b/src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java index a8b89e11..2e81fc18 100644 --- a/src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java +++ b/src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java @@ -73,7 +73,7 @@ public class MsgPonyData implements IPonyData { this.noSkin = noSkin; } - public void toBuffer(PacketByteBuf buffer) { + public PacketByteBuf toBuffer(PacketByteBuf buffer) { buffer.writeInt(race.ordinal()); buffer.writeInt(tailLength.ordinal()); buffer.writeInt(gender.ordinal()); @@ -89,6 +89,7 @@ public class MsgPonyData implements IPonyData { buffer.writeInt(gear[i].ordinal()); } buffer.writeInt(wearableColor); + return buffer; } public boolean isNoSkin() { diff --git a/src/main/java/com/minelittlepony/api/pony/network/fabric/Channel.java b/src/main/java/com/minelittlepony/api/pony/network/fabric/Channel.java index d67c4af4..44c27dc5 100644 --- a/src/main/java/com/minelittlepony/api/pony/network/fabric/Channel.java +++ b/src/main/java/com/minelittlepony/api/pony/network/fabric/Channel.java @@ -1,51 +1,70 @@ package com.minelittlepony.api.pony.network.fabric; -import io.netty.buffer.Unpooled; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.PacketByteBuf; +import net.minecraft.client.MinecraftClient; import net.minecraft.util.Identifier; +import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.network.MsgPonyData; - -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; +import com.minelittlepony.client.MineLittlePony; @Environment(EnvType.CLIENT) -public interface Channel { - Consumer CLIENT_PONY_DATA = clientToServer( - new Identifier("minelittlepony", "pony_data"), - MsgPonyData::new, - MsgPonyData::toBuffer, - (packet, player) -> { - PonyDataCallback.EVENT.invoker().onPonyDataAvailable(player, packet, packet.isNoSkin(), EnvType.SERVER); - }); +public class Channel { + private static final Identifier CLIENT_PONY_DATA = new Identifier("minelittlepony", "pony_data"); + private static final Identifier REQUEST_PONY_DATA = new Identifier("minelittlepony", "request_pony_data"); - static void bootstrap() { } + private static boolean registered; - static Consumer clientToServer(Identifier id, Function factory, - BiConsumer bufferWriter, - BiConsumer handler) { - ServerPlayNetworking.registerGlobalReceiver(id, (server, player, hhandler, buffer, responseSender) -> { - T packet = factory.apply(buffer); + public static void bootstrap() { + ClientLoginConnectionEvents.INIT.register((handler, client) -> { + registered = false; + MineLittlePony.logger.info("Resetting registered flag"); + }); + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + MineLittlePony.logger.info("Sending consent packet to " + handler.getPlayer().getName().getString()); + + sender.sendPacket(REQUEST_PONY_DATA, PacketByteBufs.empty()); + }); + + ClientPlayNetworking.registerGlobalReceiver(REQUEST_PONY_DATA, (client, handler, ignored, sender) -> { + if (client.player != null) { + IPony pony = MineLittlePony.getInstance().getManager().getPony(client.player); + registered = true; + MineLittlePony.logger.info("Server has just consented"); + + sender.sendPacket(CLIENT_PONY_DATA, new MsgPonyData(pony.getMetadata(), pony.isDefault()).toBuffer(PacketByteBufs.create())); + } + }); + ServerPlayNetworking.registerGlobalReceiver(CLIENT_PONY_DATA, (server, player, ignore, buffer, ignore2) -> { + MsgPonyData packet = new MsgPonyData(buffer); server.execute(() -> { - handler.accept(packet, player); + PonyDataCallback.EVENT.invoker().onPonyDataAvailable(player, packet, packet.isNoSkin(), EnvType.SERVER); }); }); - return packet -> { - if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { - throw new RuntimeException("Client packet send called by the server"); + } + + public static void broadcastPonyData(MsgPonyData packet) { + if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { + throw new RuntimeException("Client packet send called by the server"); + } + + if (MineLittlePony.getInstance().getConfig().passiveNetworking.get() + && !registered) { + if (MinecraftClient.getInstance().isInSingleplayer() || MinecraftClient.getInstance().isIntegratedServerRunning()) { + MineLittlePony.logger.info("Sending pony skin data over as we are either in single-player or lan"); + } else { + MineLittlePony.logger.info("Skipping network packet as the server has not consented"); + return; } + } - PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); - bufferWriter.accept(packet, buf); - - ClientPlayNetworking.send(id, buf); - }; + ClientPlayNetworking.send(CLIENT_PONY_DATA, packet.toBuffer(PacketByteBufs.create())); } } \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/client/pony/Pony.java b/src/main/java/com/minelittlepony/client/pony/Pony.java index 96353240..6c699139 100644 --- a/src/main/java/com/minelittlepony/client/pony/Pony.java +++ b/src/main/java/com/minelittlepony/client/pony/Pony.java @@ -55,6 +55,11 @@ public class Pony implements IPony { return this; } + @Override + public boolean isDefault() { + return defaulted; + } + @Override public void updateForEntity(Entity entity) { if (entity instanceof RegistrationHandler && ((RegistrationHandler)entity).shouldUpdateRegistration(this)) { @@ -63,7 +68,7 @@ public class Pony implements IPony { PlayerEntity clientPlayer = MinecraftClient.getInstance().player; if (clientPlayer != null) { if (Objects.equals(entity, clientPlayer) || Objects.equals(((PlayerEntity)entity).getGameProfile(), clientPlayer.getGameProfile())) { - Channel.CLIENT_PONY_DATA.accept(new MsgPonyData(metadata, defaulted)); + Channel.broadcastPonyData(new MsgPonyData(metadata, defaulted)); } } PonyDataCallback.EVENT.invoker().onPonyDataAvailable((PlayerEntity)entity, metadata, defaulted, EnvType.CLIENT); diff --git a/src/main/java/com/minelittlepony/settings/PonyConfig.java b/src/main/java/com/minelittlepony/settings/PonyConfig.java index 9d3882d9..68d64c67 100644 --- a/src/main/java/com/minelittlepony/settings/PonyConfig.java +++ b/src/main/java/com/minelittlepony/settings/PonyConfig.java @@ -27,6 +27,11 @@ public class PonyConfig extends JsonConfig { public final Setting ponyskulls = value("settings", "ponyskulls", true); public final Setting frustrum = value("settings", "frustrum", true); + /** + * Temporary flag to enable post-1.18 networking behaviour. + */ + public final Setting passiveNetworking = value("settings", "passiveNetworking", false); + /** * Debug override for pony sizes. */ diff --git a/src/main/resources/assets/minelittlepony/lang/en_us.json b/src/main/resources/assets/minelittlepony/lang/en_us.json index b61f1038..04ecb9f0 100644 --- a/src/main/resources/assets/minelittlepony/lang/en_us.json +++ b/src/main/resources/assets/minelittlepony/lang/en_us.json @@ -20,6 +20,7 @@ "minelp.options.tpsmagic": "Magic in third-person", "minelp.options.ponyskulls": "Pony Skulls", "minelp.options.frustrum": "Frustum checks", + "minelp.options.passivenetworking": "Passive Networking [Beta]", "minelp.options.button": "Display On Title Screen", "minelp.options.button.on": "Always Display\n\nBoth the pony button and HD Skins button are visible (if installed)", "minelp.options.button.auto": "Display only when HD Skins is not installed",