Added Trinkets support

This commit is contained in:
Sollace 2022-09-20 23:50:15 +02:00
parent 0e74cc6bbe
commit 32a23a6ca5
24 changed files with 445 additions and 136 deletions

View file

@ -39,6 +39,14 @@ repositories {
name = 'minelp-release' name = 'minelp-release'
url = 'https://repo.minelittlepony-mod.com/maven/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 { dependencies {
@ -55,6 +63,8 @@ dependencies {
modCompileOnly("com.terraformersmc:modmenu:${project.modmenu_version}") modCompileOnly("com.terraformersmc:modmenu:${project.modmenu_version}")
// implementation 'org.jetbrains:intellij-fernflower:1.2.1.16' // implementation 'org.jetbrains:intellij-fernflower:1.2.1.16'
modCompileOnly("net.caffienemc.sodium:sodium-fabric-mc1.19.2:0.4.4+build.18") modCompileOnly("net.caffienemc.sodium:sodium-fabric-mc1.19.2:0.4.4+build.18")
modCompileOnly "dev.emi:trinkets:3.4.0"
} }
processResources { processResources {

View file

@ -10,7 +10,7 @@ import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.ability.data.Pos;
import com.minelittlepony.unicopia.ability.data.tree.TreeType; import com.minelittlepony.unicopia.ability.data.tree.TreeType;
import com.minelittlepony.unicopia.block.data.BlockDestructionManager; 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.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
@ -54,7 +54,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
@Override @Override
public double getCostEstimate(Pony player) { 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) return RayTraceHelper.doTrace(player.getMaster(), distance, 1)
.getBlockPos() .getBlockPos()
@ -65,7 +65,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
@Nullable @Nullable
@Override @Override
public Pos tryActivate(Pony player) { 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) return RayTraceHelper.doTrace(player.getMaster(), distance, 1)
.getBlockPos() .getBlockPos()
@ -76,7 +76,7 @@ public class EarthPonyKickAbility implements Ability<Pos> {
private Pos getDefaultKickLocation(Pony player) { private Pos getDefaultKickLocation(Pony player) {
Vec3d kickVector = player.getMaster().getRotationVector().multiply(1, 0, 1); 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); kickVector = kickVector.rotateY((float)Math.PI);
} }
return new Pos(new BlockPos(player.getOriginVector().add(kickVector))); return new Pos(new BlockPos(player.getOriginVector().add(kickVector)));

View file

@ -11,7 +11,7 @@ import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.gui.LanSettingsScreen; import com.minelittlepony.unicopia.client.gui.LanSettingsScreen;
import com.minelittlepony.unicopia.client.gui.UHud; import com.minelittlepony.unicopia.client.gui.UHud;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookScreen; 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.container.*;
import com.minelittlepony.unicopia.entity.player.PlayerCamera; import com.minelittlepony.unicopia.entity.player.PlayerCamera;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -41,7 +41,7 @@ public class UnicopiaClient implements ClientModInitializer {
public static Race getPreferredRace() { public static Race getPreferredRace() {
if (!Unicopia.getConfig().ignoreMineLP.get() if (!Unicopia.getConfig().ignoreMineLP.get()
&& MinecraftClient.getInstance().player != null) { && MinecraftClient.getInstance().player != null) {
Race race = MineLPConnector.getPlayerPonyRace(); Race race = MineLPDelegate.getInstance().getPlayerPonyRace();
if (!race.isDefault()) { if (!race.isDefault()) {
return race; return race;

View file

@ -7,7 +7,7 @@ import com.minelittlepony.common.client.gui.ScrollContainer;
import com.minelittlepony.common.client.gui.element.*; import com.minelittlepony.common.client.gui.element.*;
import com.minelittlepony.common.client.gui.style.Style; import com.minelittlepony.common.client.gui.style.Style;
import com.minelittlepony.unicopia.*; 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 com.minelittlepony.unicopia.util.RegistryIndexer;
import net.fabricmc.loader.api.FabricLoader; 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.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); return Text.translatable("unicopia.options.ignore_mine_lp.missing").formatted(Formatting.RED);

View file

@ -1,26 +1,33 @@
package com.minelittlepony.unicopia.client.minelittlepony; package com.minelittlepony.unicopia.client.minelittlepony;
import java.util.Optional;
import com.minelittlepony.api.model.IModel; import com.minelittlepony.api.model.IModel;
import com.minelittlepony.api.model.ModelAttributes; import com.minelittlepony.api.model.ModelAttributes;
import com.minelittlepony.api.model.fabric.PonyModelPrepareCallback; import com.minelittlepony.api.model.fabric.PonyModelPrepareCallback;
import com.minelittlepony.api.model.gear.IGear; import com.minelittlepony.api.model.gear.IGear;
import com.minelittlepony.unicopia.Owned; import com.minelittlepony.client.MineLittlePony;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.client.render.LevitatingItemRenderer;
import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.AnimationUtil; import com.minelittlepony.unicopia.util.AnimationUtil;
import net.fabricmc.api.ClientModInitializer; 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.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
public class Main implements ClientModInitializer { public class Main extends MineLPDelegate implements ClientModInitializer {
private boolean hookErroring; private boolean hookErroring;
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
INSTANCE = this;
PonyModelPrepareCallback.EVENT.register(this::onPonyModelPrepared); PonyModelPrepareCallback.EVENT.register(this::onPonyModelPrepared);
IGear.register(BangleGear::new); IGear.register(BangleGear::new);
IGear.register(AmuletGear::new); IGear.register(AmuletGear::new);
@ -52,4 +59,39 @@ public class Main implements ClientModInitializer {
hookErroring = true; 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<VertexConsumer> getItemBuffer(VertexConsumerProvider vertexConsumers, Identifier texture) {
if (LevitatingItemRenderer.isEnabled()) {
return Optional.of(vertexConsumers.getBuffer(LevitatingItemRenderer.getRenderLayer(texture)));
}
return Optional.empty();
}
} }

View file

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

View file

@ -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<VertexConsumer> getItemBuffer(VertexConsumerProvider vertexConsumers, Identifier texture) {
return Optional.empty();
}
}

View file

@ -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.entity.model.BipedEntityModel;
import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -43,9 +42,9 @@ public class AmuletFeatureRenderer<E extends LivingEntity> implements AccessoryF
@Override @Override
public void render(MatrixStack matrices, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { 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")); 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); VertexConsumer consumer = ItemRenderer.getArmorGlintConsumer(renderContext, RenderLayer.getArmorCutoutNoCull(texture), false, false);

View file

@ -2,9 +2,9 @@ package com.minelittlepony.unicopia.client.render;
import com.minelittlepony.common.util.Color; import com.minelittlepony.common.util.Color;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector; import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem; import com.minelittlepony.unicopia.item.*;
import com.minelittlepony.unicopia.item.GlowableItem; import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
import net.minecraft.client.model.Dilation; import net.minecraft.client.model.Dilation;
import net.minecraft.client.model.Model; 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.entity.model.EntityModelPartNames;
import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.item.DyeableItem; import net.minecraft.item.DyeableItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Arm; import net.minecraft.util.*;
import net.minecraft.util.Identifier;
public class BraceletFeatureRenderer<E extends LivingEntity> implements AccessoryFeatureRenderer.Feature<E> { public class BraceletFeatureRenderer<E extends LivingEntity> implements AccessoryFeatureRenderer.Feature<E> {
@ -50,39 +48,41 @@ public class BraceletFeatureRenderer<E extends LivingEntity> implements Accessor
@Override @Override
public void render(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch) { 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) { 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); 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;
if (entity instanceof ArmorStandEntity) { arm.visible = true;
ModelPart arm = isLeft ? context.getModel().leftArm : context.getModel().rightArm; VertexConsumer consumer = renderContext.getBuffer(context.getModel().getLayer(context.getTexture(entity)));
arm.visible = true; arm.render(stack, consumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1);
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);
} }
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 @Override
public void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, ModelPart armModel, Arm side) { public void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, ModelPart armModel, Arm side) {
ItemStack item = entity.getEquippedStack(EquipmentSlot.CHEST); FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAINHAND : TrinketsDelegate.OFFHAND).findFirst().ifPresent(item -> {
if (item.getItem() instanceof FriendshipBraceletItem) {
int j = ((DyeableItem)item.getItem()).getColor(item); 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");
@ -91,8 +91,7 @@ public class BraceletFeatureRenderer<E extends LivingEntity> implements Accessor
boolean glowing = ((GlowableItem)item.getItem()).isGlowing(item); boolean glowing = ((GlowableItem)item.getItem()).isGlowing(item);
if (!MineLPDelegate.getInstance().getPlayerPonyRace((ClientPlayerEntity)entity).isDefault()) {
if (!MineLPConnector.getPlayerPonyRace((ClientPlayerEntity)entity).isDefault()) {
stack.translate(side == Arm.LEFT ? 0.06 : -0.06, 0.3, 0); stack.translate(side == Arm.LEFT ? 0.06 : -0.06, 0.3, 0);
} else { } else {
stack.translate(0, -0.1, 0); stack.translate(0, -0.1, 0);
@ -103,7 +102,7 @@ public class BraceletFeatureRenderer<E extends LivingEntity> implements Accessor
model.setAngles(context.getModel()); model.setAngles(context.getModel());
model.setVisible(side); model.setVisible(side);
model.render(stack, consumer, glowing ? 0x0F00F0 : lightUv, OverlayTexture.DEFAULT_UV, Color.r(j), Color.g(j), Color.b(j), 1); 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 { public static class BraceletModel extends Model {

View file

@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.client.render;
import java.util.Optional; import java.util.Optional;
import com.minelittlepony.unicopia.USounds; 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.entity.player.Pony;
import com.minelittlepony.unicopia.util.AnimationUtil; import com.minelittlepony.unicopia.util.AnimationUtil;
@ -24,7 +24,7 @@ public class PlayerPoser {
Pony pony = Pony.of(player); Pony pony = Pony.of(player);
float progress = pony.getAnimationProgress(MinecraftClient.getInstance().getTickDelta()); float progress = pony.getAnimationProgress(MinecraftClient.getInstance().getTickDelta());
Animation animation = pony.getAnimation(); Animation animation = pony.getAnimation();
boolean isPony = !MineLPConnector.getPlayerPonyRace(player).isDefault(); boolean isPony = !MineLPDelegate.getInstance().getPlayerPonyRace(player).isDefault();
switch (animation) { switch (animation) {
case WOLOLO: { case WOLOLO: {

View file

@ -1,6 +1,6 @@
package com.minelittlepony.unicopia.client.render; 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.model.ModelLoadingRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry; import net.fabricmc.fabric.api.client.rendering.v1.BuiltinItemRendererRegistry;
@ -70,7 +70,7 @@ public class PolearmRenderer implements DynamicItemRenderer, UnclampedModelPredi
matrices.scale(1, -1, -1); matrices.scale(1, -1, -1);
Identifier id = Registry.ITEM.getId(stack.getItem()); Identifier id = Registry.ITEM.getId(stack.getItem());
Identifier texture = new Identifier(id.getNamespace(), "textures/entity/polearm/" + id.getPath() + ".png"); 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()); return ItemRenderer.getDirectItemGlintConsumer(vertexConsumers, model.getLayer(texture), false, stack.hasGlint());
}), light, overlay, 1, 1, 1, 1); }), light, overlay, 1, 1, 1, 1);
matrices.pop(); matrices.pop();

View file

@ -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.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.item.GemstoneItem; import com.minelittlepony.unicopia.item.GemstoneItem;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.minelittlepony.unicopia.util.Tickable; import com.minelittlepony.unicopia.util.Tickable;
@ -43,7 +44,17 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable {
@Override @Override
public void tick() { public void tick() {
armour.update(pony.getMaster().getInventory().armor.stream()); armour.update(getAll());
}
private Stream<ItemStack> 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() { public ItemTracker getArmour() {

View file

@ -201,7 +201,7 @@ public class AlicornAmuletItem extends AmuletItem implements PlayerCharmTracker.
}, 50); }, 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)); ((MobEntity)e).addStatusEffect(new StatusEffectInstance(UEffects.CORRUPT_INFLUENCE, 1300, 1));
}); });
} }

View file

@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -99,7 +100,14 @@ public class AmuletItem extends WearableItem {
} }
public boolean isApplicable(LivingEntity entity) { 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() { public boolean isChargable() {

View file

@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
@ -23,9 +24,7 @@ import net.minecraft.item.DyeableItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.stat.Stats; import net.minecraft.stat.Stats;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Formatting; import net.minecraft.util.*;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World; import net.minecraft.world.World;
public class FriendshipBraceletItem extends WearableItem implements DyeableItem, GlowableItem { 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) { public static boolean isComrade(Caster<?> caster, Entity entity) {
if (entity instanceof LivingEntity) { if (entity instanceof LivingEntity) {
return caster.getMasterId().filter(id -> { return caster.getMasterId()
return isSignedBy(((LivingEntity)entity).getOffHandStack(), id) .filter(id -> getWornBangles((LivingEntity)entity)
|| isSignedBy(((LivingEntity)entity).getEquippedStack(EquipmentSlot.CHEST), id); .anyMatch(stack -> isSignedBy(stack, id))
}).isPresent(); )
.isPresent();
} }
return false; return false;
} }
@ -126,4 +126,16 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem,
public static Stream<Pony> getPartyMembers(Caster<?> caster, double radius) { public static Stream<Pony> getPartyMembers(Caster<?> caster, double radius) {
return Pony.stream(caster.findAllEntitiesInRange(radius, entity -> isComrade(caster, entity))); return Pony.stream(caster.findAllEntitiesInRange(radius, entity -> isComrade(caster, entity)));
} }
public static Stream<ItemStack> 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<ItemStack> getWornBangles(LivingEntity entity, Identifier slot) {
return TrinketsDelegate.getInstance().getEquipped(entity, slot)
.filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET);
}
} }

View file

@ -1,9 +1,10 @@
package com.minelittlepony.unicopia.item; package com.minelittlepony.unicopia.item;
import com.minelittlepony.unicopia.trinkets.TrinketsDelegate;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.minecraft.block.DispenserBlock; import net.minecraft.block.DispenserBlock;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ArmorItem; import net.minecraft.item.ArmorItem;
import net.minecraft.item.ArmorMaterials; import net.minecraft.item.ArmorMaterials;
@ -18,26 +19,26 @@ import net.minecraft.world.World;
public abstract class WearableItem extends Item implements Wearable { public abstract class WearableItem extends Item implements Wearable {
public WearableItem(FabricItemSettings settings) { public WearableItem(FabricItemSettings settings) {
super(settings.equipmentSlot(s -> ((WearableItem)s.getItem()).getPreferredSlot(s))); super(configureEquipmentSlotSupplier(settings));
DispenserBlock.registerBehavior(this, ArmorItem.DISPENSER_BEHAVIOR); 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 @Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) { public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getStackInHand(hand);
return TrinketsDelegate.getInstance().getAvailableTrinketSlots(player, TrinketsDelegate.ALL).stream()
EquipmentSlot slot = MobEntity.getPreferredEquipmentSlot(stack); .findAny()
ItemStack currentArmor = player.getEquippedStack(slot); .filter(slotId -> TrinketsDelegate.getInstance().equipStack(player, slotId, stack))
.map(slotId -> TypedActionResult.success(stack, world.isClient()))
if (currentArmor.isEmpty()) { .orElseGet(() -> TypedActionResult.fail(stack));
ItemStack result = stack.copy();
result.setCount(1);
player.equipStack(slot, result);
stack.decrement(1);
return TypedActionResult.success(stack, world.isClient());
}
return TypedActionResult.fail(stack);
} }
@Override @Override

View file

@ -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<Identifier> 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<Identifier> getAvailableTrinketSlots(LivingEntity entity, Set<Identifier> probedSlots) {
return Set.of();
}
default Stream<ItemStack> getEquipped(LivingEntity entity) {
return Stream.empty();
}
default Stream<ItemStack> 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) {
}
}

View file

@ -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<Identifier> getAvailableTrinketSlots(LivingEntity entity, Set<Identifier> 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<ItemStack> getEquipped(LivingEntity entity) {
return getInventories(entity).flatMap(InventoryUtil::stream).filter(s -> !s.isEmpty());
}
@Override
public Stream<ItemStack> 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<TrinketInventory> getInventory(LivingEntity entity, Identifier slot) {
return TrinketsApi.getTrinketComponent(entity)
.map(component -> component.getInventory()
.getOrDefault(slot.getNamespace(), Map.of())
.getOrDefault(slot.getPath(), null)
);
}
private Stream<TrinketInventory> 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());
}
}

View file

@ -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<EntityAttribute, EntityAttributeModifier> getModifiers(ItemStack stack, SlotReference slot, LivingEntity entity, UUID uuid) {
Multimap<EntityAttribute, EntityAttributeModifier> modifiers = Trinket.super.getModifiers(stack, slot, entity, uuid);
if (item instanceof WearableItem wearable) {
item.getAttributeModifiers(wearable.getPreferredSlot(stack));
}
return modifiers;
}
}

View file

@ -13,4 +13,13 @@ public interface InventoryUtil {
static Stream<Integer> slots(Inventory inventory) { static Stream<Integer> slots(Inventory inventory) {
return Stream.iterate(0, i -> i < inventory.size(), i -> i + 1); 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;
}
} }

View file

@ -0,0 +1,10 @@
{
"entities": [
"player"
],
"slots": [
"hand/glove",
"offhand/glove",
"chest/necklace"
]
}

View file

@ -0,0 +1,7 @@
{
"replace": false,
"values": [
"unicopia:alicorn_amulet",
"unicopia:pegasus_amulet"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"unicopia:friendship_bracelet"
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"unicopia:friendship_bracelet"
]
}