Add an event for when a pony skin's data is resolved for the player. Requested by @DataByte

This commit is contained in:
Sollace 2021-02-03 13:45:52 +02:00
parent d357f46068
commit 08cfb35520
8 changed files with 234 additions and 3 deletions

View file

@ -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}"

View file

@ -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<MsgPonyData> CLIENT_PONY_DATA = clientToServer(new Identifier("minelittlepony", "pony_data"), MsgPonyData::new);
static void bootstrap() { }
static <T extends Packet> SPacketType<T> clientToServer(Identifier id, Function<PacketByteBuf, T> factory) {
ServerSidePacketRegistry.INSTANCE.register(id, (context, buffer) -> factory.apply(buffer).handleOnMain(context));
return () -> id;
}
interface SPacketType<T extends Packet> {
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;
}
}
}

View file

@ -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);
}
}

View file

@ -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<PonyDataCallback> 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);
}

View file

@ -0,0 +1,4 @@
@ParametersAreNonnullByDefault
package com.minelittlepony.api.pony.network;
import javax.annotation.ParametersAreNonnullByDefault;

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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