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.USounds;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem; import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
import com.minelittlepony.unicopia.item.UItems;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
@ -73,6 +75,11 @@ public class ChangeFormAbility implements Ability<Hit> {
List<Pony> targets = getTargets(player).toList(); List<Pony> targets = getTargets(player).toList();
player.subtractEnergyCost(5 * targets.size()); 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(); boolean isTransforming = player.getSuppressedRace().isUnset();
targets.forEach(target -> { targets.forEach(target -> {
Race supressed = target.getSuppressedRace(); Race supressed = target.getSuppressedRace();

View file

@ -214,8 +214,8 @@ public class UHud {
boolean hasEffect = client.player.hasStatusEffect(UEffects.SUN_BLINDNESS); boolean hasEffect = client.player.hasStatusEffect(UEffects.SUN_BLINDNESS);
ItemStack glasses = GlassesItem.getForEntity(client.player); ItemStack glasses = GlassesItem.getForEntity(client.player).stack();
boolean hasSunglasses = glasses.getItem() == UItems.SUNGLASSES; boolean hasSunglasses = glasses.isOf(UItems.SUNGLASSES);
if (hasEffect || (!hasSunglasses && pony.getObservedSpecies() == Race.BAT && SunBlindnessStatusEffect.hasSunExposure(client.player))) { 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; 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 @Override
public boolean canRender(IModel model, Entity entity) { 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 @Override
@ -41,7 +41,7 @@ class AmuletGear extends AmuletModel implements IGear {
@Override @Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) { 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 @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) { 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"); alex = entity instanceof ClientPlayerEntity && ((ClientPlayerEntity)entity).getModel().startsWith("slim");
FriendshipBraceletItem.getWornBangles((LivingEntity)entity, slot).findFirst().ifPresent(bracelet -> { FriendshipBraceletItem.getWornBangles((LivingEntity)entity, slot).findFirst().ifPresent(bracelet -> {
color = ((DyeableItem)bracelet.getItem()).getColor(bracelet); color = ((DyeableItem)bracelet.stack().getItem()).getColor(bracelet.stack());
glowing = ((GlowableItem)bracelet.getItem()).isGlowing(bracelet); glowing = ((GlowableItem)bracelet.stack().getItem()).isGlowing(bracelet.stack());
}); });
BraceletModel m = alex ? alexModel : steveModel; BraceletModel m = alex ? alexModel : steveModel;
@ -76,7 +76,7 @@ class BangleGear implements IGear {
m.setAngles(biped); m.setAngles(biped);
} }
Arm mainArm = ((LivingEntity)entity).getMainArm(); Arm mainArm = ((LivingEntity)entity).getMainArm();
m.setVisible(slot == TrinketsDelegate.MAINHAND ? mainArm : mainArm.getOpposite()); m.setVisible(slot == TrinketsDelegate.MAIN_GLOVE ? mainArm : mainArm.getOpposite());
} }
@Override @Override

View file

@ -28,7 +28,7 @@ class GlassesGear extends GlassesModel implements IGear {
@Override @Override
public boolean canRender(IModel model, Entity entity) { 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 @Override
@ -38,7 +38,7 @@ class GlassesGear extends GlassesModel implements IGear {
@Override @Override
public <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) { 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 @Override

View file

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

View file

@ -42,7 +42,7 @@ 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 = AmuletItem.getForEntity(entity); ItemStack stack = AmuletItem.get(entity).stack();
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
Identifier texture = textures.computeIfAbsent(Registries.ITEM.getId(stack.getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); 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 @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) {
FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.MAINHAND).findFirst().ifPresent(bangle -> { FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.MAIN_GLOVE).findFirst().ifPresent(bangle -> {
renderBangleThirdPerson(bangle, stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm()); renderBangleThirdPerson(bangle.stack(), stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm());
}); });
FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.OFFHAND).findFirst().ifPresent(bangle -> { FriendshipBraceletItem.getWornBangles(entity, TrinketsDelegate.SECONDARY_GLOVE).findFirst().ifPresent(bangle -> {
renderBangleThirdPerson(bangle, stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch, entity.getMainArm().getOpposite()); 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 @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) {
FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAINHAND : TrinketsDelegate.OFFHAND).findFirst().ifPresent(item -> { FriendshipBraceletItem.getWornBangles(entity, side == entity.getMainArm() ? TrinketsDelegate.MAIN_GLOVE : TrinketsDelegate.SECONDARY_GLOVE).findFirst().ifPresent(item -> {
int j = ((DyeableItem)item.getItem()).getColor(item); int j = ((DyeableItem)item.stack().getItem()).getColor(item.stack());
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 glowing = ((GlowableItem)item.getItem()).isGlowing(item); boolean glowing = ((GlowableItem)item.stack().getItem()).isGlowing(item.stack());
if (MineLPDelegate.getInstance().getPlayerPonyRace((ClientPlayerEntity)entity).isEquine()) { if (MineLPDelegate.getInstance().getPlayerPonyRace((ClientPlayerEntity)entity).isEquine()) {
stack.translate(side == Arm.LEFT ? 0.06 : -0.06, 0.3, 0); 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 @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 = GlassesItem.getForEntity(entity); ItemStack stack = GlassesItem.getForEntity(entity).stack();
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
Identifier texture = textures.computeIfAbsent(Registries.ITEM.getId(stack.getItem()), id -> new Identifier(id.getNamespace(), "textures/models/armor/" + id.getPath() + ".png")); 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 liftLeftArm = mainArm == Arm.LEFT || !ponyRace.isEquine();
boolean liftRightArm = mainArm == Arm.RIGHT || !ponyRace.isEquine(); boolean liftRightArm = mainArm == Arm.RIGHT || !ponyRace.isEquine();
ItemStack glasses = GlassesItem.getForEntity(player); ItemStack glasses = GlassesItem.getForEntity(player).stack();
ModelPart head = model.getHead(); ModelPart head = model.getHead();
if (context == Context.THIRD_PERSON && !player.isSneaking()) { if (context == Context.THIRD_PERSON && !player.isSneaking()) {

View file

@ -1,6 +1,8 @@
package com.minelittlepony.unicopia.compat.trinkets; package com.minelittlepony.unicopia.compat.trinkets;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -16,16 +18,17 @@ import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public interface TrinketsDelegate { public interface TrinketsDelegate {
Identifier MAINHAND = new Identifier("hand:glove"); Identifier MAIN_GLOVE = new Identifier("hand:glove");
Identifier OFFHAND = new Identifier("offhand:glove"); Identifier SECONDARY_GLOVE = new Identifier("offhand:glove");
Identifier NECKLACE = new Identifier("chest:necklace"); Identifier NECKLACE = new Identifier("chest:necklace");
Identifier FACE = new Identifier("head:face"); 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() {}; TrinketsDelegate EMPTY = new TrinketsDelegate() {};
@ -61,8 +64,8 @@ public interface TrinketsDelegate {
default void setEquippedStack(LivingEntity entity, Identifier slot, ItemStack stack) { default void setEquippedStack(LivingEntity entity, Identifier slot, ItemStack stack) {
EquipmentSlot eq = slot == FACE ? EquipmentSlot.HEAD EquipmentSlot eq = slot == FACE ? EquipmentSlot.HEAD
: slot == NECKLACE ? EquipmentSlot.CHEST : slot == NECKLACE ? EquipmentSlot.CHEST
: slot == MAINHAND ? EquipmentSlot.CHEST : slot == MAIN_GLOVE ? EquipmentSlot.CHEST
: slot == OFFHAND ? EquipmentSlot.OFFHAND : slot == SECONDARY_GLOVE ? EquipmentSlot.OFFHAND
: null; : null;
if (eq != null) { if (eq != null) {
entity.equipStack(eq, stack); entity.equipStack(eq, stack);
@ -70,19 +73,27 @@ public interface TrinketsDelegate {
} }
default Set<Identifier> getAvailableTrinketSlots(LivingEntity entity, Set<Identifier> probedSlots) { 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) { default Stream<EquippedStack> getEquipped(LivingEntity entity, Identifier slot) {
return Stream.of(entity.getEquippedStack(EquipmentSlot.HEAD)); 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) { if ((slot == NECKLACE || slot == MAIN_GLOVE) && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.CHEST)))) {
return Stream.of(entity.getEquippedStack(EquipmentSlot.CHEST)); return Stream.of(new EquippedStack(entity, EquipmentSlot.CHEST));
} }
if (slot == OFFHAND) { if (slot == SECONDARY_GLOVE && (predicate == null || predicate.test(entity.getEquippedStack(EquipmentSlot.OFFHAND)))) {
return Stream.of(entity.getOffHandStack()); return Stream.of(new EquippedStack(entity, EquipmentSlot.OFFHAND));
} }
return Stream.empty(); return Stream.empty();
@ -102,16 +113,24 @@ public interface TrinketsDelegate {
interface Inventory extends EntityConvertable<LivingEntity> { interface Inventory extends EntityConvertable<LivingEntity> {
default Stream<ItemStack> getEquippedStacks(Identifier slot) { default Stream<EquippedStack> getEquippedStacks(Identifier slot) {
return TrinketsDelegate.getInstance(asEntity()).getEquipped(asEntity(), slot); return TrinketsDelegate.getInstance(asEntity()).getEquipped(asEntity(), slot);
} }
default ItemStack getEquippedStack(Identifier slot) { default EquippedStack getEquippedStack(Identifier slot) {
return getEquippedStacks(slot).findFirst().orElse(ItemStack.EMPTY); return getEquippedStacks(slot).findFirst().orElse(EquippedStack.EMPTY);
} }
default void equipStack(Identifier slot, ItemStack stack) { default void equipStack(Identifier slot, ItemStack stack) {
TrinketsDelegate.getInstance(asEntity()).setEquippedStack(asEntity(), slot, 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; package com.minelittlepony.unicopia.compat.trinkets;
import java.util.*; import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.container.SpellbookScreenHandler; import com.minelittlepony.unicopia.container.SpellbookScreenHandler;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments; 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 com.minelittlepony.unicopia.util.InventoryUtil;
import dev.emi.trinkets.TrinketSlot; import dev.emi.trinkets.TrinketSlot;
import dev.emi.trinkets.api.*; import dev.emi.trinkets.api.*;
@ -80,8 +85,16 @@ public class TrinketsDelegateImpl implements TrinketsDelegate {
} }
@Override @Override
public Stream<ItemStack> getEquipped(LivingEntity entity, Identifier slot) { public Stream<EquippedStack> getEquipped(LivingEntity entity, Identifier slot, @Nullable Predicate<ItemStack> predicate) {
return getInventory(entity, slot).stream().flatMap(InventoryUtil::stream).filter(s -> !s.isEmpty()); 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 @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.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.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.MAIN_GLOVE, 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.SECONDARY_GLOVE, 0, rightHandX, equipmentY).ifPresent(this::addSlot);
addSlot(outputSlot = new OutputSlot(this, inventory.player, input, result, 0, gemPos.get(0))); 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)) { if (magical.isIn(UTags.DamageTypes.BREAKS_SUNGLASSES)) {
ItemStack glasses = GlassesItem.getForEntity(entity); ItemStack glasses = GlassesItem.getForEntity(entity).stack();
if (glasses.getItem() == UItems.SUNGLASSES) { if (glasses.isOf(UItems.SUNGLASSES)) {
ItemStack broken = UItems.BROKEN_SUNGLASSES.getDefaultStack(); ItemStack broken = UItems.BROKEN_SUNGLASSES.getDefaultStack();
broken.setNbt(glasses.getNbt()); broken.setNbt(glasses.getNbt());
TrinketsDelegate.getInstance(entity).setEquippedStack(entity, TrinketsDelegate.FACE, broken); 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 StreamSupport.stream(entity.getArmorItems().spliterator(), false);
} }
return Stream.concat( 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) 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 com.minelittlepony.unicopia.util.MeteorlogicalUtil;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffectInstance;
@ -72,9 +71,7 @@ public class SunBlindnessStatusEffect extends StatusEffect {
return true; return true;
} }
if (entity.getEquippedStack(EquipmentSlot.HEAD).isIn(UTags.Items.SHADES) if (entity.isSubmergedInWater() || TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE, i -> i.isIn(UTags.Items.SHADES)).findAny().isPresent()) {
|| TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE).anyMatch(i -> i.isIn(UTags.Items.SHADES))
|| entity.isSubmergedInWater()) {
return false; return false;
} }

View file

@ -11,11 +11,11 @@ import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
import com.minelittlepony.unicopia.advancement.UCriteria; import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.entity.AmuletSelectors; import com.minelittlepony.unicopia.entity.AmuletSelectors;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.ai.ArenaAttackGoal; import com.minelittlepony.unicopia.entity.ai.ArenaAttackGoal;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.AmuletItem;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleSource; 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.IronGolemEntity;
import net.minecraft.entity.passive.MerchantEntity; import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtHelper; 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")); player.sendMessage(Text.translatable("entity.unicopia.sombra.taunt"));
} }
} }
ItemStack amulet = AmuletItem.getForEntity(player); TrinketsDelegate.EquippedStack amulet = UItems.ALICORN_AMULET.getForEntity(player);
if (amulet.isOf(UItems.ALICORN_AMULET)) { if (!amulet.stack().isEmpty()) {
amulet.decrement(1); amulet.stack().decrement(1);
amulet.sendUpdate();
} }
} }
boolean damaged = super.damage(source, amount); 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.minelittlepony.MineLPDelegate;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation; import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.compat.ad_astra.OxygenApi; 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.*;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; 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.block.*;
import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LightningEntity; import net.minecraft.entity.LightningEntity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.predicate.entity.EntityPredicates;
@ -499,8 +498,8 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
private void tickArtificialFlight(MutableVector velocity) { private void tickArtificialFlight(MutableVector velocity) {
if (ticksInAir % 10 == 0 && !entity.getWorld().isClient) { if (ticksInAir % 10 == 0 && !entity.getWorld().isClient) {
ItemStack stack = AmuletItem.getForEntity(entity); TrinketsDelegate.EquippedStack stack = AmuletItem.get(entity);
if (ChargeableItem.getEnergy(stack) < 9) { if (ChargeableItem.getEnergy(stack.stack()) < 9) {
playSound(USounds.ITEM_ICARUS_WINGS_WARN, 0.13F, 0.5F); playSound(USounds.ITEM_ICARUS_WINGS_WARN, 0.13F, 0.5F);
} }
@ -517,10 +516,10 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
minDamage *= 3; minDamage *= 3;
} }
ChargeableItem.consumeEnergy(stack, energyConsumed); ChargeableItem.consumeEnergy(stack.stack(), energyConsumed);
if (entity.getWorld().random.nextInt(damageInterval) == 0) { 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()) { 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 AmuletSelectors.PEARL_NECKLACE.test(entity) ? suppressedRace.or(Race.SEAPONY) : null
); );
UCriteria.PLAYER_CHANGE_RACE.trigger(entity); UCriteria.PLAYER_CHANGE_RACE.trigger(entity);
var hasNecklace = AmuletSelectors.PEARL_NECKLACE.test(entity);
System.out.println(hasNecklace);
} }
@Override @Override
@ -526,7 +529,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
} }
if (getObservedSpecies() == Race.BAT && !entity.hasPortalCooldown()) { 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) { if (!this.hasShades && hasShades && getObservedSpecies() == Race.BAT) {
UCriteria.WEAR_SHADES.trigger(entity); 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 // bind to the player after 3 days
if (daysAttached >= 3 && !pony.asEntity().isCreative()) { 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)) { if (stack.getItem() == this && !EnchantmentHelper.hasBindingCurse(stack)) {
pony.playSound(USounds.ITEM_ALICORN_AMULET_HALLUCINATION, 3, 1); pony.playSound(USounds.ITEM_ALICORN_AMULET_HALLUCINATION, 3, 1);
stack = stack.copy(); stack = stack.copy();

View file

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

View file

@ -69,7 +69,7 @@ public class BellItem extends Item implements ChargeableItem {
@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);
ItemStack offhandStack = AmuletItem.getForEntity(player); ItemStack offhandStack = AmuletItem.get(player).stack();
if (!(offhandStack.getItem() instanceof ChargeableItem)) { if (!(offhandStack.getItem() instanceof ChargeableItem)) {
offhandStack = player.getStackInHand(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND); 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.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -120,28 +121,36 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem,
public static boolean isComrade(Owned<?> caster, Entity entity) { public static boolean isComrade(Owned<?> caster, Entity entity) {
return entity instanceof LivingEntity l && caster.getMasterId() 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(); .isPresent();
} }
public static boolean isComrade(UUID signator, Entity entity) { 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) { 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) { private static final Predicate<ItemStack> IS_BANGLE = stack -> stack.isOf(UItems.FRIENDSHIP_BRACELET);
public static Stream<TrinketsDelegate.EquippedStack> getWornBangles(LivingEntity entity) {
return Stream.concat( return Stream.concat(
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAINHAND), TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.MAIN_GLOVE, IS_BANGLE),
TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.OFFHAND) TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.SECONDARY_GLOVE, IS_BANGLE)
).filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET); );
} }
public static Stream<ItemStack> getWornBangles(LivingEntity entity, Identifier slot) { public static Stream<TrinketsDelegate.EquippedStack> getWornBangles(LivingEntity entity, @Nullable Predicate<ItemStack> predicate) {
return TrinketsDelegate.getInstance(entity) predicate = predicate == null ? IS_BANGLE : IS_BANGLE.and(predicate);
.getEquipped(entity, slot) return Stream.concat(
.filter(stack -> stack.getItem() == UItems.FRIENDSHIP_BRACELET); 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) { public boolean isApplicable(LivingEntity entity) {
return getForEntity(entity).getItem() == this; return getForEntity(entity).stack().isOf(this);
} }
public static ItemStack getForEntity(LivingEntity entity) { public static TrinketsDelegate.EquippedStack getForEntity(LivingEntity entity) {
return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE) return TrinketsDelegate.getInstance(entity).getEquipped(entity, TrinketsDelegate.FACE, stack -> stack.getItem() instanceof GlassesItem)
.filter(stack -> stack.getItem() instanceof GlassesItem)
.findFirst() .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 @Override
public int getDefaultCharge() { public int getDefaultCharge() {
return getMaxCharge() / 2; return getMaxCharge() / 2;

View file

@ -220,6 +220,7 @@ public interface UItems {
.rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS); .rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS);
AmuletItem PEARL_NECKLACE = register("pearl_necklace", new AmuletItem(new FabricItemSettings() AmuletItem PEARL_NECKLACE = register("pearl_necklace", new AmuletItem(new FabricItemSettings()
.maxCount(1) .maxCount(1)
.maxDamage(4)
.rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS); .rarity(Rarity.UNCOMMON), 0), ItemGroups.TOOLS);
GlassesItem SUNGLASSES = register("sunglasses", new GlassesItem(new FabricItemSettings().maxCount(1)), ItemGroups.COMBAT); 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<MsgSkyAngle> SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new);
S2CPacketType<MsgConfigurationChange> CONFIGURATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("config"), MsgConfigurationChange::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<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() { static void bootstrap() {
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { 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 com.minelittlepony.unicopia.network.MsgCasterLookRequest.Reply;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; 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.Identifier;
import net.minecraft.util.math.Vec3d;
public class ClientNetworkHandlerImpl { public class ClientNetworkHandlerImpl {
private final MinecraftClient client = MinecraftClient.getInstance(); private final MinecraftClient client = MinecraftClient.getInstance();
@ -36,6 +42,7 @@ public class ClientNetworkHandlerImpl {
Channel.SERVER_ZAP_STAGE.receiver().addPersistentListener(this::handleZapStage); Channel.SERVER_ZAP_STAGE.receiver().addPersistentListener(this::handleZapStage);
Channel.SERVER_PLAYER_ANIMATION_CHANGE.receiver().addPersistentListener(this::handlePlayerAnimation); Channel.SERVER_PLAYER_ANIMATION_CHANGE.receiver().addPersistentListener(this::handlePlayerAnimation);
Channel.SERVER_REQUEST_PLAYER_LOOK.receiver().addPersistentListener(this::handleCasterLookRequest); Channel.SERVER_REQUEST_PLAYER_LOOK.receiver().addPersistentListener(this::handleCasterLookRequest);
Channel.SERVER_TRINKET_BROKEN.receiver().addPersistentListener(this::handleTrinketBroken);
Channel.CONFIGURATION_CHANGE.receiver().addPersistentListener(this::handleConfigurationChange); 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))); 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) { private void handleConfigurationChange(PlayerEntity sender, MsgConfigurationChange packet) {
InteractionManager.getInstance().setSyncedConfig(packet.config()); InteractionManager.getInstance().setSyncedConfig(packet.config());
} }