diff --git a/build.gradle b/build.gradle index 553ed649..754fdb46 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,14 @@ repositories { name = 'minelp-release' url = 'https://repo.minelittlepony-mod.com/maven/release' } + maven { + name = "TerraformersMC" + url = "https://maven.terraformersmc.com/" + } + maven { + name = "Ladysnake Libs" + url = "https://ladysnake.jfrog.io/artifactory/mods" + } } dependencies { @@ -55,6 +63,8 @@ dependencies { modCompileOnly("com.terraformersmc:modmenu:${project.modmenu_version}") // implementation 'org.jetbrains:intellij-fernflower:1.2.1.16' modCompileOnly("net.caffienemc.sodium:sodium-fabric-mc1.19.2:0.4.4+build.18") + + modCompileOnly "dev.emi:trinkets:3.4.0" } processResources { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java index 32bba993..1eb00244 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java @@ -10,7 +10,7 @@ import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.ability.data.tree.TreeType; import com.minelittlepony.unicopia.block.data.BlockDestructionManager; -import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.ParticleUtils; @@ -54,7 +54,7 @@ public class EarthPonyKickAbility implements Ability { @Override public double getCostEstimate(Pony player) { - double distance = MineLPConnector.getPlayerPonyRace(player.getMaster()).isDefault() ? 6 : -6; + double distance = MineLPDelegate.getInstance().getPlayerPonyRace(player.getMaster()).isDefault() ? 6 : -6; return RayTraceHelper.doTrace(player.getMaster(), distance, 1) .getBlockPos() @@ -65,7 +65,7 @@ public class EarthPonyKickAbility implements Ability { @Nullable @Override public Pos tryActivate(Pony player) { - double distance = MineLPConnector.getPlayerPonyRace(player.getMaster()).isDefault() ? 6 : -6; + double distance = MineLPDelegate.getInstance().getPlayerPonyRace(player.getMaster()).isDefault() ? 6 : -6; return RayTraceHelper.doTrace(player.getMaster(), distance, 1) .getBlockPos() @@ -76,7 +76,7 @@ public class EarthPonyKickAbility implements Ability { private Pos getDefaultKickLocation(Pony player) { Vec3d kickVector = player.getMaster().getRotationVector().multiply(1, 0, 1); - if (!MineLPConnector.getPlayerPonyRace(player.getMaster()).isDefault()) { + if (!MineLPDelegate.getInstance().getPlayerPonyRace(player.getMaster()).isDefault()) { kickVector = kickVector.rotateY((float)Math.PI); } return new Pos(new BlockPos(player.getOriginVector().add(kickVector))); diff --git a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java index 6dc0e1e9..f83a4c9a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java +++ b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java @@ -11,7 +11,7 @@ import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.client.gui.LanSettingsScreen; import com.minelittlepony.unicopia.client.gui.UHud; import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookScreen; -import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.container.*; import com.minelittlepony.unicopia.entity.player.PlayerCamera; import com.minelittlepony.unicopia.entity.player.Pony; @@ -41,7 +41,7 @@ public class UnicopiaClient implements ClientModInitializer { public static Race getPreferredRace() { if (!Unicopia.getConfig().ignoreMineLP.get() && MinecraftClient.getInstance().player != null) { - Race race = MineLPConnector.getPlayerPonyRace(); + Race race = MineLPDelegate.getInstance().getPlayerPonyRace(); if (!race.isDefault()) { return race; diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java b/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java index 3193780f..8a0ccd25 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/SettingsScreen.java @@ -7,7 +7,7 @@ import com.minelittlepony.common.client.gui.ScrollContainer; import com.minelittlepony.common.client.gui.element.*; import com.minelittlepony.common.client.gui.style.Style; import com.minelittlepony.unicopia.*; -import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.util.RegistryIndexer; import net.fabricmc.loader.api.FabricLoader; @@ -97,7 +97,7 @@ public class SettingsScreen extends GameGui { return Text.translatable("unicopia.options.ignore_mine_lp.undetected").formatted(Formatting.DARK_GREEN); } - return Text.translatable("unicopia.options.ignore_mine_lp.detected", MineLPConnector.getPlayerPonyRace().getDisplayName()).formatted(Formatting.GREEN); + return Text.translatable("unicopia.options.ignore_mine_lp.detected", MineLPDelegate.getInstance().getPlayerPonyRace().getDisplayName()).formatted(Formatting.GREEN); } return Text.translatable("unicopia.options.ignore_mine_lp.missing").formatted(Formatting.RED); diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java index e90c7672..9244e02e 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java @@ -1,26 +1,33 @@ package com.minelittlepony.unicopia.client.minelittlepony; +import java.util.Optional; + import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.fabric.PonyModelPrepareCallback; import com.minelittlepony.api.model.gear.IGear; -import com.minelittlepony.unicopia.Owned; -import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.client.MineLittlePony; +import com.minelittlepony.client.render.LevitatingItemRenderer; +import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.util.AnimationUtil; import net.fabricmc.api.ClientModInitializer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; -public class Main implements ClientModInitializer { +public class Main extends MineLPDelegate implements ClientModInitializer { private boolean hookErroring; @Override public void onInitializeClient() { + INSTANCE = this; PonyModelPrepareCallback.EVENT.register(this::onPonyModelPrepared); IGear.register(BangleGear::new); IGear.register(AmuletGear::new); @@ -52,4 +59,39 @@ public class Main implements ClientModInitializer { hookErroring = true; } } + + + @Override + public Race getPlayerPonyRace(PlayerEntity player) { + switch (MineLittlePony.getInstance().getManager().getPony(player).getRace(false)) { + case ALICORN: + return Race.ALICORN; + case CHANGELING: + case CHANGEDLING: + return Race.CHANGELING; + case ZEBRA: + case EARTH: + return Race.EARTH; + case GRYPHON: + case HIPPOGRIFF: + case PEGASUS: + return Race.PEGASUS; + case BATPONY: + return Race.BAT; + case SEAPONY: + case UNICORN: + return Race.UNICORN; + default: + return Race.HUMAN; + } + } + + @Override + public Optional getItemBuffer(VertexConsumerProvider vertexConsumers, Identifier texture) { + if (LevitatingItemRenderer.isEnabled()) { + return Optional.of(vertexConsumers.getBuffer(LevitatingItemRenderer.getRenderLayer(texture))); + } + + return Optional.empty(); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/MineLPConnector.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/MineLPConnector.java deleted file mode 100644 index 436879e2..00000000 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/MineLPConnector.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.minelittlepony.unicopia.client.minelittlepony; - -import java.util.Optional; - -import com.minelittlepony.client.MineLittlePony; -import com.minelittlepony.client.render.LevitatingItemRenderer; -import com.minelittlepony.unicopia.Race; - -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.render.VertexConsumer; -import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.util.Identifier; - -public final class MineLPConnector { - public static Race getPlayerPonyRace() { - return getPlayerPonyRace(MinecraftClient.getInstance().player); - } - - public static Race getPlayerPonyRace(PlayerEntity player) { - if (!FabricLoader.getInstance().isModLoaded("minelp") || player == null) { - return Race.HUMAN; - } - - switch (MineLittlePony.getInstance().getManager().getPony(player).getRace(false)) { - case ALICORN: - return Race.ALICORN; - case CHANGELING: - case CHANGEDLING: - return Race.CHANGELING; - case ZEBRA: - case EARTH: - return Race.EARTH; - case GRYPHON: - case HIPPOGRIFF: - case PEGASUS: - return Race.PEGASUS; - case BATPONY: - return Race.BAT; - case SEAPONY: - case UNICORN: - return Race.UNICORN; - default: - return Race.HUMAN; - } - } - - public static Optional getItemBuffer(VertexConsumerProvider vertexConsumers, Identifier texture) { - if (!FabricLoader.getInstance().isModLoaded("minelp")) { - return Optional.empty(); - } - - if (LevitatingItemRenderer.isEnabled()) { - return Optional.of(vertexConsumers.getBuffer(LevitatingItemRenderer.getRenderLayer(texture))); - } - - return Optional.empty(); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/MineLPDelegate.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/MineLPDelegate.java new file mode 100644 index 00000000..719e4455 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/MineLPDelegate.java @@ -0,0 +1,31 @@ +package com.minelittlepony.unicopia.client.minelittlepony; + +import java.util.Optional; + +import com.minelittlepony.unicopia.Race; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.Identifier; + +public class MineLPDelegate { + static MineLPDelegate INSTANCE = new MineLPDelegate(); + + public static MineLPDelegate getInstance() { + return INSTANCE; + } + + public final Race getPlayerPonyRace() { + return getPlayerPonyRace(MinecraftClient.getInstance().player); + } + + public Race getPlayerPonyRace(PlayerEntity player) { + return Race.HUMAN; + } + + public Optional getItemBuffer(VertexConsumerProvider vertexConsumers, Identifier texture) { + return Optional.empty(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java index 5c9537e5..b504b087 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/AmuletFeatureRenderer.java @@ -21,7 +21,6 @@ import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.Identifier; @@ -43,9 +42,9 @@ public class AmuletFeatureRenderer implements AccessoryF @Override public void render(MatrixStack matrices, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { - ItemStack stack = entity.getEquippedStack(EquipmentSlot.CHEST); + ItemStack stack = AmuletItem.getForEntity(entity); - if (stack.getItem() instanceof AmuletItem) { + if (!stack.isEmpty()) { Identifier texture = textures.computeIfAbsent(Registry.ITEM.getId(stack.getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(texture), false, false); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java index 91441ce5..3fc7da6f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java @@ -2,9 +2,9 @@ package com.minelittlepony.unicopia.client.render; import com.minelittlepony.common.util.Color; import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; -import com.minelittlepony.unicopia.item.FriendshipBraceletItem; -import com.minelittlepony.unicopia.item.GlowableItem; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; +import com.minelittlepony.unicopia.item.*; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import net.minecraft.client.model.Dilation; import net.minecraft.client.model.Model; @@ -24,13 +24,11 @@ import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.model.EntityModelPartNames; import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.item.DyeableItem; import net.minecraft.item.ItemStack; -import net.minecraft.util.Arm; -import net.minecraft.util.Identifier; +import net.minecraft.util.*; public class BraceletFeatureRenderer implements AccessoryFeatureRenderer.Feature { @@ -50,39 +48,41 @@ public class BraceletFeatureRenderer implements Accessor @Override public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { - ItemStack item = entity.getEquippedStack(EquipmentSlot.CHEST); + FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.MAINHAND).findFirst().ifPresent(bangle -> { + renderBangleThirdPerson(bangle, stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm()); + }); + FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.OFFHAND).findFirst().ifPresent(bangle -> { + renderBangleThirdPerson(bangle, stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm().getOpposite()); + }); + } - if (item.getItem() instanceof FriendshipBraceletItem) { - int j = ((DyeableItem)item.getItem()).getColor(item); + private void renderBangleThirdPerson(ItemStack item, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch, Arm mainArm) { + int j = ((DyeableItem)item.getItem()).getColor(item); - boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim"); + boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim"); - BraceletModel model = alex ? alexModel : steveModel; + BraceletModel model = alex ? alexModel : steveModel; + boolean isLeft = mainArm == Arm.LEFT; - boolean isLeft = entity.getMainArm() == Arm.LEFT; - - if (entity instanceof ArmorStandEntity) { - ModelPart arm = isLeft ? context.getModel().leftArm : context.getModel().rightArm; - arm.visible = true; - VertexConsumer consumer = renderContext.getBuffer(context.getModel().getLayer(context.getTexture(entity))); - arm.render(stack, consumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); - } - - boolean glowing = ((GlowableItem)item.getItem()).isGlowing(item); - - VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(TEXTURE), false, false); - - model.setAngles(context.getModel()); - model.setVisible(entity.getMainArm()); - model.render(stack, consumer, glowing ? 0x0F00F0 : lightUv, OverlayTexture.DEFAULT_UV, Color.r(j), Color.g(j), Color.b(j), 1); + if (entity instanceof ArmorStandEntity) { + ModelPart arm = isLeft ? context.getModel().leftArm : context.getModel().rightArm; + arm.visible = true; + VertexConsumer consumer = renderContext.getBuffer(context.getModel().getLayer(context.getTexture(entity))); + arm.render(stack, consumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1); } + + boolean glowing = ((GlowableItem)item.getItem()).isGlowing(item); + + VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(TEXTURE), false, false); + + model.setAngles(context.getModel()); + model.setVisible(mainArm); + model.render(stack, consumer, glowing ? 0x0F00F0 : lightUv, OverlayTexture.DEFAULT_UV, Color.r(j), Color.g(j), Color.b(j), 1); } @Override public void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, ModelPart armModel, Arm side) { - ItemStack item = entity.getEquippedStack(EquipmentSlot.CHEST); - - if (item.getItem() instanceof FriendshipBraceletItem) { + FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAINHAND : TrinketsDelegate.OFFHAND).findFirst().ifPresent(item -> { int j = ((DyeableItem)item.getItem()).getColor(item); boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim"); @@ -91,8 +91,7 @@ public class BraceletFeatureRenderer implements Accessor boolean glowing = ((GlowableItem)item.getItem()).isGlowing(item); - - if (!MineLPConnector.getPlayerPonyRace((ClientPlayerEntity)entity).isDefault()) { + if (!MineLPDelegate.getInstance().getPlayerPonyRace((ClientPlayerEntity)entity).isDefault()) { stack.translate(side == Arm.LEFT ? 0.06 : -0.06, 0.3, 0); } else { stack.translate(0, -0.1, 0); @@ -103,7 +102,7 @@ public class BraceletFeatureRenderer implements Accessor model.setAngles(context.getModel()); model.setVisible(side); model.render(stack, consumer, glowing ? 0x0F00F0 : lightUv, OverlayTexture.DEFAULT_UV, Color.r(j), Color.g(j), Color.b(j), 1); - } + }); } public static class BraceletModel extends Model { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java index d1f411cc..6e98eae5 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java @@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.client.render; import java.util.Optional; import com.minelittlepony.unicopia.USounds; -import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.util.AnimationUtil; @@ -24,7 +24,7 @@ public class PlayerPoser { Pony pony = Pony.of(player); float progress = pony.getAnimationProgress(MinecraftClient.getInstance().getTickDelta()); Animation animation = pony.getAnimation(); - boolean isPony = !MineLPConnector.getPlayerPonyRace(player).isDefault(); + boolean isPony = !MineLPDelegate.getInstance().getPlayerPonyRace(player).isDefault(); switch (animation) { case WOLOLO: { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/PolearmRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/PolearmRenderer.java index 72ac6310..e50e3e2d 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/PolearmRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/PolearmRenderer.java @@ -1,6 +1,6 @@ package com.minelittlepony.unicopia.client.render; -import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry; @@ -70,7 +70,7 @@ public class PolearmRenderer implements DynamicItemRenderer, UnclampedModelPredi matrices.scale(1, -1, -1); Identifier id = Registry.ITEM.getId(stack.getItem()); Identifier texture = new Identifier(id.getNamespace(), "textures/entity/polearm/" + id.getPath() + ".png"); - model.render(matrices, MineLPConnector.getItemBuffer(vertexConsumers, texture).orElseGet(() -> { + model.render(matrices, MineLPDelegate.getInstance().getItemBuffer(vertexConsumers, texture).orElseGet(() -> { return ItemRenderer.getDirectItemGlintConsumer(vertexConsumers, model.getLayer(texture), false, stack.hasGlint()); }), light, overlay, 1, 1, 1, 1); matrices.pop(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java index 5f564c15..3db6efc8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.item.GemstoneItem; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.Tickable; @@ -43,7 +44,17 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable { @Override public void tick() { - armour.update(pony.getMaster().getInventory().armor.stream()); + armour.update(getAll()); + } + + private Stream getAll() { + if (!TrinketsDelegate.hasTrinkets()) { + return pony.getMaster().getInventory().armor.stream(); + } + return Stream.concat( + TrinketsDelegate.getInstance().getEquipped(pony.getMaster(), TrinketsDelegate.NECKLACE), + pony.getMaster().getInventory().armor.stream() + ); } public ItemTracker getArmour() { diff --git a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java index 58264874..9c63fedb 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java @@ -201,7 +201,7 @@ public class AlicornAmuletItem extends AmuletItem implements PlayerCharmTracker. }, 50); } - pony.findAllEntitiesInRange(10, e -> e instanceof MobEntity && !((MobEntity)e).hasStatusEffect(UEffects.CORRUPT_INFLUENCE)).forEach(e -> { + pony.findAllEntitiesInRange(10, e -> e instanceof MobEntity mob && !mob.hasStatusEffect(UEffects.CORRUPT_INFLUENCE)).forEach(e -> { ((MobEntity)e).addStatusEffect(new StatusEffectInstance(UEffects.CORRUPT_INFLUENCE, 1300, 1)); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java index da51b994..122815b3 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AmuletItem.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; import com.minelittlepony.unicopia.particle.ParticleUtils; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.minecraft.client.MinecraftClient; @@ -99,7 +100,14 @@ public class AmuletItem extends WearableItem { } public boolean isApplicable(LivingEntity entity) { - return isApplicable(entity.getEquippedStack(EquipmentSlot.CHEST)); + return isApplicable(getForEntity(entity)); + } + + public static ItemStack getForEntity(LivingEntity entity) { + return TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.NECKLACE) + .filter(stack -> stack.getItem() instanceof AmuletItem) + .findFirst() + .orElse(ItemStack.EMPTY); } public boolean isChargable() { diff --git a/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java index b13ff14c..a40d3e85 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java @@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -23,9 +24,7 @@ import net.minecraft.item.DyeableItem; import net.minecraft.item.ItemStack; import net.minecraft.stat.Stats; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Hand; -import net.minecraft.util.TypedActionResult; +import net.minecraft.util.*; import net.minecraft.world.World; public class FriendshipBraceletItem extends WearableItem implements DyeableItem, GlowableItem { @@ -115,10 +114,11 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem, public static boolean isComrade(Caster caster, Entity entity) { if (entity instanceof LivingEntity) { - return caster.getMasterId().filter(id -> { - return isSignedBy(((LivingEntity)entity).getOffHandStack(), id) - || isSignedBy(((LivingEntity)entity).getEquippedStack(EquipmentSlot.CHEST), id); - }).isPresent(); + return caster.getMasterId() + .filter(id -> getWornBangles((LivingEntity)entity) + .anyMatch(stack -> isSignedBy(stack, id)) + ) + .isPresent(); } return false; } @@ -126,4 +126,16 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem, public static Stream getPartyMembers(Caster caster, double radius) { return Pony.stream(caster.findAllEntitiesInRange(radius, entity -> isComrade(caster, entity))); } + + public static Stream getWornBangles(LivingEntity entity) { + return Stream.concat( + TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.MAINHAND), + TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.OFFHAND) + ).filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET); + } + + public static Stream getWornBangles(LivingEntity entity, Identifier slot) { + return TrinketsDelegate.getInstance().getEquipped(entity, slot) + .filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java b/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java index 4d7aab6e..3a3e062f 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java @@ -1,9 +1,10 @@ package com.minelittlepony.unicopia.item; +import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; + import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.minecraft.block.DispenserBlock; import net.minecraft.entity.EquipmentSlot; -import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ArmorItem; import net.minecraft.item.ArmorMaterials; @@ -18,26 +19,26 @@ import net.minecraft.world.World; public abstract class WearableItem extends Item implements Wearable { public WearableItem(FabricItemSettings settings) { - super(settings.equipmentSlot(s -> ((WearableItem)s.getItem()).getPreferredSlot(s))); + super(configureEquipmentSlotSupplier(settings)); DispenserBlock.registerBehavior(this, ArmorItem.DISPENSER_BEHAVIOR); + TrinketsDelegate.getInstance().registerTrinket(this); + } + + private static FabricItemSettings configureEquipmentSlotSupplier(FabricItemSettings settings) { + if (TrinketsDelegate.hasTrinkets()) { + return settings; + } + return settings.equipmentSlot(s -> ((WearableItem)s.getItem()).getPreferredSlot(s)); } @Override public TypedActionResult use(World world, PlayerEntity player, Hand hand) { ItemStack stack = player.getStackInHand(hand); - - EquipmentSlot slot = MobEntity.getPreferredEquipmentSlot(stack); - ItemStack currentArmor = player.getEquippedStack(slot); - - if (currentArmor.isEmpty()) { - ItemStack result = stack.copy(); - result.setCount(1); - player.equipStack(slot, result); - stack.decrement(1); - return TypedActionResult.success(stack, world.isClient()); - } - - return TypedActionResult.fail(stack); + return TrinketsDelegate.getInstance().getAvailableTrinketSlots(player, TrinketsDelegate.ALL).stream() + .findAny() + .filter(slotId -> TrinketsDelegate.getInstance().equipStack(player, slotId, stack)) + .map(slotId -> TypedActionResult.success(stack, world.isClient())) + .orElseGet(() -> TypedActionResult.fail(stack)); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java new file mode 100644 index 00000000..38369cbe --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegate.java @@ -0,0 +1,68 @@ +package com.minelittlepony.unicopia.trinkets; + +import java.util.*; +import java.util.stream.Stream; + +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; + +public interface TrinketsDelegate { + Identifier MAINHAND = new Identifier("hand:glove"); + Identifier OFFHAND = new Identifier("offhand:glove"); + Identifier NECKLACE = new Identifier("chest:necklace"); + + Set ALL = new TreeSet<>(List.of(MAINHAND, OFFHAND, NECKLACE)); + + TrinketsDelegate EMPTY = new TrinketsDelegate() {}; + + static TrinketsDelegate getInstance() { + if (!hasTrinkets()) { + return EMPTY; + } + + return TrinketsDelegateImpl.INSTANCE; + } + + static boolean hasTrinkets() { + return FabricLoader.getInstance().isModLoaded("trinkets"); + } + + default boolean equipStack(LivingEntity entity, Identifier slot, ItemStack stack) { + EquipmentSlot eq = MobEntity.getPreferredEquipmentSlot(stack); + if (!entity.getEquippedStack(eq).isEmpty()) { + return false; + } + + entity.equipStack(eq, stack.split(1)); + return true; + } + + default Set getAvailableTrinketSlots(LivingEntity entity, Set probedSlots) { + return Set.of(); + } + + default Stream getEquipped(LivingEntity entity) { + return Stream.empty(); + } + + default Stream getEquipped(LivingEntity entity, Identifier slot) { + + if (slot == NECKLACE || slot == MAINHAND) { + return Stream.of(entity.getEquippedStack(EquipmentSlot.CHEST)); + } + if (slot == OFFHAND) { + return Stream.of(entity.getOffHandStack()); + } + + return Stream.empty(); + } + + default void registerTrinket(Item item) { + + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java new file mode 100644 index 00000000..06940ecf --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/TrinketsDelegateImpl.java @@ -0,0 +1,85 @@ +package com.minelittlepony.unicopia.trinkets; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.minelittlepony.unicopia.util.InventoryUtil; + +import dev.emi.trinkets.TrinketSlot; +import dev.emi.trinkets.api.*; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.Identifier; +import net.minecraft.world.event.GameEvent; + +class TrinketsDelegateImpl implements TrinketsDelegate { + static final TrinketsDelegateImpl INSTANCE = new TrinketsDelegateImpl(); + // who tf designed this api? + + @Override + public boolean equipStack(LivingEntity entity, Identifier slot, ItemStack stack) { + return getInventory(entity, slot).map(inventory -> { + for (int position = 0; position < inventory.size(); position++) { + if (inventory.getStack(position).isEmpty() && TrinketSlot.canInsert(stack, new SlotReference(inventory, position), entity)) { + SoundEvent soundEvent = stack.getEquipSound(); + inventory.setStack(position, stack.split(1)); + if (soundEvent != null) { + entity.emitGameEvent(GameEvent.EQUIP); + entity.playSound(soundEvent, 1, 1); + } + return true; + } + } + return false; + }).orElse(false); + } + + @Override + public Set getAvailableTrinketSlots(LivingEntity entity, Set probedSlots) { + probedSlots = new HashSet<>(probedSlots); + probedSlots.removeAll(getInventories(entity) + .filter(inventory -> InventoryUtil.getOpenSlot(inventory) == -1) + .map(slot -> slot.getSlotType()) + .map(TrinketsDelegateImpl::getSlotId) + .collect(Collectors.toSet())); + return probedSlots; + } + + @Override + public Stream getEquipped(LivingEntity entity) { + return getInventories(entity).flatMap(InventoryUtil::stream).filter(s -> !s.isEmpty()); + } + + @Override + public Stream getEquipped(LivingEntity entity, Identifier slot) { + return getInventory(entity, slot).stream().flatMap(InventoryUtil::stream).filter(s -> !s.isEmpty()); + } + + @Override + public void registerTrinket(Item item) { + TrinketsApi.registerTrinket(item, new UnicopiaTrinket(item)); + } + + public Optional getInventory(LivingEntity entity, Identifier slot) { + return TrinketsApi.getTrinketComponent(entity) + .map(component -> component.getInventory() + .getOrDefault(slot.getNamespace(), Map.of()) + .getOrDefault(slot.getPath(), null) + ); + } + + private Stream getInventories(LivingEntity entity) { + return TrinketsApi.getTrinketComponent(entity) + .stream() + .map(component -> component.getInventory()) + .flatMap(groups -> groups.values().stream()) + .flatMap(group -> group.values().stream()); + } + + private static Identifier getSlotId(SlotType slotType) { + return new Identifier(slotType.getGroup(), slotType.getName()); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/trinkets/UnicopiaTrinket.java b/src/main/java/com/minelittlepony/unicopia/trinkets/UnicopiaTrinket.java new file mode 100644 index 00000000..48a9a27e --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/trinkets/UnicopiaTrinket.java @@ -0,0 +1,65 @@ +package com.minelittlepony.unicopia.trinkets; + +import java.util.UUID; + +import com.google.common.collect.Multimap; +import com.minelittlepony.unicopia.item.FriendshipBraceletItem; +import com.minelittlepony.unicopia.item.WearableItem; + +import dev.emi.trinkets.api.*; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.EntityAttribute; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundEvent; + +public class UnicopiaTrinket implements Trinket { + + private final Item item; + + public UnicopiaTrinket(Item item) { + this.item = item; + } + + @Override + public void onEquip(ItemStack stack, SlotReference slot, LivingEntity entity) { + if (entity.isSpectator() || stack.isEmpty()) { + return; + } + + SoundEvent soundEvent = stack.getEquipSound(); + if (soundEvent != null) { + entity.playSound(soundEvent, 1, 1); + } + } + + // @Override + public int getMaxCount(ItemStack stack, SlotReference slot, LivingEntity entity) { + // https://github.com/emilyploszaj/trinkets/issues/215 + return 1; + } + + @Override + public boolean canEquip(ItemStack stack, SlotReference slot, LivingEntity entity) { + if (item instanceof FriendshipBraceletItem && !FriendshipBraceletItem.isSigned(stack)) { + return false; + } + + return slot.inventory().getStack(slot.index()).isEmpty(); + } + + @Override + public void tick(ItemStack stack, SlotReference slot, LivingEntity entity) { + item.inventoryTick(stack, entity.world, entity, slot.index(), false); + } + + @Override + public Multimap getModifiers(ItemStack stack, SlotReference slot, LivingEntity entity, UUID uuid) { + Multimap modifiers = Trinket.super.getModifiers(stack, slot, entity, uuid); + if (item instanceof WearableItem wearable) { + item.getAttributeModifiers(wearable.getPreferredSlot(stack)); + } + return modifiers; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/util/InventoryUtil.java b/src/main/java/com/minelittlepony/unicopia/util/InventoryUtil.java index f4893019..2b19564e 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/InventoryUtil.java +++ b/src/main/java/com/minelittlepony/unicopia/util/InventoryUtil.java @@ -13,4 +13,13 @@ public interface InventoryUtil { static Stream slots(Inventory inventory) { return Stream.iterate(0, i -> i < inventory.size(), i -> i + 1); } + + static int getOpenSlot(Inventory inventory) { + for (int i = 0; i < inventory.size(); i++) { + if (inventory.getStack(i).isEmpty()) { + return i; + } + } + return -1; + } } diff --git a/src/main/resources/data/trinkets/entities/unicopia.json b/src/main/resources/data/trinkets/entities/unicopia.json new file mode 100644 index 00000000..9cad0bc7 --- /dev/null +++ b/src/main/resources/data/trinkets/entities/unicopia.json @@ -0,0 +1,10 @@ +{ + "entities": [ + "player" + ], + "slots": [ + "hand/glove", + "offhand/glove", + "chest/necklace" + ] +} diff --git a/src/main/resources/data/trinkets/tags/items/chest/necklace.json b/src/main/resources/data/trinkets/tags/items/chest/necklace.json new file mode 100644 index 00000000..0dee7ce9 --- /dev/null +++ b/src/main/resources/data/trinkets/tags/items/chest/necklace.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "unicopia:alicorn_amulet", + "unicopia:pegasus_amulet" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/trinkets/tags/items/hand/glove.json b/src/main/resources/data/trinkets/tags/items/hand/glove.json new file mode 100644 index 00000000..c72868a5 --- /dev/null +++ b/src/main/resources/data/trinkets/tags/items/hand/glove.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "unicopia:friendship_bracelet" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/trinkets/tags/items/offhand/glove.json b/src/main/resources/data/trinkets/tags/items/offhand/glove.json new file mode 100644 index 00000000..c72868a5 --- /dev/null +++ b/src/main/resources/data/trinkets/tags/items/offhand/glove.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "unicopia:friendship_bracelet" + ] +} \ No newline at end of file