From 120fd6eb385e1cadde392a19415d9d9ec9973c5a Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 3 Feb 2021 22:25:42 +0200 Subject: [PATCH] Added friendship bracelets! --- .../ability/magic/spell/ShieldSpell.java | 4 +- .../unicopia/client/URenderers.java | 5 + .../render/BraceletFeatureRenderer.java | 96 +++++++++++++ .../unicopia/item/FriendshipBraceletItem.java | 126 ++++++++++++++++++ .../unicopia/item/GlowableItem.java | 15 +++ .../unicopia/item/GlowingRecipe.java | 79 +++++++++++ .../minelittlepony/unicopia/item/UItems.java | 8 ++ .../unicopia/item/URecipes.java | 20 +++ .../unicopia/item/ZapAppleRecipe.java | 16 +-- .../client/MixinArmorFeatureRenderer.java | 34 +++++ .../resources/assets/unicopia/lang/en_us.json | 4 + .../models/item/friendship_bracelet.json | 6 + .../textures/item/friendship_bracelet.png | Bin 0 -> 3094 bytes .../textures/models/armor/bracelet.png | Bin 0 -> 1076 bytes .../unicopia/recipes/friendship_bracelet.json | 19 +++ .../data/unicopia/recipes/glowing_bangle.json | 3 + src/main/resources/unicopia.mixin.json | 1 + 17 files changed, 420 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/GlowableItem.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/GlowingRecipe.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java create mode 100644 src/main/resources/assets/unicopia/models/item/friendship_bracelet.json create mode 100644 src/main/resources/assets/unicopia/textures/item/friendship_bracelet.png create mode 100644 src/main/resources/assets/unicopia/textures/models/armor/bracelet.png create mode 100644 src/main/resources/data/unicopia/recipes/friendship_bracelet.json create mode 100644 src/main/resources/data/unicopia/recipes/glowing_bangle.json diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ShieldSpell.java index 989078d9..119af6c0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ShieldSpell.java @@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.item.FriendshipBraceletItem; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.ParticleHandle; import com.minelittlepony.unicopia.particle.SphereParticleEffect; @@ -114,7 +115,8 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements Attached { return source.findAllEntitiesInRange(radius) .filter(entity -> { return - (entity instanceof LivingEntity + !FriendshipBraceletItem.isComrade(source, entity) + && (entity instanceof LivingEntity || entity instanceof TntEntity || entity instanceof FallingBlockEntity || entity instanceof EyeOfEnderEntity diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index 9e4f0e61..afdd1c3c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -9,15 +9,18 @@ import com.minelittlepony.unicopia.client.particle.RainboomParticle; import com.minelittlepony.unicopia.client.particle.RainbowTrailParticle; import com.minelittlepony.unicopia.client.particle.RaindropsParticle; import com.minelittlepony.unicopia.client.particle.SphereParticle; +import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.particle.UParticles; import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry.PendingParticleFactory; import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.SpriteProvider; import net.minecraft.client.render.entity.FlyingItemEntityRenderer; import net.minecraft.client.world.ClientWorld; +import net.minecraft.item.DyeableItem; import net.minecraft.particle.ParticleEffect; public interface URenderers { @@ -32,6 +35,8 @@ public interface URenderers { ParticleFactoryRegistry.getInstance().register(UParticles.DISK, DiskParticle::new); EntityRendererRegistry.INSTANCE.register(UEntities.THROWN_ITEM, (manager, context) -> new FlyingItemEntityRenderer<>(manager, context.getItemRenderer())); + + ColorProviderRegistry.ITEM.register((stack, i) -> i > 0 ? -1 : ((DyeableItem)stack.getItem()).getColor(stack), UItems.FRIENDSHIP_BRACELET); } static PendingParticleFactory createFactory(ParticleSupplier supplier) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java new file mode 100644 index 00000000..5c8a1194 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/BraceletFeatureRenderer.java @@ -0,0 +1,96 @@ +package com.minelittlepony.unicopia.client.render; + +import com.minelittlepony.common.util.Color; +import com.minelittlepony.unicopia.item.FriendshipBraceletItem; +import com.minelittlepony.unicopia.item.GlowableItem; + +import net.minecraft.client.model.Model; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.feature.FeatureRenderer; +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.DyeableItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Arm; +import net.minecraft.util.Identifier; + +public class BraceletFeatureRenderer< + E extends LivingEntity, + M extends BipedEntityModel> extends FeatureRenderer { + + private static final Identifier TEXTURE = new Identifier("unicopia", "textures/models/armor/bracelet.png"); + + private final BraceletModel steveModel = new BraceletModel(0.3F, false); + private final BraceletModel alexModel = new BraceletModel(0.3F, true); + + public BraceletFeatureRenderer(FeatureRendererContext context) { + super(context); + } + + @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); + + if (item.getItem() instanceof FriendshipBraceletItem) { + VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(TEXTURE), false, false); + + int j = ((DyeableItem)item.getItem()).getColor(item); + + boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim"); + + BraceletModel model = alex ? alexModel : steveModel; + + model.setAngles(getContextModel()); + model.setVisible(entity.getMainArm()); + model.render(stack, consumer, ((GlowableItem)item.getItem()).isGlowing(item) ? 0x0F00F0 : lightUv, OverlayTexture.DEFAULT_UV, Color.r(j), Color.g(j), Color.b(j), 1); + } + } + + static class BraceletModel extends Model { + + private final ModelPart leftArm; + private final ModelPart rightArm; + + private final boolean alex; + + public BraceletModel(float dilate, boolean alex) { + super(RenderLayer::getEntityTranslucent); + this.alex = alex; + rightArm = new ModelPart(this, 0, alex ? 6 : 0); + rightArm.addCuboid(-3, 7, -2, alex ? 3 : 4, 2, 4, dilate); + leftArm = new ModelPart(this, 0, alex ? 6 : 0); + leftArm.mirror = true; + leftArm.addCuboid(-1, 7, -2, alex ? 3 : 4, 2, 4, dilate); + } + + public void setAngles(BipedEntityModel biped) { + leftArm.copyPositionAndRotation(biped.leftArm); + rightArm.copyPositionAndRotation(biped.rightArm); + if (alex) { + rightArm.pivotX++; + } + } + + public void setVisible(Arm arm) { + leftArm.visible = arm == Arm.LEFT; + rightArm.visible = arm == Arm.RIGHT; + } + + @Override + public void render(MatrixStack matrixStack, VertexConsumer vertexConsumer, int i, int j, float f, float g, float h, float k) { + leftArm.render(matrixStack, vertexConsumer, i, j, f, g, h, k); + rightArm.render(matrixStack, vertexConsumer, i, j, f, g, h, k); + } + } + +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java new file mode 100644 index 00000000..f78d16e7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java @@ -0,0 +1,126 @@ +package com.minelittlepony.unicopia.item; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.minelittlepony.unicopia.EquinePredicates; +import com.minelittlepony.unicopia.ability.magic.Caster; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.DispenserBlock; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.DyeableItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Wearable; +import net.minecraft.sound.SoundEvents; +import net.minecraft.stat.Stats; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; + +public class FriendshipBraceletItem extends Item implements DyeableItem, Wearable, GlowableItem { + + public FriendshipBraceletItem(Settings settings) { + super(settings); + DispenserBlock.registerBehavior(this, ArmorItem.DISPENSER_BEHAVIOR); + } + + @Override + public TypedActionResult use(World world, PlayerEntity player, Hand hand) { + ItemStack stack = player.getStackInHand(hand); + + if (!isSigned(stack) && EquinePredicates.PLAYER_UNICORN.test(player)) { + player.setCurrentHand(hand); + + ItemStack result = stack.copy(); + result.setCount(1); + result.getOrCreateTag().putString("issuer", player.getName().asString()); + + if (!player.abilities.creativeMode) { + stack.decrement(1); + } + + player.incrementStat(Stats.USED.getOrCreateStat(this)); + player.playSound(SoundEvents.ITEM_BOOK_PUT, 1, 1); + + if (stack.isEmpty()) { + return TypedActionResult.consume(result); + } + if (!player.giveItemStack(result)) { + player.dropStack(result); + } + return TypedActionResult.consume(stack); + } + + EquipmentSlot slot = MobEntity.getPreferredEquipmentSlot(stack); + ItemStack currentArmor = player.getEquippedStack(slot); + + if (currentArmor.isEmpty()) { + ItemStack result = stack.copy(); + result.setCount(1); + + if (!player.abilities.creativeMode) { + stack.decrement(1); + } + + player.equipStack(slot, result); + return TypedActionResult.success(stack, world.isClient()); + } + + return TypedActionResult.fail(stack); + } + + @Override + @Environment(EnvType.CLIENT) + public void appendTooltip(ItemStack stack, @Nullable World world, List list, TooltipContext tooltipContext) { + if (isSigned(stack)) { + list.add(new TranslatableText("item.unicopia.friendship_bracelet.issuer", getSignature(stack))); + } + if (isGlowing(stack)) { + list.add(new TranslatableText("item.unicopia.friendship_bracelet.glowing").formatted(Formatting.ITALIC, Formatting.GRAY)); + } + } + + private boolean checkSignature(ItemStack stack, PlayerEntity player) { + return player.getName().asString().contentEquals(getSignature(stack)); + } + + @Nullable + public static String getSignature(ItemStack stack) { + return isSigned(stack) ? stack.getTag().getString("issuer") : null; + } + + public static boolean isSigned(ItemStack stack) { + return stack.hasTag() && stack.getTag().contains("issuer"); + } + + public static boolean isSignedBy(ItemStack stack, PlayerEntity player) { + return stack.getItem() instanceof FriendshipBraceletItem + && ((FriendshipBraceletItem)stack.getItem()).checkSignature(stack, player); + } + + public static boolean isComrade(Caster caster, Entity entity) { + Entity master = caster.getMaster(); + if (master instanceof PlayerEntity && entity instanceof LivingEntity) { + return isSignedBy(((LivingEntity)entity).getOffHandStack(), (PlayerEntity)master) + || isSignedBy(((LivingEntity)entity).getEquippedStack(EquipmentSlot.CHEST), (PlayerEntity)master); + } + + return false; + } + + public static EquipmentSlot getPreferredEquipmentSlot(ItemStack stack) { + return isSigned(stack) ? EquipmentSlot.CHEST : EquipmentSlot.OFFHAND; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/GlowableItem.java b/src/main/java/com/minelittlepony/unicopia/item/GlowableItem.java new file mode 100644 index 00000000..0c3931c4 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/GlowableItem.java @@ -0,0 +1,15 @@ +package com.minelittlepony.unicopia.item; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; + +public interface GlowableItem { + default boolean isGlowing(ItemStack stack) { + CompoundTag tag = stack.getSubTag("display"); + return tag != null && tag.getBoolean("glowing"); + } + + default void setGlowing(ItemStack stack, boolean glowing) { + stack.getOrCreateSubTag("display").putBoolean("glowing", glowing); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/GlowingRecipe.java b/src/main/java/com/minelittlepony/unicopia/item/GlowingRecipe.java new file mode 100644 index 00000000..4f1b1a3a --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/GlowingRecipe.java @@ -0,0 +1,79 @@ +package com.minelittlepony.unicopia.item; + +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.recipe.SpecialCraftingRecipe; +import net.minecraft.util.Identifier; +import net.minecraft.util.Pair; +import net.minecraft.world.World; + +public class GlowingRecipe extends SpecialCraftingRecipe { + + public GlowingRecipe(Identifier id) { + super(id); + } + + @Override + public boolean matches(CraftingInventory inventory, World world) { + Pair result = runMatch(inventory); + + return !result.getLeft().isEmpty() && !result.getRight().isEmpty(); + } + + @Override + public ItemStack craft(CraftingInventory inventory) { + Pair pair = runMatch(inventory); + + ItemStack result = pair.getLeft().copy(); + ((GlowableItem)result.getItem()).setGlowing(result, pair.getRight().getItem() == Items.GLOWSTONE_DUST); + + return result; + } + + private Pair runMatch(CraftingInventory inventory) { + ItemStack bangle = ItemStack.EMPTY; + ItemStack dust = ItemStack.EMPTY; + + for(int i = 0; i < inventory.size(); i++) { + ItemStack stack = inventory.getStack(i); + + if (!stack.isEmpty()) { + if (stack.getItem() instanceof GlowableItem) { + if (!bangle.isEmpty()) { + return new Pair<>(bangle, dust); + } + + bangle = stack; + } else { + if (!(stack.getItem() == Items.GLOWSTONE_DUST || stack.getItem() == Items.INK_SAC)) { + return new Pair<>(bangle, dust); + } + + dust = stack; + + + } + } + } + + if (!bangle.isEmpty()) { + if ((dust.getItem() == Items.GLOWSTONE_DUST) == ((GlowableItem)bangle.getItem()).isGlowing(bangle)) { + return new Pair<>(ItemStack.EMPTY, ItemStack.EMPTY); + } + } + + return new Pair<>(bangle, dust); + } + + @Override + public boolean fits(int i, int j) { + return i * j >= 2; + } + + @Override + public RecipeSerializer getSerializer() { + return URecipes.GLOWING_SERIALIZER; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index 93a8cb4a..772d6258 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -13,6 +13,7 @@ import net.minecraft.item.Item; import net.minecraft.item.Item.Settings; import net.minecraft.item.ItemGroup; import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; +import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.minecraft.item.BlockItem; import net.minecraft.item.FoodComponents; import net.minecraft.item.MusicDiscItem; @@ -39,6 +40,13 @@ public interface UItems { Item MUSIC_DISC_POPULAR = register("music_disc_popular", USounds.RECORD_POPULAR); Item MUSIC_DISC_FUNK = register("music_disc_funk", USounds.RECORD_FUNK); + FriendshipBraceletItem FRIENDSHIP_BRACELET = register("friendship_bracelet", new FriendshipBraceletItem( + new FabricItemSettings() + .rarity(Rarity.UNCOMMON) + .group(ItemGroup.TOOLS) + .equipmentSlot(FriendshipBraceletItem::getPreferredEquipmentSlot) + )); + static T register(String name, T item) { ITEMS.add(item); if (item instanceof BlockItem) { diff --git a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java b/src/main/java/com/minelittlepony/unicopia/item/URecipes.java index 9ddef924..8d6f8af7 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java +++ b/src/main/java/com/minelittlepony/unicopia/item/URecipes.java @@ -1,15 +1,21 @@ package com.minelittlepony.unicopia.item; +import com.google.gson.JsonArray; + +import net.minecraft.recipe.Ingredient; import net.minecraft.recipe.Recipe; import net.minecraft.recipe.RecipeSerializer; import net.minecraft.recipe.RecipeType; import net.minecraft.recipe.ShapelessRecipe; +import net.minecraft.recipe.SpecialRecipeSerializer; import net.minecraft.util.Identifier; +import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.registry.Registry; public interface URecipes { RecipeSerializer ZAP_APPLE_SERIALIZER = register("crafting_zap_apple", new ZapAppleRecipe.Serializer()); + RecipeSerializer GLOWING_SERIALIZER = register("crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new)); static > RecipeType register(final String id) { return Registry.register(Registry.RECIPE_TYPE, new Identifier("unicopia", id), new RecipeType() { @@ -24,5 +30,19 @@ public interface URecipes { return Registry.register(Registry.RECIPE_SERIALIZER, new Identifier("unicopia", id), serializer); } + + static DefaultedList getIngredients(JsonArray json) { + DefaultedList defaultedList = DefaultedList.of(); + + for (int i = 0; i < json.size(); ++i) { + Ingredient ingredient = Ingredient.fromJson(json.get(i)); + if (!ingredient.isEmpty()) { + defaultedList.add(ingredient); + } + } + + return defaultedList; + } + static void bootstrap() {} } \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleRecipe.java b/src/main/java/com/minelittlepony/unicopia/item/ZapAppleRecipe.java index 8a5ad90f..8cc3a565 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleRecipe.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ZapAppleRecipe.java @@ -1,6 +1,5 @@ package com.minelittlepony.unicopia.item; -import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; @@ -22,7 +21,7 @@ public class ZapAppleRecipe extends ShapelessRecipe { @Override public ShapelessRecipe read(Identifier identifier, JsonObject json) { String group = JsonHelper.getString(json, "group", ""); - DefaultedList ingredients = getIngredients(JsonHelper.getArray(json, "ingredients")); + DefaultedList ingredients = URecipes.getIngredients(JsonHelper.getArray(json, "ingredients")); if (ingredients.isEmpty()) { throw new JsonParseException("No ingredients for shapeless recipe"); @@ -48,18 +47,5 @@ public class ZapAppleRecipe extends ShapelessRecipe { return new ZapAppleRecipe(identifier, group, input.readItemStack(), ingredients); } - - private static DefaultedList getIngredients(JsonArray json) { - DefaultedList defaultedList = DefaultedList.of(); - - for (int i = 0; i < json.size(); ++i) { - Ingredient ingredient = Ingredient.fromJson(json.get(i)); - if (!ingredient.isEmpty()) { - defaultedList.add(ingredient); - } - } - - return defaultedList; - } } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java new file mode 100644 index 00000000..5945638c --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java @@ -0,0 +1,34 @@ +package com.minelittlepony.unicopia.mixin.client; + +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 com.minelittlepony.unicopia.client.render.BraceletFeatureRenderer; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; +import net.minecraft.client.render.entity.feature.FeatureRenderer; +import net.minecraft.client.render.entity.feature.FeatureRendererContext; +import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.LivingEntity; + +@Mixin(ArmorFeatureRenderer.class) +abstract class MixinArmorFeatureRenderer, A extends BipedEntityModel> extends FeatureRenderer { + + private BraceletFeatureRenderer bracelet; + + MixinArmorFeatureRenderer() { super(null); } + + @Inject(method = "", at = @At("RETURN")) + private void onInit(FeatureRendererContext context, A inner, A outer, CallbackInfo info) { + bracelet = new BraceletFeatureRenderer<>(context); + } + + @Inject(method = "render", at = @At("RETURN")) + private void onRender(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch, CallbackInfo info) { + bracelet.render(stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch); + } +} diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index f4661619..934af1b9 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -5,6 +5,10 @@ "itemGroup.unicopia.items": "Unicopia - Misc.", "itemGroup.unicopia.horsefeed": "Unicopia - Horse Feed", + "item.unicopia.friendship_bracelet": "Bangle of Comradery", + "item.unicopia.friendship_bracelet.issuer": "Signed by %s", + "item.unicopia.friendship_bracelet.glowing": "Glowing", + "item.unicopia.green_apple": "Granny Smith Apple", "item.unicopia.sweet_apple": "Sweet Apple Acres Apple", "item.unicopia.sour_apple": "Sour Apple", diff --git a/src/main/resources/assets/unicopia/models/item/friendship_bracelet.json b/src/main/resources/assets/unicopia/models/item/friendship_bracelet.json new file mode 100644 index 00000000..06fa4fad --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/friendship_bracelet.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "unicopia:item/friendship_bracelet" + } +} diff --git a/src/main/resources/assets/unicopia/textures/item/friendship_bracelet.png b/src/main/resources/assets/unicopia/textures/item/friendship_bracelet.png new file mode 100644 index 0000000000000000000000000000000000000000..eabb3cb647cf0eea2b9dfdc57b66272fa5a97677 GIT binary patch literal 3094 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