diff --git a/src/main/java/com/minelittlepony/api/pony/meta/Flags.java b/src/main/java/com/minelittlepony/api/pony/meta/Flags.java index 9d69d1d0..8905d17e 100644 --- a/src/main/java/com/minelittlepony/api/pony/meta/Flags.java +++ b/src/main/java/com/minelittlepony/api/pony/meta/Flags.java @@ -27,7 +27,7 @@ public record Flags & TValue> ( for (int i = 0; i < length; i++) { values.add(all[buffer.readInt()]); } - return new Flags<>(def, values, buffer.readInt()); + return of(def, buffer.readInt(), values); } public void write(PacketByteBuf buffer) { diff --git a/src/main/java/com/minelittlepony/client/PonyDataLoader.java b/src/main/java/com/minelittlepony/client/PonyDataLoader.java index a02e9176..e8737017 100644 --- a/src/main/java/com/minelittlepony/client/PonyDataLoader.java +++ b/src/main/java/com/minelittlepony/client/PonyDataLoader.java @@ -15,8 +15,8 @@ import java.util.function.Supplier; import org.jetbrains.annotations.Nullable; -class PonyDataLoader { - static final Supplier> NULL = loaded(PonyData.NULL); +public class PonyDataLoader { + public static final Supplier> NULL = loaded(PonyData.NULL); private static final ResourceMetadataReader SERIALIZER = new ResourceMetadataReader() { private static final Gson GSON = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() diff --git a/src/main/java/com/minelittlepony/client/PonyManagerImpl.java b/src/main/java/com/minelittlepony/client/PonyManagerImpl.java index 538e9ab4..de03197c 100644 --- a/src/main/java/com/minelittlepony/client/PonyManagerImpl.java +++ b/src/main/java/com/minelittlepony/client/PonyManagerImpl.java @@ -15,12 +15,12 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.util.DefaultSkinHelper; import net.minecraft.resource.ResourceManager; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.Identifier; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -29,22 +29,21 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe private final PonyConfig config; - private final LoadingCache defaultedPoniesCache = CacheBuilder.newBuilder() + private final LoadingCache poniesCache = CacheBuilder.newBuilder() .expireAfterAccess(30, TimeUnit.SECONDS) - .build(CacheLoader.from(resource -> new Pony(resource, PonyDataLoader.parse(resource, true)))); + .build(CacheLoader.from(key -> new Pony(key.texture(), PonyDataLoader.parse(key.texture(), key.defaulted())))); + private final WeakHashMap playerPonies = new WeakHashMap<>(); - private final LoadingCache poniesCache = CacheBuilder.newBuilder() - .expireAfterAccess(30, TimeUnit.SECONDS) - .build(CacheLoader.from(resource -> new Pony(resource, PonyDataLoader.parse(resource, false)))); + record Key(Identifier texture, @Nullable UUID uuid, boolean defaulted) {} public PonyManagerImpl(PonyConfig config) { this.config = config; Instance.instance = this; } - private Pony loadPony(Identifier resource, boolean defaulted) { + private Pony loadPony(Identifier resource, @Nullable UUID uuid, boolean defaulted) { try { - return (defaulted ? defaultedPoniesCache : poniesCache).get(resource); + return poniesCache.get(new Key(resource, uuid, defaulted)); } catch (ExecutionException e) { return new Pony(resource, PonyDataLoader.NULL); } @@ -52,13 +51,26 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe @Override public Pony getPony(PlayerEntity player) { - final UUID id = player instanceof ForcedPony ? null : player.getGameProfile() == null ? player.getUuid() : player.getGameProfile().getId(); + final UUID id = player instanceof ForcedPony ? null : player.getGameProfile() == null || player.getGameProfile().getId() == null ? player.getUuid() : player.getGameProfile().getId(); + + Pony pony; + if (player instanceof ServerPlayerEntity && id != null) { + pony = playerPonies.get(id); + if (pony != null) { + return pony; + } + } + @Nullable Identifier skin = getSkin(player); if (skin != null) { skin = MoreObjects.firstNonNull(PonySkinResolver.EVENT.invoker().onPonySkinResolving(player, s -> getPony(s, id), skin), skin); } - return getPony(skin, id); + pony = getPony(skin, id); + if (!(player instanceof ServerPlayerEntity) && id != null) { + playerPonies.put(id, pony); + } + return pony; } @Override @@ -77,10 +89,10 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe @Override public Pony getPony(@Nullable Identifier resource, @Nullable UUID uuid) { if (resource == null) { - return uuid == null ? loadPony(DefaultSkinHelper.getTexture(), true) : getBackgroundPony(uuid); + return uuid == null ? loadPony(DefaultSkinHelper.getTexture(), uuid, true) : getBackgroundPony(uuid); } - Pony pony = loadPony(resource, false); + Pony pony = loadPony(resource, uuid, false); if (uuid != null && PonyConfig.getInstance().ponyLevel.get() == PonyLevel.PONIES && pony.metadata().race().isHuman()) { return getBackgroundPony(uuid); @@ -91,9 +103,9 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe @Override public Pony getBackgroundPony(@Nullable UUID uuid) { if (config.ponyLevel.get() == PonyLevel.PONIES) { - return loadPony(MineLittlePony.getInstance().getVariatedTextures().get(VariatedTextureSupplier.BACKGROUND_PONIES_POOL, uuid).orElse(DefaultSkinHelper.getSkinTextures(uuid).texture()), true); + return loadPony(MineLittlePony.getInstance().getVariatedTextures().get(VariatedTextureSupplier.BACKGROUND_PONIES_POOL, uuid).orElse(DefaultSkinHelper.getSkinTextures(uuid).texture()), uuid, true); } - return loadPony(DefaultSkinHelper.getSkinTextures(uuid).texture(), true); + return loadPony(DefaultSkinHelper.getSkinTextures(uuid).texture(), uuid, true); } @Nullable @@ -113,13 +125,11 @@ public class PonyManagerImpl implements PonyManager, SimpleSynchronousResourceRe public void removePony(Identifier resource) { poniesCache.invalidate(resource); - defaultedPoniesCache.invalidate(resource); } public void clearCache() { - MineLittlePony.logger.info("Flushed {} cached ponies.", poniesCache.size()); + MineLittlePony.logger.info("Turned {} cached ponies into cupcakes.", poniesCache.size()); poniesCache.invalidateAll(); - defaultedPoniesCache.invalidateAll(); } @Override diff --git a/src/main/java/com/minelittlepony/client/mixin/MixinClientPlayerEntity.java b/src/main/java/com/minelittlepony/client/mixin/MixinClientPlayerEntity.java deleted file mode 100644 index 024ff010..00000000 --- a/src/main/java/com/minelittlepony/client/mixin/MixinClientPlayerEntity.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.minelittlepony.client.mixin; - -import com.minelittlepony.client.render.EquineRenderManager; - -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.network.ClientPlayerEntity; -import org.spongepowered.asm.mixin.Mixin; - -@Mixin(ClientPlayerEntity.class) -abstract class MixinClientPlayerEntity extends AbstractClientPlayerEntity implements EquineRenderManager.RegistrationHandler { - public MixinClientPlayerEntity() { super(null, null); } - - private final EquineRenderManager.SyncedPony syncedPony = new EquineRenderManager.SyncedPony(); - - @Override - public EquineRenderManager.SyncedPony getSyncedPony() { - return syncedPony; - } -} diff --git a/src/main/java/com/minelittlepony/client/mixin/MixinPlayerEntity.java b/src/main/java/com/minelittlepony/client/mixin/MixinPlayerEntity.java index e2731350..5bc60a6a 100644 --- a/src/main/java/com/minelittlepony/client/mixin/MixinPlayerEntity.java +++ b/src/main/java/com/minelittlepony/client/mixin/MixinPlayerEntity.java @@ -6,22 +6,35 @@ import net.minecraft.entity.player.PlayerEntity; import org.spongepowered.asm.mixin.Mixin; 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 com.minelittlepony.api.pony.Pony; +import com.minelittlepony.client.render.EquineRenderManager.RegistrationHandler; +import com.minelittlepony.client.render.EquineRenderManager.SyncedPony; @Mixin(PlayerEntity.class) -abstract class MixinPlayerEntity { +abstract class MixinPlayerEntity extends LivingEntity implements RegistrationHandler { + MixinPlayerEntity() { super(null, null); } + + private final SyncedPony syncedPony = new SyncedPony(); + + @Override + public SyncedPony getSyncedPony() { + return syncedPony; + } + @Inject(method = "getBaseDimensions", at = @At("RETURN"), cancellable = true) private void onGetBaseDimensions(EntityPose pose, CallbackInfoReturnable info) { - Pony pony = Pony.getManager().getPony((PlayerEntity)(Object)this); + float factor = syncedPony.getCachedPonyData().size().eyeHeightFactor(); - if (!pony.race().isHuman()) { - float factor = pony.size().eyeHeightFactor(); - if (factor != 1) { - EntityDimensions dimensions = info.getReturnValue(); - info.setReturnValue(dimensions.withEyeHeight(dimensions.eyeHeight() * factor)); - } + if (factor != 1) { + EntityDimensions dimensions = info.getReturnValue(); + info.setReturnValue(dimensions.withEyeHeight(dimensions.eyeHeight() * factor)); } } + + @Inject(method = "tick()V", at = @At("TAIL")) + private void onTick(CallbackInfo info) { + syncedPony.synchronize((PlayerEntity)(Object)this); + } } diff --git a/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java b/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java index 9d1f6f48..fe7f54e7 100644 --- a/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java +++ b/src/main/java/com/minelittlepony/client/render/EquineRenderManager.java @@ -5,13 +5,16 @@ import com.minelittlepony.api.events.Channel; import com.minelittlepony.api.events.PonyDataCallback; import com.minelittlepony.api.model.*; import com.minelittlepony.api.pony.Pony; +import com.minelittlepony.api.pony.PonyData; +import com.minelittlepony.client.PonyDataLoader; import com.minelittlepony.client.transform.PonyPosture; import com.minelittlepony.mson.api.ModelKey; import com.minelittlepony.util.MathUtil; import com.mojang.blaze3d.systems.RenderSystem; -import java.util.Objects; +import java.util.*; import java.util.function.Function; +import java.util.function.Supplier; import net.fabricmc.api.EnvType; import net.minecraft.client.MinecraftClient; @@ -78,10 +81,6 @@ public class EquineRenderManager> lastPonyData = PonyDataLoader.NULL; @Nullable private Pony lastTransmittedPony; - public void synchronize(PlayerEntity player, Pony pony) { + public Pony getCachedPony() { + return lastRenderedPony; + } + + public PonyData getCachedPonyData() { + return lastPonyData.get().orElse(PonyData.NULL); + } + + public void synchronize(PlayerEntity player) { + Pony pony = Pony.getManager().getPony(player); boolean changed = pony.compareTo(lastRenderedPony) != 0; if (changed) { lastRenderedPony = pony; + lastPonyData = pony.metadataGetter(); player.calculateDimensions(); } diff --git a/src/main/java/com/minelittlepony/client/render/MobRenderers.java b/src/main/java/com/minelittlepony/client/render/MobRenderers.java index d37db2d7..d18553fe 100644 --- a/src/main/java/com/minelittlepony/client/render/MobRenderers.java +++ b/src/main/java/com/minelittlepony/client/render/MobRenderers.java @@ -15,7 +15,7 @@ import net.minecraft.entity.EntityType; /** * Central location where new entity renderers are registered and applied. */ -public final class MobRenderers { +public class MobRenderers { public static final Map REGISTRY = new HashMap<>(); public static final MobRenderers VILLAGER = register("villagers", (state, pony) -> { diff --git a/src/main/resources/minelp.mixin.json b/src/main/resources/minelp.mixin.json index 5c32b7be..efeb588d 100644 --- a/src/main/resources/minelp.mixin.json +++ b/src/main/resources/minelp.mixin.json @@ -11,7 +11,6 @@ "MixinEntityRenderers", "MixinSkullBlockEntityRenderer", "MixinHeldItemRenderer", - "MixinClientPlayerEntity", "MixinPlayerEntity", "MixinPlayerMoveC2SPacket", "MixinPlayerPositionLookS2CPacket",