The pearl necklace now has 4 durability

This commit is contained in:
Sollace 2024-06-23 14:41:44 +01:00
parent e2f2b83003
commit 498ec2bca0
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
28 changed files with 194 additions and 86 deletions

View file

@ -10,8 +10,10 @@ import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
import com.minelittlepony.unicopia.item.UItems;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory;
@ -73,6 +75,11 @@ public class ChangeFormAbility implements Ability<Hit> {
List<Pony> targets = getTargets(player).toList();
player.subtractEnergyCost(5 * targets.size());
TrinketsDelegate.EquippedStack amulet = UItems.PEARL_NECKLACE.getForEntity(player.asEntity());
if (!amulet.stack().isEmpty()) {
amulet.stack().damage(1, player.asEntity(), amulet.breakStatusSender());
}
boolean isTransforming = player.getSuppressedRace().isUnset();
targets.forEach(target -> {
Race supressed = target.getSuppressedRace();

View file

@ -214,8 +214,8 @@ public class UHud {
boolean hasEffect = client.player.hasStatusEffect(UEffects.SUN_BLINDNESS);
ItemStack glasses = GlassesItem.getForEntity(client.player);
boolean hasSunglasses = glasses.getItem() == UItems.SUNGLASSES;
ItemStack glasses = GlassesItem.getForEntity(client.player).stack();
boolean hasSunglasses = glasses.isOf(UItems.SUNGLASSES);
if (hasEffect || (!hasSunglasses && pony.getObservedSpecies() == Race.BAT && SunBlindnessStatusEffect.hasSunExposure(client.player))) {
float i = hasEffect ? (client.player.getStatusEffect(UEffects.SUN_BLINDNESS).getDuration() - tickDelta) / SunBlindnessStatusEffect.MAX_DURATION : 0;

View file

@ -31,7 +31,7 @@ class AmuletGear extends AmuletModel implements IGear {
@Override
public boolean canRender(IModel model, Entity entity) {
return entity instanceof LivingEntity living && !AmuletItem.getForEntity(living).isEmpty();
return entity instanceof LivingEntity living && !AmuletItem.get(living).stack().isEmpty();
}
@Override
@ -41,7 +41,7 @@ class AmuletGear extends AmuletModel implements IGear {
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return textures.computeIfAbsent(Registries.ITEM.getId(AmuletItem.getForEntity((LivingEntity)entity).getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png"));
return textures.computeIfAbsent(Registries.ITEM.getId(AmuletItem.get((LivingEntity)entity).stack().getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png"));
}
@Override

View file

@ -67,8 +67,8 @@ class BangleGear implements IGear {
public void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim");
FriendshipBraceletItem.getWornBangles((LivingEntity)entity, slot).findFirst().ifPresent(bracelet -> {
color = ((DyeableItem)bracelet.getItem()).getColor(bracelet);
glowing = ((GlowableItem)bracelet.getItem()).isGlowing(bracelet);
color = ((DyeableItem)bracelet.stack().getItem()).getColor(bracelet.stack());
glowing = ((GlowableItem)bracelet.stack().getItem()).isGlowing(bracelet.stack());
});
BraceletModel m = alex ? alexModel : steveModel;
@ -76,7 +76,7 @@ class BangleGear implements IGear {
m.setAngles(biped);
}
Arm mainArm = ((LivingEntity)entity).getMainArm();
m.setVisible(slot == TrinketsDelegate.MAINHAND ? mainArm : mainArm.getOpposite());
m.setVisible(slot == TrinketsDelegate.MAIN_GLOVE ? mainArm : mainArm.getOpposite());
}
@Override

View file

@ -28,7 +28,7 @@ class GlassesGear extends GlassesModel implements IGear {
@Override
public boolean canRender(IModel model, Entity entity) {
return entity instanceof LivingEntity living && !GlassesItem.getForEntity(living).isEmpty();
return entity instanceof LivingEntity living && !GlassesItem.getForEntity(living).stack().isEmpty();
}
@Override
@ -38,7 +38,7 @@ class GlassesGear extends GlassesModel implements IGear {
@Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return textures.computeIfAbsent(Registries.ITEM.getId(GlassesItem.getForEntity((LivingEntity)entity).getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png"));
return textures.computeIfAbsent(Registries.ITEM.getId(GlassesItem.getForEntity((LivingEntity)entity).stack().getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png"));
}
@Override

View file

@ -44,8 +44,8 @@ public class Main extends MineLPDelegate implements ClientModInitializer {
public void onInitializeClient() {
INSTANCE = this;
PonyModelPrepareCallback.EVENT.register(this::onPonyModelPrepared);
IGear.register(() -> new BangleGear(TrinketsDelegate.MAINHAND));
IGear.register(() -> new BangleGear(TrinketsDelegate.OFFHAND));
IGear.register(() -> new BangleGear(TrinketsDelegate.MAIN_GLOVE));
IGear.register(() -> new BangleGear(TrinketsDelegate.SECONDARY_GLOVE));
IGear.register(HeldEntityGear::new);
IGear.register(BodyPartGear::pegasusWings);
IGear.register(BodyPartGear::batWings);

View file

@ -42,7 +42,7 @@ public class AmuletFeatureRenderer<E extends LivingEntity> 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 = AmuletItem.getForEntity(entity);
ItemStack stack = AmuletItem.get(entity).stack();
if (!stack.isEmpty()) {
Identifier texture = textures.computeIfAbsent(Registries.ITEM.getId(stack.getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png"));

View file

@ -48,11 +48,11 @@ public class BraceletFeatureRenderer<E extends LivingEntity> 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) {
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.MAIN_GLOVE).findFirst().ifPresent(bangle -> {
renderBangleThirdPerson(bangle.stack(), 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());
FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.SECONDARY_GLOVE).findFirst().ifPresent(bangle -> {
renderBangleThirdPerson(bangle.stack(), stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm().getOpposite());
});
}
@ -82,14 +82,14 @@ public class BraceletFeatureRenderer<E extends LivingEntity> implements Accessor
@Override
public void renderArm(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, E entity, ModelPart armModel, Arm side) {
FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAINHAND : TrinketsDelegate.OFFHAND).findFirst().ifPresent(item -> {
int j = ((DyeableItem)item.getItem()).getColor(item);
FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAIN_GLOVE : TrinketsDelegate.SECONDARY_GLOVE).findFirst().ifPresent(item -> {
int j = ((DyeableItem)item.stack().getItem()).getColor(item.stack());
boolean alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim");
BraceletModel model = alex ? alexModel : steveModel;
boolean glowing = ((GlowableItem)item.getItem()).isGlowing(item);
boolean glowing = ((GlowableItem)item.stack().getItem()).isGlowing(item.stack());
if (MineLPDelegate.getInstance().getPlayerPonyRace((ClientPlayerEntity)entity).isEquine()) {
stack.translate(side == Arm.LEFT ? 0.06 : -0.06, 0.3, 0);

View file

@ -36,7 +36,7 @@ public class GlassesFeatureRenderer<E extends LivingEntity> implements Accessory
@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 = GlassesItem.getForEntity(entity);
ItemStack stack = GlassesItem.getForEntity(entity).stack();
if (!stack.isEmpty()) {
Identifier texture = textures.computeIfAbsent(Registries.ITEM.getId(stack.getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png"));

View file

@ -42,7 +42,7 @@ public class PlayerPoser {
boolean liftLeftArm = mainArm == Arm.LEFT || !ponyRace.isEquine();
boolean liftRightArm = mainArm == Arm.RIGHT || !ponyRace.isEquine();
ItemStack glasses = GlassesItem.getForEntity(player);
ItemStack glasses = GlassesItem.getForEntity(player).stack();
ModelPart head = model.getHead();
if (context == Context.THIRD_PERSON && !player.isSneaking()) {

View file

@ -1,6 +1,8 @@
package com.minelittlepony.unicopia.compat.trinkets;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -16,16 +18,17 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.screen.slot.Slot;
import net.minecraft.util.Identifier;
public interface TrinketsDelegate {
Identifier MAINHAND = new Identifier("hand:glove");
Identifier OFFHAND = new Identifier("offhand:glove");
Identifier MAIN_GLOVE = new Identifier("hand:glove");
Identifier SECONDARY_GLOVE = new Identifier("offhand:glove");
Identifier NECKLACE = new Identifier("chest:necklace");
Identifier FACE = new Identifier("head:face");
Set<Identifier> ALL = new TreeSet<>(List.of(MAINHAND, OFFHAND, NECKLACE, FACE));
Set<Identifier> ALL = new TreeSet<>(List.of(MAIN_GLOVE, SECONDARY_GLOVE, NECKLACE, FACE));
TrinketsDelegate EMPTY = new TrinketsDelegate() {};
@ -61,8 +64,8 @@ public interface TrinketsDelegate {
default void setEquippedStack(LivingEntity entity, Identifier slot, ItemStack stack) {
EquipmentSlot eq = slot == FACE ? EquipmentSlot.HEAD
: slot == NECKLACE ? EquipmentSlot.CHEST
: slot == MAINHAND ? EquipmentSlot.CHEST
: slot == OFFHAND ? EquipmentSlot.OFFHAND
: slot == MAIN_GLOVE ? EquipmentSlot.CHEST
: slot == SECONDARY_GLOVE ? EquipmentSlot.OFFHAND
: null;
if (eq != null) {
entity.equipStack(eq, stack);
@ -70,19 +73,27 @@ public interface TrinketsDelegate {
}
default Set<Identifier> getAvailableTrinketSlots(LivingEntity entity, Set<Identifier> probedSlots) {
return probedSlots.stream().filter(slot -> getEquipped(entity, slot).anyMatch(ItemStack::isEmpty)).collect(Collectors.toSet());
return probedSlots.stream().filter(slot -> getEquipped(entity, slot).map(EquippedStack::stack).anyMatch(ItemStack::isEmpty)).collect(Collectors.toSet());
}
default Stream<ItemStack> getEquipped(LivingEntity entity, Identifier slot) {
default Stream<EquippedStack> getEquipped(LivingEntity entity, Identifier slot, TagKey<Item> tag) {
return getEquipped(entity, slot, stack -> stack.isIn(tag));
}
if (slot == FACE) {
return Stream.of(entity.getEquippedStack(EquipmentSlot.HEAD));
default Stream<EquippedStack> getEquipped(LivingEntity entity, Identifier slot) {
return getEquipped(entity, slot, (Predicate<ItemStack>)null);
}
default Stream<EquippedStack> getEquipped(LivingEntity entity, Identifier slot, @Nullable Predicate<ItemStack> predicate) {
if (slot == FACE && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.HEAD)))) {
return Stream.of(new EquippedStack(entity, EquipmentSlot.HEAD));
}
if (slot == NECKLACE || slot == MAINHAND) {
return Stream.of(entity.getEquippedStack(EquipmentSlot.CHEST));
if ((slot == NECKLACE || slot == MAIN_GLOVE) && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.CHEST)))) {
return Stream.of(new EquippedStack(entity, EquipmentSlot.CHEST));
}
if (slot == OFFHAND) {
return Stream.of(entity.getOffHandStack());
if (slot == SECONDARY_GLOVE && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.OFFHAND)))) {
return Stream.of(new EquippedStack(entity, EquipmentSlot.OFFHAND));
}
return Stream.empty();
@ -102,16 +113,24 @@ public interface TrinketsDelegate {
interface Inventory extends EntityConvertable<LivingEntity> {
default Stream<ItemStack> getEquippedStacks(Identifier slot) {
default Stream<EquippedStack> getEquippedStacks(Identifier slot) {
return TrinketsDelegate.getInstance(asEntity()).getEquipped(asEntity(), slot);
}
default ItemStack getEquippedStack(Identifier slot) {
return getEquippedStacks(slot).findFirst().orElse(ItemStack.EMPTY);
default EquippedStack getEquippedStack(Identifier slot) {
return getEquippedStacks(slot).findFirst().orElse(EquippedStack.EMPTY);
}
default void equipStack(Identifier slot, ItemStack stack) {
TrinketsDelegate.getInstance(asEntity()).setEquippedStack(asEntity(), slot, stack);
}
}
record EquippedStack(ItemStack stack, Runnable sendUpdate, Consumer<LivingEntity> breakStatusSender) {
public static EquippedStack EMPTY = new EquippedStack(ItemStack.EMPTY, () -> {}, l -> {});
EquippedStack(LivingEntity entity, EquipmentSlot slot) {
this(entity.getEquippedStack(slot), () -> {}, l -> l.sendEquipmentBreakStatus(slot));
}
}
}

View file

@ -1,11 +1,16 @@
package com.minelittlepony.unicopia.compat.trinkets;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.container.SpellbookScreenHandler;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgTrinketBroken;
import com.minelittlepony.unicopia.util.InventoryUtil;
import dev.emi.trinkets.TrinketSlot;
import dev.emi.trinkets.api.*;
@ -80,8 +85,16 @@ public class TrinketsDelegateImpl implements TrinketsDelegate {
}
@Override
public Stream<ItemStack> getEquipped(LivingEntity entity, Identifier slot) {
return getInventory(entity, slot).stream().flatMap(InventoryUtil::stream).filter(s -> !s.isEmpty());
public Stream<EquippedStack> getEquipped(LivingEntity entity, Identifier slot, @Nullable Predicate<ItemStack> predicate) {
return getInventory(entity, slot).stream().flatMap(inventory -> {
return InventoryUtil.stream(inventory).filter(s -> !s.isEmpty() && (predicate == null || predicate.test(s))).map(stack -> {
ItemStack oldStack = stack.copy();
return new EquippedStack(stack, inventory::markUpdate, l -> {
inventory.markUpdate();
Channel.SERVER_TRINKET_BROKEN.sendToSurroundingPlayers(new MsgTrinketBroken(oldStack, l.getId()), l);
});
});
});
}
@Override

View file

@ -147,8 +147,8 @@ public class SpellbookScreenHandler extends ScreenHandler {
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.FACE, 0, rightHandX, inventoryY + slotSpacing * 6).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.NECKLACE, 0, leftHandX, equipmentY + slotSpacing).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.MAINHAND, 0, leftHandX, equipmentY).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.OFFHAND, 0, rightHandX, equipmentY).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.MAIN_GLOVE, 0, leftHandX, equipmentY).ifPresent(this::addSlot);
TrinketsDelegate.getInstance(inv.player).createSlot(this, inv.player, TrinketsDelegate.SECONDARY_GLOVE, 0, rightHandX, equipmentY).ifPresent(this::addSlot);
addSlot(outputSlot = new OutputSlot(this, inventory.player, input, result, 0, gemPos.get(0)));

View file

@ -371,8 +371,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
}
if (magical.isIn(UTags.DamageTypes.BREAKS_SUNGLASSES)) {
ItemStack glasses = GlassesItem.getForEntity(entity);
if (glasses.getItem() == UItems.SUNGLASSES) {
ItemStack glasses = GlassesItem.getForEntity(entity).stack();
if (glasses.isOf(UItems.SUNGLASSES)) {
ItemStack broken = UItems.BROKEN_SUNGLASSES.getDefaultStack();
broken.setNbt(glasses.getNbt());
TrinketsDelegate.getInstance(entity).setEquippedStack(entity, TrinketsDelegate.FACE, broken);
@ -417,7 +417,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
return StreamSupport.stream(entity.getArmorItems().spliterator(), false);
}
return Stream.concat(
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE),
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE).map(TrinketsDelegate.EquippedStack::stack),
StreamSupport.stream(entity.getArmorItems().spliterator(), false)
);
}

View file

@ -11,7 +11,6 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.MeteorlogicalUtil;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance;
@ -72,9 +71,7 @@ public class SunBlindnessStatusEffect extends StatusEffect {
return true;
}
if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.Items.SHADES)
|| TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.Items.SHADES))
|| entity.isSubmergedInWater()) {
if (entity.isSubmergedInWater() || TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE, i -> i.isIn(UTags.Items.SHADES)).findAny().isPresent()) {
return false;
}

View file

@ -11,11 +11,11 @@ import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.AmuletSelectors;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.ai.ArenaAttackGoal;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.AmuletItem;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleSource;
@ -63,7 +63,6 @@ import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.passive.IronGolemEntity;
import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtHelper;
@ -484,9 +483,10 @@ public class SombraEntity extends HostileEntity implements ArenaCombatant, Parti
player.sendMessage(Text.translatable("entity.unicopia.sombra.taunt"));
}
}
ItemStack amulet = AmuletItem.getForEntity(player);
if (amulet.isOf(UItems.ALICORN_AMULET)) {
amulet.decrement(1);
TrinketsDelegate.EquippedStack amulet = UItems.ALICORN_AMULET.getForEntity(player);
if (!amulet.stack().isEmpty()) {
amulet.stack().decrement(1);
amulet.sendUpdate();
}
}
boolean damaged = super.damage(source, amount);

View file

@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.compat.ad_astra.OxygenApi;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.*;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck;
@ -38,12 +39,10 @@ import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBlockTags;
import net.minecraft.block.*;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LightningEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates;
@ -499,8 +498,8 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
private void tickArtificialFlight(MutableVector velocity) {
if (ticksInAir % 10 == 0 && !entity.getWorld().isClient) {
ItemStack stack = AmuletItem.getForEntity(entity);
if (ChargeableItem.getEnergy(stack) < 9) {
TrinketsDelegate.EquippedStack stack = AmuletItem.get(entity);
if (ChargeableItem.getEnergy(stack.stack()) < 9) {
playSound(USounds.ITEM_ICARUS_WINGS_WARN, 0.13F, 0.5F);
}
@ -517,10 +516,10 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
minDamage *= 3;
}
ChargeableItem.consumeEnergy(stack, energyConsumed);
ChargeableItem.consumeEnergy(stack.stack(), energyConsumed);
if (entity.getWorld().random.nextInt(damageInterval) == 0) {
stack.damage(minDamage + entity.getWorld().random.nextInt(50), entity, e -> e.sendEquipmentBreakStatus(EquipmentSlot.CHEST));
stack.stack().damage(minDamage + entity.getWorld().random.nextInt(50), (LivingEntity)entity, stack.breakStatusSender());
}
if (!lastFlightType.canFly()) {

View file

@ -484,6 +484,9 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
AmuletSelectors.PEARL_NECKLACE.test(entity) ? suppressedRace.or(Race.SEAPONY) : null
);
UCriteria.PLAYER_CHANGE_RACE.trigger(entity);
var hasNecklace = AmuletSelectors.PEARL_NECKLACE.test(entity);
System.out.println(hasNecklace);
}
@Override
@ -526,7 +529,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
if (getObservedSpecies() == Race.BAT && !entity.hasPortalCooldown()) {
boolean hasShades = TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.isIn(UTags.Items.SHADES));
boolean hasShades = TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(s -> s.stack().isIn(UTags.Items.SHADES));
if (!this.hasShades && hasShades && getObservedSpecies() == Race.BAT) {
UCriteria.WEAR_SHADES.trigger(entity);
}

View file

@ -247,7 +247,7 @@ public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackab
// bind to the player after 3 days
if (daysAttached >= 3 && !pony.asEntity().isCreative()) {
stack = living.getArmour().getEquippedStack(TrinketsDelegate.NECKLACE);
stack = living.getArmour().getEquippedStack(TrinketsDelegate.NECKLACE).stack();
if (stack.getItem() == this && !EnchantmentHelper.hasBindingCurse(stack)) {
pony.playSound(USounds.ITEM_ALICORN_AMULET_HALLUCINATION, 3, 1);
stack = stack.copy();

View file

@ -86,7 +86,13 @@ public class AmuletItem extends WearableItem implements ChargeableItem {
}
public final boolean isApplicable(LivingEntity entity) {
return isApplicable(getForEntity(entity));
return !getForEntity(entity).stack().isEmpty();
}
public TrinketsDelegate.EquippedStack getForEntity(LivingEntity entity) {
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE, this::isApplicable)
.findFirst()
.orElse(TrinketsDelegate.EquippedStack.EMPTY);
}
@Override
@ -94,11 +100,10 @@ public class AmuletItem extends WearableItem implements ChargeableItem {
return maxEnergy;
}
public static ItemStack getForEntity(LivingEntity entity) {
public static TrinketsDelegate.EquippedStack get(LivingEntity entity) {
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.NECKLACE)
.filter(stack -> stack.getItem() instanceof AmuletItem)
.findFirst()
.orElse(ItemStack.EMPTY);
.orElse(TrinketsDelegate.EquippedStack.EMPTY);
}
public static class ModifiersBuilder {

View file

@ -69,7 +69,7 @@ public class BellItem extends Item implements ChargeableItem {
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand);
ItemStack offhandStack = AmuletItem.getForEntity(player);
ItemStack offhandStack = AmuletItem.get(player).stack();
if (!(offhandStack.getItem() instanceof ChargeableItem)) {
offhandStack = player.getStackInHand(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND);

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.item;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
@ -120,28 +121,36 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem,
public static boolean isComrade(Owned<?> caster, Entity entity) {
return entity instanceof LivingEntity l && caster.getMasterId()
.filter(id -> getWornBangles(l).anyMatch(stack -> isSignedBy(stack, id)))
.filter(id -> getWornBangles(l).anyMatch(stack -> isSignedBy(stack.stack(), id)))
.isPresent();
}
public static boolean isComrade(UUID signator, Entity entity) {
return entity instanceof LivingEntity l && getWornBangles(l).anyMatch(stack -> isSignedBy(stack, signator));
return entity instanceof LivingEntity l && getWornBangles(l, stack -> isSignedBy(stack, signator)).findAny().isPresent();
}
public static Stream<Pony> getPartyMembers(Caster<?> caster, double radius) {
return Pony.stream(caster.findAllEntitiesInRange(radius, entity -> isComrade(caster, entity)));
}
public static Stream<ItemStack> getWornBangles(LivingEntity entity) {
private static final Predicate<ItemStack> IS_BANGLE = stack -> stack.isOf(UItems.FRIENDSHIP_BRACELET);
public static Stream<TrinketsDelegate.EquippedStack> getWornBangles(LivingEntity entity) {
return Stream.concat(
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAINHAND),
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.OFFHAND)
).filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET);
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAIN_GLOVE, IS_BANGLE),
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.SECONDARY_GLOVE, IS_BANGLE)
);
}
public static Stream<ItemStack> getWornBangles(LivingEntity entity, Identifier slot) {
return TrinketsDelegate.getInstance(entity)
.getEquipped(entity, slot)
.filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET);
public static Stream<TrinketsDelegate.EquippedStack> getWornBangles(LivingEntity entity, @Nullable Predicate<ItemStack> predicate) {
predicate = predicate == null ? IS_BANGLE : IS_BANGLE.and(predicate);
return Stream.concat(
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAIN_GLOVE, predicate),
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.SECONDARY_GLOVE, predicate)
);
}
public static Stream<TrinketsDelegate.EquippedStack> getWornBangles(LivingEntity entity, Identifier slot) {
return TrinketsDelegate.getInstance(entity).getEquipped(entity, slot, IS_BANGLE);
}
}

View file

@ -25,13 +25,12 @@ public class GlassesItem extends WearableItem {
}
public boolean isApplicable(LivingEntity entity) {
return getForEntity(entity).getItem() == this;
return getForEntity(entity).stack().isOf(this);
}
public static ItemStack getForEntity(LivingEntity entity) {
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE)
.filter(stack -> stack.getItem() instanceof GlassesItem)
public static TrinketsDelegate.EquippedStack getForEntity(LivingEntity entity) {
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE, stack -> stack.getItem() instanceof GlassesItem)
.findFirst()
.orElse(ItemStack.EMPTY);
.orElse(TrinketsDelegate.EquippedStack.EMPTY);
}
}

View file

@ -25,11 +25,6 @@ public class PegasusAmuletItem extends AmuletItem implements ItemTracker.Trackab
}
@Override
public boolean isApplicable(ItemStack stack) {
return super.isApplicable(stack);
}
@Override
public int getDefaultCharge() {
return getMaxCharge() / 2;

View file

@ -220,6 +220,7 @@ public interface UItems {
.rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS);
AmuletItem PEARL_NECKLACE = register("pearl_necklace", new AmuletItem(new FabricItemSettings()
.maxCount(1)
.maxDamage(4)
.rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS);
GlassesItem SUNGLASSES = register("sunglasses", new GlassesItem(new FabricItemSettings().maxCount(1)), ItemGroups.COMBAT);

View file

@ -37,6 +37,7 @@ public interface Channel {
S2CPacketType<MsgSkyAngle> SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new);
S2CPacketType<MsgConfigurationChange> CONFIGURATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("config"), MsgConfigurationChange::new);
S2CPacketType<MsgZapAppleStage> SERVER_ZAP_STAGE = SimpleNetworking.serverToClient(Unicopia.id("zap_stage"), MsgZapAppleStage::new);
S2CPacketType<MsgTrinketBroken> SERVER_TRINKET_BROKEN = SimpleNetworking.serverToClient(Unicopia.id("trinket_broken"), MsgTrinketBroken::new);
static void bootstrap() {
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {

View file

@ -0,0 +1,22 @@
package com.minelittlepony.unicopia.network;
import com.sollace.fabwork.api.packets.Packet;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
/**
* Sent to the client when an item equipped in a trinket slot breaks
*/
public record MsgTrinketBroken (ItemStack stack, int entityId) implements Packet<PlayerEntity> {
public MsgTrinketBroken(PacketByteBuf buffer) {
this(buffer.readItemStack(), buffer.readInt());
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeItemStack(stack);
buffer.writeInt(entityId);
}
}

View file

@ -20,8 +20,14 @@ import com.minelittlepony.unicopia.network.*;
import com.minelittlepony.unicopia.network.MsgCasterLookRequest.Reply;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.particle.ItemStackParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
public class ClientNetworkHandlerImpl {
private final MinecraftClient client = MinecraftClient.getInstance();
@ -36,6 +42,7 @@ public class ClientNetworkHandlerImpl {
Channel.SERVER_ZAP_STAGE.receiver().addPersistentListener(this::handleZapStage);
Channel.SERVER_PLAYER_ANIMATION_CHANGE.receiver().addPersistentListener(this::handlePlayerAnimation);
Channel.SERVER_REQUEST_PLAYER_LOOK.receiver().addPersistentListener(this::handleCasterLookRequest);
Channel.SERVER_TRINKET_BROKEN.receiver().addPersistentListener(this::handleTrinketBroken);
Channel.CONFIGURATION_CHANGE.receiver().addPersistentListener(this::handleConfigurationChange);
}
@ -96,6 +103,37 @@ public class ClientNetworkHandlerImpl {
Channel.CLIENT_CASTER_LOOK.sendToServer(new Reply(packet.spellId(), Rot.of(player)));
}
private void handleTrinketBroken(PlayerEntity player, MsgTrinketBroken packet) {
if (player.getWorld().getEntityById(packet.entityId()) instanceof LivingEntity sender) {
ItemStack stack = packet.stack();
if (!stack.isEmpty()) {
if (!sender.isSilent()) {
sender.getWorld().playSound(
sender.getX(), sender.getY(), sender.getZ(),
SoundEvents.ENTITY_ITEM_BREAK, sender.getSoundCategory(),
0.8F,
0.8F + sender.getWorld().random.nextFloat() * 0.4F,
false
);
}
int count = 5;
for (int i = 0; i < count; ++i) {
Vec3d vec3d = new Vec3d((sender.getWorld().random.nextFloat() - 0.5) * 0.1, Math.random() * 0.1 + 0.1, 0.0);
vec3d = vec3d.rotateX(-sender.getPitch() * (float) (Math.PI / 180.0));
vec3d = vec3d.rotateY(-sender.getYaw() * (float) (Math.PI / 180.0));
double d = (-sender.getWorld().random.nextFloat()) * 0.6 - 0.3;
Vec3d vec3d2 = new Vec3d((sender.getWorld().random.nextFloat() - 0.5) * 0.3, d, 0.6);
vec3d2 = vec3d2.rotateX(-sender.getPitch() * (float) (Math.PI / 180.0));
vec3d2 = vec3d2.rotateY(-sender.getYaw() * (float) (Math.PI / 180.0));
vec3d2 = vec3d2.add(sender.getX(), sender.getEyeY(), sender.getZ());
sender.getWorld().addParticle(new ItemStackParticleEffect(ParticleTypes.ITEM, stack), vec3d2.x, vec3d2.y, vec3d2.z, vec3d.x, vec3d.y + 0.05, vec3d.z);
}
}
}
}
private void handleConfigurationChange(PlayerEntity sender, MsgConfigurationChange packet) {
InteractionManager.getInstance().setSyncedConfig(packet.config());
}