From bc01a8a82415091e447277e0b7e63289c2c9fa7e Mon Sep 17 00:00:00 2001 From: Sollace Date: Fri, 9 Dec 2022 20:45:49 +0000 Subject: [PATCH] Allow all entities to get the effects of wearing an alicorn amulet and not just the player --- .../unicopia/entity/ItemTracker.java | 80 ++++++++++++++++ .../unicopia/entity/Living.java | 25 +++++ .../entity/player/PlayerCharmTracker.java | 89 +----------------- .../unicopia/entity/player/Pony.java | 4 +- .../unicopia/item/AlicornAmuletItem.java | 91 +++++++++---------- .../unicopia/item/PegasusAmuletItem.java | 14 +-- 6 files changed, 156 insertions(+), 147 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java new file mode 100644 index 00000000..4e3c4338 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/ItemTracker.java @@ -0,0 +1,80 @@ +package com.minelittlepony.unicopia.entity; + +import java.util.*; +import java.util.stream.Stream; + +import com.minelittlepony.unicopia.util.NbtSerialisable; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemConvertible; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +public class ItemTracker implements NbtSerialisable { + public static final long TICKS = 1; + public static final long SECONDS = 20 * TICKS; + public static final long HOURS = 1000 * TICKS; + public static final long DAYS = 24 * HOURS; + + private final Map items = new HashMap<>(); + + public void update(Living living, Stream stacks) { + final Set found = new HashSet<>(); + final Set foundStacks = new HashSet<>(); + stacks.forEach(stack -> { + if (stack.getItem() instanceof Trackable trackable) { + items.compute(trackable, (item, prev) -> prev == null ? 1 : prev + 1); + found.add(trackable); + foundStacks.add(stack); + } + }); + items.entrySet().removeIf(e -> { + if (!found.contains(e.getKey())) { + e.getKey().onUnequipped(living, e.getValue()); + return true; + } + return false; + }); + + if (!(living.getEntity() instanceof PlayerEntity)) { + foundStacks.forEach(stack -> { + if (getTicks((Trackable)stack.getItem()) == 1) { + stack.inventoryTick(living.getReferenceWorld(), living.getEntity(), 0, false); + } + }); + } + } + + public long getTicks(Trackable charm) { + return items.getOrDefault(charm.asItem(), 0L); + } + + public boolean contains(Trackable charm) { + return getTicks(charm) > 0; + } + + @Override + public void toNBT(NbtCompound compound) { + items.forEach((charm, count) -> { + compound.putLong(Registry.ITEM.getId(charm.asItem()).toString(), count); + }); + } + + @Override + public void fromNBT(NbtCompound compound) { + items.clear(); + compound.getKeys().stream().map(Identifier::tryParse) + .filter(Objects::nonNull) + .map(id -> Map.entry(Registry.ITEM.get(id), compound.getLong(id.toString()))) + .filter(i -> i.getKey() instanceof Trackable && i.getValue() > 0) + .forEach(item -> items.put((Trackable)item.getKey(), item.getValue())); + } + + public interface Trackable extends ItemConvertible { + void onUnequipped(Living living, long timeWorn); + + void onEquipped(Living living); + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 1feb82b4..007ede28 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.entity; import java.util.Optional; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -59,6 +60,8 @@ public abstract class Living implements Equine, Caste private final Enchantments enchants = new Enchantments(this); + private final ItemTracker armour = new ItemTracker(); + protected Living(T entity, TrackedData effect) { this.entity = entity; this.effectDelegate = new EffectSync(this, effect); @@ -91,6 +94,10 @@ public abstract class Living implements Equine, Caste return enchants; } + public ItemTracker getArmour() { + return armour; + } + @Override public void setMaster(T owner) { } @@ -103,6 +110,8 @@ public abstract class Living implements Equine, Caste @Override public void tick() { + armour.update(this, getArmourStacks()); + try { getSpellSlot().forEach(spell -> Operation.ofBoolean(spell.tick(this, Situation.BODY)), entity.world.isClient); } catch (Exception e) { @@ -217,6 +226,16 @@ public abstract class Living implements Equine, Caste return Stream.of(entity.getStackInHand(Hand.MAIN_HAND), entity.getStackInHand(Hand.OFF_HAND)); } + protected Stream getArmourStacks() { + if (!TrinketsDelegate.hasTrinkets()) { + return StreamSupport.stream(entity.getArmorItems().spliterator(), false); + } + return Stream.concat( + TrinketsDelegate.getInstance().getEquipped(entity, TrinketsDelegate.NECKLACE), + StreamSupport.stream(entity.getArmorItems().spliterator(), false) + ); + } + protected void giveBackItem(ItemStack stack) { entity.dropStack(stack); } @@ -240,18 +259,24 @@ public abstract class Living implements Equine, Caste public void toNBT(NbtCompound compound) { enchants.toNBT(compound); effectDelegate.toNBT(compound); + compound.put("armour", armour.toNBT()); } @Override public void fromNBT(NbtCompound compound) { enchants.fromNBT(compound); effectDelegate.fromNBT(compound); + armour.fromNBT(compound.getCompound("armour")); } public void updateVelocity() { updateVelocity(entity); } + public static Living living(Entity entity) { + return PonyContainer.of(entity).map(a -> a instanceof Living ? (Living)a.get() : null).orElse(null); + } + public static void updateVelocity(Entity entity) { entity.velocityModified = true; //if (entity instanceof ServerPlayerEntity ply) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java index 3db6efc8..53afef2d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCharmTracker.java @@ -1,38 +1,22 @@ package com.minelittlepony.unicopia.entity.player; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Stream; - import com.google.common.collect.Streams; -import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.item.GemstoneItem; -import com.minelittlepony.unicopia.trinkets.TrinketsDelegate; import com.minelittlepony.unicopia.util.NbtSerialisable; -import com.minelittlepony.unicopia.util.Tickable; -import net.minecraft.item.ItemConvertible; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtList; import net.minecraft.sound.SoundEvents; import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; import net.minecraft.util.TypedActionResult; -import net.minecraft.util.registry.Registry; -public class PlayerCharmTracker implements Tickable, NbtSerialisable { +public class PlayerCharmTracker implements NbtSerialisable { private final Pony pony; - private final ItemTracker armour = new ItemTracker(); - private CustomisedSpellType[] handSpells = new CustomisedSpellType[] { SpellType.SHIELD.withTraits(), SpellType.CATAPULT.withTraits() @@ -42,25 +26,6 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable { this.pony = pony; } - @Override - public void tick() { - armour.update(getAll()); - } - - private Stream getAll() { - if (!TrinketsDelegate.hasTrinkets()) { - return pony.getMaster().getInventory().armor.stream(); - } - return Stream.concat( - TrinketsDelegate.getInstance().getEquipped(pony.getMaster(), TrinketsDelegate.NECKLACE), - pony.getMaster().getInventory().armor.stream() - ); - } - - public ItemTracker getArmour() { - return armour; - } - public CustomisedSpellType[] getHandSpells() { return handSpells; } @@ -85,7 +50,6 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable { @Override public void toNBT(NbtCompound compound) { - compound.put("armour", armour.toNBT()); NbtList equippedSpells = new NbtList(); for (CustomisedSpellType spell : handSpells) { equippedSpells.add(spell.toNBT()); @@ -95,7 +59,6 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable { @Override public void fromNBT(NbtCompound compound) { - armour.fromNBT(compound.getCompound("armour")); if (compound.contains("handSpells", NbtElement.LIST_TYPE)) { NbtList list = compound.getList("handSpells", NbtElement.COMPOUND_TYPE); for (int i = 0; i < handSpells.length && i < list.size(); i++) { @@ -103,54 +66,4 @@ public class PlayerCharmTracker implements Tickable, NbtSerialisable { } } } - - public class ItemTracker implements NbtSerialisable { - private final Map items = new HashMap<>(); - - public void update(Stream stacks) { - Set found = new HashSet<>(); - stacks.forEach(stack -> { - if (stack.getItem() instanceof Charm) { - items.compute((Charm)stack.getItem(), (item, prev) -> prev == null ? 1 : prev + 1); - found.add((Charm)stack.getItem()); - } - }); - items.entrySet().removeIf(e -> { - if (!found.contains(e.getKey())) { - e.getKey().onRemoved(pony, e.getValue()); - return true; - } - return false; - }); - } - - public int getTicks(Charm charm) { - return items.getOrDefault(charm.asItem(), 0); - } - - public boolean contains(Charm charm) { - return getTicks(charm) > 0; - } - - @Override - public void toNBT(NbtCompound compound) { - items.forEach((charm, count) -> { - compound.putInt(Registry.ITEM.getId(charm.asItem()).toString(), count); - }); - } - - @Override - public void fromNBT(NbtCompound compound) { - items.clear(); - compound.getKeys().stream().map(Identifier::tryParse) - .filter(Objects::nonNull) - .map(id -> Map.entry(Registry.ITEM.get(id), compound.getInt(id.toString()))) - .filter(i -> i.getKey() instanceof Charm && i.getValue() > 0) - .forEach(item -> items.put((Charm)item.getKey(), item.getValue())); - } - } - - public interface Charm extends Affine, ItemConvertible { - void onRemoved(Pony pony, int timeWorn); - } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index df11d9fd..91f45b61 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -117,7 +117,7 @@ public class Pony extends Living implements Transmittable, Copieab this.mana = new ManaContainer(this); this.levels = new PlayerLevelStore(this, LEVEL, true, SoundEvents.ENTITY_PLAYER_LEVELUP); this.corruption = new PlayerLevelStore(this, CORRUPTION, false, SoundEvents.PARTICLE_SOUL_ESCAPE); - this.tickers = Lists.newArrayList(gravity, mana, attributes, charms); + this.tickers = Lists.newArrayList(gravity, mana, attributes); player.getDataTracker().startTracking(RACE, Race.DEFAULT_ID); } @@ -516,7 +516,7 @@ public class Pony extends Living implements Transmittable, Copieab @Override public boolean isEnemy(Affine other) { - return getCharms().getArmour().contains(UItems.ALICORN_AMULET) || super.isEnemy(other); + return getArmour().contains(UItems.ALICORN_AMULET) || super.isEnemy(other); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java index f4273922..276077bb 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/AlicornAmuletItem.java @@ -5,7 +5,6 @@ import java.util.*; import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableMultimap; -import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.player.*; @@ -35,7 +34,7 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.world.LocalDifficulty; import net.minecraft.world.World; -public class AlicornAmuletItem extends AmuletItem implements PlayerCharmTracker.Charm, ItemImpl.ClingyItem, ItemImpl.GroundTickCallback { +public class AlicornAmuletItem extends AmuletItem implements ItemTracker.Trackable, ItemImpl.ClingyItem, ItemImpl.GroundTickCallback { private static final float EFFECT_UPDATE_FREQUENCY = 1000000; private static final UUID EFFECT_UUID = UUID.fromString("c0a870f5-99ef-4716-a23e-f320ee834b26"); private static final Map EFFECT_SCALES = Map.of( @@ -50,20 +49,15 @@ public class AlicornAmuletItem extends AmuletItem implements PlayerCharmTracker. super(settings, 0, ImmutableMultimap.of()); } - @Override - public Affinity getAffinity() { - return Affinity.BAD; - } - @Environment(EnvType.CLIENT) @Override public void appendTooltip(ItemStack stack, @Nullable World world, List tooltip, TooltipContext tooltipContext) { Pony iplayer = Pony.of(MinecraftClient.getInstance().player); if (iplayer != null) { - int attachedTime = iplayer.getCharms().getArmour().getTicks(this); + long attachedTime = iplayer.getArmour().getTicks(this); if (attachedTime > 0) { - tooltip.add(Text.translatable(getTranslationKey() + ".lore", StringHelper.formatTicks(attachedTime))); + tooltip.add(Text.translatable(getTranslationKey() + ".lore", StringHelper.formatTicks((int)attachedTime))); } } } @@ -112,80 +106,83 @@ public class AlicornAmuletItem extends AmuletItem implements PlayerCharmTracker. } @Override - public void onRemoved(Pony pony, int timeWorn) { + public void onEquipped(Living wearer) { + wearer.getReferenceWorld().playSound(null, wearer.getOrigin(), USounds.ITEM_ALICORN_AMULET_CURSE, wearer.getEntity().getSoundCategory(), 3, 1); + } + + @Override + public void onUnequipped(Living wearer, long timeWorn) { float attachedTime = timeWorn / 100F; - LocalDifficulty difficulty = pony.getReferenceWorld().getLocalDifficulty(pony.getOrigin()); + LocalDifficulty difficulty = wearer.getReferenceWorld().getLocalDifficulty(wearer.getOrigin()); float amount = attachedTime * (1 + difficulty.getClampedLocalDifficulty()); - amount = Math.min(amount, pony.getMaster().getMaxHealth()); + amount = Math.min(amount, wearer.getMaster().getMaxHealth()); - pony.getMaster().getHungerManager().setFoodLevel(1); - pony.getMaster().damage(MagicalDamageSource.ALICORN_AMULET, amount); - pony.getMaster().addStatusEffect(new StatusEffectInstance(StatusEffects.NAUSEA, 200, 1)); + if (wearer.getMaster() instanceof PlayerEntity) { + ((PlayerEntity)wearer.getMaster()).getHungerManager().setFoodLevel(1); + } + wearer.getMaster().damage(MagicalDamageSource.ALICORN_AMULET, amount); + wearer.getMaster().addStatusEffect(new StatusEffectInstance(StatusEffects.NAUSEA, 200, 1)); if (attachedTime > 120) { - pony.getMaster().takeKnockback(1, 1, 1); - pony.updateVelocity(); + wearer.getMaster().takeKnockback(1, 1, 1); + wearer.updateVelocity(); } EFFECT_SCALES.keySet().forEach(attribute -> { - pony.getMaster().getAttributeInstance(attribute).tryRemoveModifier(EFFECT_UUID); + wearer.getMaster().getAttributeInstance(attribute).tryRemoveModifier(EFFECT_UUID); }); } @Override public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) { - if (!(entity instanceof PlayerEntity) || world.isClient) { + if (world.isClient) { return; } - PlayerEntity player = (PlayerEntity)entity; - // if we're in the main hand, try to equip ourselves - if (selected && !isApplicable(player) && world.random.nextInt(320) == 0) { + if (entity instanceof PlayerEntity player && selected && !isApplicable(player) && world.random.nextInt(320) == 0) { use(world, player, Hand.MAIN_HAND); return; } - Pony pony = Pony.of(player); + Living living = Living.living(entity); - if (!pony.getCharms().getArmour().contains(this)) { + if (!living.getArmour().contains(this)) { return; } - // healing effect - if (player.getHealth() < player.getMaxHealth()) { - player.heal(0.5F); - } else if (player.canConsume(false)) { - player.getHungerManager().add(1, 0); - } else { - player.removeStatusEffect(StatusEffects.NAUSEA); - } - - MagicReserves reserves = pony.getMagicalReserves(); - - // constantly increase exertion - if (reserves.getExertion().get() < reserves.getExertion().getMax()) { - reserves.getExertion().add(2); - } - - float attachedTicks = pony.getCharms().getArmour().getTicks(this); + float attachedTicks = living.getArmour().getTicks(this); float seconds = attachedTicks / EFFECT_UPDATE_FREQUENCY; - if (reserves.getEnergy().get() < 0.005F + seconds) { - reserves.getEnergy().add(2); - } + if (entity instanceof PlayerEntity player) { + // healing effect + if (player.getHealth() < player.getMaxHealth()) { + player.heal(0.5F); + } else if (player.canConsume(false)) { + player.getHungerManager().add(1, 0); + } else { + player.removeStatusEffect(StatusEffects.NAUSEA); + } - if (attachedTicks == 1) { - world.playSound(null, player.getBlockPos(), USounds.ITEM_ALICORN_AMULET_CURSE, SoundCategory.PLAYERS, 3, 1); + MagicReserves reserves = ((Pony)living).getMagicalReserves(); + + // constantly increase exertion + if (reserves.getExertion().get() < reserves.getExertion().getMax()) { + reserves.getExertion().add(2); + } + + if (reserves.getEnergy().get() < 0.005F + seconds) { + reserves.getEnergy().add(2); + } } // every 1 second, update modifiers if (attachedTicks % EFFECT_UPDATE_FREQUENCY == 0) { EFFECT_SCALES.entrySet().forEach(attribute -> { - EntityAttributeInstance instance = player.getAttributeInstance(attribute.getKey()); + EntityAttributeInstance instance = living.getMaster().getAttributeInstance(attribute.getKey()); EntityAttributeModifier modifier = instance.getModifier(EFFECT_UUID); float desiredValue = attribute.getValue() * seconds; if (!MathHelper.approximatelyEquals(desiredValue, modifier.getValue())) { diff --git a/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java b/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java index 266d10cb..332c816b 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/PegasusAmuletItem.java @@ -1,8 +1,7 @@ package com.minelittlepony.unicopia.item; -import com.minelittlepony.unicopia.Affinity; +import com.minelittlepony.unicopia.entity.ItemTracker; import com.minelittlepony.unicopia.entity.Living; -import com.minelittlepony.unicopia.entity.player.PlayerCharmTracker; import com.minelittlepony.unicopia.particle.ParticleUtils; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; @@ -11,23 +10,18 @@ import net.minecraft.item.ItemStack; import net.minecraft.particle.ParticleTypes; import net.minecraft.world.World; -public class PegasusAmuletItem extends AmuletItem implements PlayerCharmTracker.Charm { +public class PegasusAmuletItem extends AmuletItem implements ItemTracker.Trackable { public PegasusAmuletItem(FabricItemSettings settings, int maxEnergy) { super(settings, maxEnergy); } @Override - public Affinity getAffinity() { - return Affinity.NEUTRAL; - } - - @Override - public void onRemoved(Living living, int timeWorn) { + public void onUnequipped(Living living, long timeWorn) { } @Override - public void onAdded(Living living) { + public void onEquipped(Living living) { }