From 08cfb355204050089d876227aa88f9d82dbb9adc Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 3 Feb 2021 13:45:52 +0200 Subject: [PATCH] Add an event for when a pony skin's data is resolved for the player. Requested by @DataByte --- build.gradle | 1 + .../api/pony/network/Channel.java | 60 ++++++++++ .../api/pony/network/MsgPonyData.java | 112 ++++++++++++++++++ .../api/pony/network/PonyDataCallback.java | 32 +++++ .../api/pony/network/package-info.java | 4 + .../minelittlepony/client/MineLittlePony.java | 2 + .../com/minelittlepony/client/pony/Pony.java | 22 +++- .../client/pony/PonyManager.java | 4 +- 8 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/minelittlepony/api/pony/network/Channel.java create mode 100644 src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java create mode 100644 src/main/java/com/minelittlepony/api/pony/network/PonyDataCallback.java create mode 100644 src/main/java/com/minelittlepony/api/pony/network/package-info.java diff --git a/build.gradle b/build.gradle index 2ba0d5b5..c7d559df 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,7 @@ dependencies { modApi fabricApi.module("fabric-api-base", project.fabric_version) modApi fabricApi.module("fabric-lifecycle-events-v1", project.fabric_version) modApi fabricApi.module("fabric-resource-loader-v0", project.fabric_version) + modApi fabricApi.module("fabric-networking-v0", project.fabric_version) modApi "com.minelittlepony:Kirin:${project.kirin_version}" include "com.minelittlepony:Kirin:${project.kirin_version}" diff --git a/src/main/java/com/minelittlepony/api/pony/network/Channel.java b/src/main/java/com/minelittlepony/api/pony/network/Channel.java new file mode 100644 index 00000000..f670de46 --- /dev/null +++ b/src/main/java/com/minelittlepony/api/pony/network/Channel.java @@ -0,0 +1,60 @@ +package com.minelittlepony.api.pony.network; + +import io.netty.buffer.Unpooled; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; +import net.fabricmc.fabric.api.network.PacketContext; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; + +import java.util.function.Function; + +public interface Channel { + + @Environment(EnvType.CLIENT) + SPacketType CLIENT_PONY_DATA = clientToServer(new Identifier("minelittlepony", "pony_data"), MsgPonyData::new); + + static void bootstrap() { } + + static SPacketType clientToServer(Identifier id, Function factory) { + ServerSidePacketRegistry.INSTANCE.register(id, (context, buffer) -> factory.apply(buffer).handleOnMain(context)); + return () -> id; + } + + interface SPacketType { + Identifier getId(); + + default void send(T packet) { + if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { + throw new RuntimeException("Client packet send called by the server"); + } + ClientSidePacketRegistry.INSTANCE.sendToServer(getId(), packet.toBuffer()); + } + + default net.minecraft.network.Packet toPacket(T packet) { + if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { + throw new RuntimeException("Client packet send called by the server"); + } + return ClientSidePacketRegistry.INSTANCE.toPacket(getId(), packet.toBuffer()); + } + } + + interface Packet { + void handle(PacketContext context); + + void toBuffer(PacketByteBuf buffer); + + default void handleOnMain(PacketContext context) { + context.getTaskQueue().execute(() -> handle(context)); + } + + default PacketByteBuf toBuffer() { + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + toBuffer(buf); + return buf; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java b/src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java new file mode 100644 index 00000000..17f52337 --- /dev/null +++ b/src/main/java/com/minelittlepony/api/pony/network/MsgPonyData.java @@ -0,0 +1,112 @@ +package com.minelittlepony.api.pony.network; + +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.network.PacketContext; +import net.minecraft.network.PacketByteBuf; + +import com.minelittlepony.api.pony.IPonyData; +import com.minelittlepony.api.pony.meta.Gender; +import com.minelittlepony.api.pony.meta.Race; +import com.minelittlepony.api.pony.meta.Size; +import com.minelittlepony.api.pony.meta.TailLength; +import com.minelittlepony.api.pony.meta.Wearable; +import com.minelittlepony.common.util.animation.Interpolator; + +import java.util.UUID; + +public class MsgPonyData implements Channel.Packet, IPonyData { + + private final Race race; + private final TailLength tailLength; + private final Gender gender; + private final Size size; + private final int glowColor; + private final boolean hasHorn; + private final boolean hasMagic; + + private final boolean noSkin; + + MsgPonyData(PacketByteBuf buffer) { + race = Race.values()[buffer.readInt()]; + tailLength = TailLength.values()[buffer.readInt()]; + gender = Gender.values()[buffer.readInt()]; + size = Size.values()[buffer.readInt()]; + glowColor = buffer.readInt(); + hasHorn = buffer.readBoolean(); + hasMagic = buffer.readBoolean(); + noSkin = buffer.readBoolean(); + } + + public MsgPonyData(IPonyData data, boolean noSkin) { + race = data.getRace(); + tailLength = data.getTail(); + gender = data.getGender(); + size = data.getSize(); + glowColor = data.getGlowColor(); + hasHorn = data.hasHorn(); + hasMagic = data.hasMagic(); + this.noSkin = noSkin; + } + + @Override + public void handle(PacketContext context) { + PonyDataCallback.EVENT.invoker().onPonyDataAvailable(context.getPlayer(), this, noSkin, EnvType.SERVER); + } + + @Override + public void toBuffer(PacketByteBuf buffer) { + buffer.writeInt(race.ordinal()); + buffer.writeInt(tailLength.ordinal()); + buffer.writeInt(gender.ordinal()); + buffer.writeInt(size.ordinal()); + buffer.writeInt(glowColor); + buffer.writeBoolean(hasHorn); + buffer.writeBoolean(hasMagic); + buffer.writeBoolean(noSkin); + } + + @Override + public Race getRace() { + return race; + } + + @Override + public TailLength getTail() { + return tailLength; + } + + @Override + public Gender getGender() { + return gender; + } + + @Override + public Size getSize() { + return size; + } + + @Override + public int getGlowColor() { + return glowColor; + } + + @Override + public boolean hasHorn() { + return hasHorn; + } + + @Override + public boolean hasMagic() { + return hasMagic; + } + + @Override + public boolean isWearing(Wearable wearable) { + return false; + } + + @Override + public Interpolator getInterpolator(UUID interpolatorId) { + return Interpolator.linear(interpolatorId); + } +} diff --git a/src/main/java/com/minelittlepony/api/pony/network/PonyDataCallback.java b/src/main/java/com/minelittlepony/api/pony/network/PonyDataCallback.java new file mode 100644 index 00000000..199cc5ee --- /dev/null +++ b/src/main/java/com/minelittlepony/api/pony/network/PonyDataCallback.java @@ -0,0 +1,32 @@ +package com.minelittlepony.api.pony.network; + +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.player.PlayerEntity; + +import com.minelittlepony.api.pony.IPonyData; +import com.minelittlepony.client.MineLittlePony; + +/** + * Callback triggered on the server when receiving pony data from a client. + * + */ +public interface PonyDataCallback { + + Event EVENT = EventFactory.createArrayBacked(PonyDataCallback.class, listeners -> (sender, data, noSkin, env) -> { + MineLittlePony.logger.info("Got pony data on the " + env + " from " + sender.getName().asString() + " with " + (noSkin ? "un" : "") + "set skin and he is a " + data.getRace() + "!"); + for (PonyDataCallback event : listeners) { + event.onPonyDataAvailable(sender, data, noSkin, env); + } + }); + + /** + * Called when pony data is received. + * @param sender The player who sent the data - this is the owner of the skin/pony data. + * @param data The skin/pony data + * @param noSkin Whether the data is for a player with a default/unset custom skin. + * @param env The environment. Whether this call is coming from the client or server. Clients may get two calls, one for both. + */ + void onPonyDataAvailable(PlayerEntity sender, IPonyData data, boolean noSkin, EnvType env); +} diff --git a/src/main/java/com/minelittlepony/api/pony/network/package-info.java b/src/main/java/com/minelittlepony/api/pony/network/package-info.java new file mode 100644 index 00000000..452cf392 --- /dev/null +++ b/src/main/java/com/minelittlepony/api/pony/network/package-info.java @@ -0,0 +1,4 @@ +@ParametersAreNonnullByDefault +package com.minelittlepony.api.pony.network; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/minelittlepony/client/MineLittlePony.java b/src/main/java/com/minelittlepony/client/MineLittlePony.java index a8360af9..8bda02ae 100644 --- a/src/main/java/com/minelittlepony/client/MineLittlePony.java +++ b/src/main/java/com/minelittlepony/client/MineLittlePony.java @@ -1,6 +1,7 @@ package com.minelittlepony.client; import com.minelittlepony.api.pony.IPonyManager; +import com.minelittlepony.api.pony.network.Channel; import com.minelittlepony.client.model.ModelType; import com.minelittlepony.client.pony.PonyManager; import com.minelittlepony.client.render.PonyRenderDispatcher; @@ -85,6 +86,7 @@ public class MineLittlePony implements ClientModInitializer { config.load(); + Channel.bootstrap(); ModelType.bootstrap(); FabricLoader.getInstance().getEntrypoints("minelittlepony", ClientModInitializer.class).forEach(ClientModInitializer::onInitializeClient); diff --git a/src/main/java/com/minelittlepony/client/pony/Pony.java b/src/main/java/com/minelittlepony/client/pony/Pony.java index 8aaa0202..32cd8ce2 100644 --- a/src/main/java/com/minelittlepony/client/pony/Pony.java +++ b/src/main/java/com/minelittlepony/client/pony/Pony.java @@ -5,10 +5,14 @@ import com.minelittlepony.api.pony.IPony; import com.minelittlepony.api.pony.IPonyData; import com.minelittlepony.api.pony.meta.Race; import com.minelittlepony.api.pony.meta.Size; +import com.minelittlepony.api.pony.network.Channel; +import com.minelittlepony.api.pony.network.MsgPonyData; +import com.minelittlepony.api.pony.network.PonyDataCallback; import com.minelittlepony.client.render.IPonyRenderContext; import com.minelittlepony.client.render.PonyRenderDispatcher; import com.minelittlepony.client.transform.PonyTransformation; +import net.fabricmc.api.EnvType; import net.minecraft.block.BlockState; import net.minecraft.block.Material; import net.minecraft.block.StairsBlock; @@ -31,6 +35,9 @@ public class Pony implements IPony { private final IPonyData metadata; private boolean initialized = false; + private boolean defaulted = false; + + private int entityId = -1; Pony(Identifier resource, IPonyData data) { texture = resource; @@ -41,11 +48,24 @@ public class Pony implements IPony { this(resource, PonyData.parse(resource)); } + public IPony defaulted() { + defaulted = true; + return this; + } + @Override public void updateForEntity(Entity entity) { - if (!initialized) { + if (!initialized || entityId != entity.getEntityId()) { + entityId = entity.getEntityId(); initialized = true; entity.calculateDimensions(); + + if (entity == MinecraftClient.getInstance().player) { + Channel.CLIENT_PONY_DATA.send(new MsgPonyData(metadata, defaulted)); + } + if (entity instanceof PlayerEntity) { + PonyDataCallback.EVENT.invoker().onPonyDataAvailable((PlayerEntity)entity, metadata, defaulted, EnvType.CLIENT); + } } } diff --git a/src/main/java/com/minelittlepony/client/pony/PonyManager.java b/src/main/java/com/minelittlepony/client/pony/PonyManager.java index 5110d2da..a9b43f0d 100644 --- a/src/main/java/com/minelittlepony/client/pony/PonyManager.java +++ b/src/main/java/com/minelittlepony/client/pony/PonyManager.java @@ -92,7 +92,7 @@ public class PonyManager implements IPonyManager, IdentifiableResourceReloadList @Override public IPony getDefaultPony(UUID uuid) { if (config.ponyLevel.get() != PonyLevel.PONIES) { - return getPony(DefaultSkinHelper.getTexture(uuid)); + return ((Pony)getPony(DefaultSkinHelper.getTexture(uuid))).defaulted(); } return getBackgroundPony(uuid); @@ -100,7 +100,7 @@ public class PonyManager implements IPonyManager, IdentifiableResourceReloadList @Override public IPony getBackgroundPony(UUID uuid) { - return getPony(backgroundPonyList.getId(uuid)); + return ((Pony)getPony(backgroundPonyList.getId(uuid))).defaulted(); } @Override