From 269db7bdc9a5c16b46a0440d373196079ae59c4e Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 3 Mar 2021 11:33:23 +0200 Subject: [PATCH] Further cleanup to the magic system --- .../unicopia/EquinePredicates.java | 8 +- .../unicopia/ability/BatEeeeAbility.java | 4 +- .../ability/ChangelingDisguiseAbility.java | 5 +- .../ability/PegasusRainboomAbility.java | 4 +- .../ability/UnicornCastingAbility.java | 9 +- .../unicopia/ability/magic/Caster.java | 44 +-------- .../unicopia/ability/magic/Spell.java | 7 -- .../ability/magic/spell/RevealingSpell.java | 9 +- .../ability/magic/spell/SpellPredicate.java | 14 +++ .../ability/magic/spell/SpellType.java | 22 ++--- .../unicopia/client/gui/UHud.java | 3 +- .../client/render/WorldRenderDelegate.java | 4 +- .../unicopia/command/DisguiseCommand.java | 14 +-- .../unicopia/entity/Creature.java | 7 +- .../unicopia/entity/Living.java | 32 +++---- .../unicopia/entity/behaviour/Disguise.java | 4 +- .../unicopia/entity/player/PlayerCamera.java | 4 +- .../entity/player/PlayerDimensions.java | 11 +-- .../unicopia/entity/player/PlayerPhysics.java | 17 ++-- .../unicopia/entity/player/Pony.java | 15 ++- .../unicopia/mixin/MixinLivingEntity.java | 5 +- .../unicopia/mixin/MixinTargetPredicate.java | 4 +- .../unicopia/network/EffectSync.java | 95 +++++++++---------- .../unicopia/particle/ParticleHandle.java | 9 +- .../projectile/MagicProjectileEntity.java | 34 +++---- 25 files changed, 160 insertions(+), 224 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellPredicate.java diff --git a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java index 5cafbb74..e5fcc115 100644 --- a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java +++ b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java @@ -2,8 +2,10 @@ package com.minelittlepony.unicopia; import java.util.function.Predicate; +import javax.annotation.Nullable; + import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.enchantment.UEnchantments; @@ -28,7 +30,7 @@ public interface EquinePredicates { Predicate HAS_WANT_IT_NEED_IT = e -> EnchantmentHelper.getEquipmentLevel(UEnchantments.WANT_IT_NEED_IT, e) > 0; - static Predicate carryingSpell(Class type) { - return IS_PLAYER.and(entity -> Pony.of((PlayerEntity)entity).getSpellOrEmpty(type, false).isPresent()); + static Predicate carryingSpell(@Nullable SpellType type) { + return IS_PLAYER.and(entity -> Pony.of((PlayerEntity)entity).getSpellSlot().get(type, false).isPresent()); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java index 8f100cca..40799135 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/BatEeeeAbility.java @@ -8,7 +8,7 @@ import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.ability.data.Hit; -import com.minelittlepony.unicopia.ability.magic.spell.ShieldSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.util.MagicalDamageSource; @@ -23,7 +23,7 @@ import net.minecraft.util.math.Vec3d; */ public class BatEeeeAbility implements Ability { - private static final Predicate HAS_SHIELD = EquinePredicates.carryingSpell(ShieldSpell.class); + private static final Predicate HAS_SHIELD = EquinePredicates.carryingSpell(SpellType.SHIELD); @Override public int getWarmupTime(Pony player) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java index 49460f69..a4b44d93 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java @@ -44,7 +44,8 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility { Entity looked = trace.getEntity().map(e -> { return e instanceof PlayerEntity ? Pony.of((PlayerEntity)e) - .getSpellOrEmpty(DisguiseSpell.class) + .getSpellSlot() + .get(SpellType.DISGUISE, true) .map(DisguiseSpell::getDisguise) .map(Disguise::getAppearance) .orElse(e) : e; @@ -57,7 +58,7 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility { player.getEntityWorld().playSound(null, player.getBlockPos(), SoundEvents.ENTITY_PARROT_IMITATE_RAVAGER, SoundCategory.PLAYERS, 1.4F, 0.4F); - iplayer.getSpellOrEmpty(DisguiseSpell.class).orElseGet(() -> { + iplayer.getSpellSlot().get(SpellType.DISGUISE, true).orElseGet(() -> { DisguiseSpell disc = SpellType.DISGUISE.create(); iplayer.setSpell(disc); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java index 87bab9d3..b800d1c6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java @@ -40,7 +40,7 @@ public class PegasusRainboomAbility implements Ability { return null; } - if (player.getPhysics().isFlying() && !player.hasSpell()) { + if (player.getPhysics().isFlying() && !player.getSpellSlot().isPresent()) { return Hit.INSTANCE; } @@ -64,7 +64,7 @@ public class PegasusRainboomAbility implements Ability { return; } - if (player.getPhysics().isFlying() && !player.hasSpell()) { + if (player.getPhysics().isFlying() && !player.getSpellSlot().isPresent()) { player.getMagicalReserves().getMana().multiply(0.1F); player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO); player.setSpell(SpellType.JOUSTING.create()); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java index c037c298..1e62c82e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java @@ -7,6 +7,7 @@ import javax.annotation.Nullable; import com.google.common.collect.Streams; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; +import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.AmuletItem; @@ -60,7 +61,7 @@ public class UnicornCastingAbility implements Ability { return Hit.of(spell != ActionResult.FAIL && manaLevel > 4F); } - return Hit.of(manaLevel > (player.hasSpell() ? 2F : 4F)); + return Hit.of(manaLevel > (player.getSpellSlot().isPresent() ? 2F : 4F)); } @Override @@ -82,7 +83,7 @@ public class UnicornCastingAbility implements Ability { return 4F; } - if (player.hasSpell()) { + if (player.getSpellSlot().isPresent()) { return 2F; } @@ -112,7 +113,7 @@ public class UnicornCastingAbility implements Ability { if (newSpell.getResult() != ActionResult.FAIL) { @Nullable SpellType spell = newSpell.getValue(); - if (!player.hasSpell() && spell == null) { + if (!player.getSpellSlot().isPresent() && spell == null) { spell = SpellType.SHIELD; } @@ -138,7 +139,7 @@ public class UnicornCastingAbility implements Ability { } private TypedActionResult> getNewSpell(Pony player) { - final SpellType current = player.hasSpell() ? player.getSpell(true).getType() : null; + final SpellType current = player.getSpellSlot().get(true).map(Spell::getType).orElse(null); return Streams.stream(player.getMaster().getItemsHand()) .filter(GemstoneItem::isEnchanted) .map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), current, SpellType::mayAttach)) diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java index b2b27f26..d7aac342 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Caster.java @@ -27,48 +27,10 @@ public interface Caster extends Owned, Levelled, Affi Physics getPhysics(); - EffectSync getPrimarySpellSlot(); + EffectSync getSpellSlot(); default void setSpell(@Nullable Spell spell) { - getPrimarySpellSlot().set(spell); - } - - /** - * Gets the active effect for this caster. - */ - @Nullable - default Spell getSpell(boolean update) { - return getSpell(null, update); - } - - /** - * Gets the active effect for the matching given type. - * Returns null if no such effect exists for this caster. - */ - @Nullable - default T getSpell(@Nullable Class type, boolean update) { - return getPrimarySpellSlot().get(type, update); - } - - /** - * Gets the active effect for this caster updating it if needed. - */ - default Optional getSpellOrEmpty(Class type, boolean update) { - return getPrimarySpellSlot().getOrEmpty(type, update); - } - - /** - * Gets the active effect for this caster updating it if needed. - */ - default Optional getSpellOrEmpty(Class type) { - return getSpellOrEmpty(type, true); - } - - /** - * Returns true if this caster has an active effect attached to it. - */ - default boolean hasSpell() { - return getPrimarySpellSlot().has(); + getSpellSlot().put(spell); } /** @@ -80,7 +42,7 @@ public interface Caster extends Owned, Levelled, Affi } /** - * gets the minecraft world + * Gets the minecraft world */ @Override default World getWorld() { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/Spell.java index bbf463fe..a37b13d8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/Spell.java @@ -52,11 +52,4 @@ public interface Spell extends NbtSerialisable, Affine { default boolean handleProjectileImpact(ProjectileEntity projectile) { return false; } - - /** - * Returns a new, deep-copied instance of this spell. - */ - default Spell copy() { - return SpellType.copy(this); - } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RevealingSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RevealingSpell.java index 44858efd..17ce9fb3 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RevealingSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RevealingSpell.java @@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability.magic.spell; import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.Suppressable; import com.minelittlepony.unicopia.ability.magic.Thrown; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.util.shape.Shape; @@ -45,12 +44,12 @@ public class RevealingSpell extends AbstractSpell implements Attached, Thrown { } source.findAllSpellsInRange(15).forEach(e -> { - Suppressable spell = e.getSpell(Suppressable.class, false); - - if (spell != null && spell.isVulnerable(source, this)) { + e.getSpellSlot().get(SpellPredicate.IS_SUPPRESSABLE, false) + .filter(spell -> spell.isVulnerable(source, this)) + .ifPresent(spell -> { spell.onSuppressed(source); source.getWorld().playSound(null, e.getOrigin(), SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, SoundCategory.PLAYERS, 0.2F, 0.5F); - } + }); }); return true; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellPredicate.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellPredicate.java new file mode 100644 index 00000000..6de6d70d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellPredicate.java @@ -0,0 +1,14 @@ +package com.minelittlepony.unicopia.ability.magic.spell; + +import java.util.function.Predicate; + +import com.minelittlepony.unicopia.ability.magic.Attached; +import com.minelittlepony.unicopia.ability.magic.Spell; +import com.minelittlepony.unicopia.ability.magic.Suppressable; +import com.minelittlepony.unicopia.ability.magic.Thrown; + +public interface SpellPredicate extends Predicate { + SpellPredicate IS_THROWN = s -> s instanceof Thrown; + SpellPredicate IS_ATTACHED = s -> s instanceof Attached; + SpellPredicate IS_SUPPRESSABLE = s -> s instanceof Suppressable; +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellType.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellType.java index 4dd547bf..965d8c0f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellType.java @@ -10,9 +10,7 @@ import javax.annotation.Nullable; import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.ability.magic.Affine; -import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Spell; -import com.minelittlepony.unicopia.ability.magic.Thrown; import net.minecraft.nbt.CompoundTag; import net.minecraft.text.Text; @@ -20,7 +18,7 @@ import net.minecraft.text.TranslatableText; import net.minecraft.util.Identifier; import net.minecraft.util.Util; -public class SpellType implements Affine { +public final class SpellType implements Affine, SpellPredicate { public static final Identifier EMPTY_ID = new Identifier("unicopia", "null"); public static final SpellType EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, t -> null); @@ -57,7 +55,7 @@ public class SpellType implements Affine { @Nullable private String translationKey; - SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Factory factory) { + private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Factory factory) { this.id = id; this.affinity = affinity; this.color = color; @@ -65,8 +63,8 @@ public class SpellType implements Affine { this.factory = factory; Spell inst = create(); - thrown = inst instanceof Thrown; - attached = inst instanceof Attached; + thrown = SpellPredicate.IS_THROWN.test(inst); + attached = SpellPredicate.IS_ATTACHED.test(inst); } public boolean isObtainable() { @@ -119,6 +117,11 @@ public class SpellType implements Affine { return null; } + @Override + public boolean test(@Nullable Spell spell) { + return spell != null && spell.getType() == this; + } + public static SpellType register(Identifier id, Affinity affinity, int color, boolean obtainable, Factory factory) { SpellType type = new SpellType<>(id, affinity, color, obtainable, factory); byAffinity(affinity).add(type); @@ -132,18 +135,13 @@ public class SpellType implements Affine { @SuppressWarnings("unchecked") public static SpellType getKey(Identifier id) { - return (SpellType)REGISTRY.getOrDefault(id, EMPTY_KEY); + return (SpellType)(EMPTY_ID.equals(id) ? EMPTY_KEY : REGISTRY.getOrDefault(id, EMPTY_KEY)); } public static Set> byAffinity(Affinity affinity) { return BY_AFFINITY.computeIfAbsent(affinity, a -> new HashSet<>()); } - @SuppressWarnings("unchecked") - public static T copy(T effect) { - return (T)fromNBT(toNBT(effect)); - } - @Nullable public static Spell fromNBT(CompoundTag compound) { if (compound.contains("effect_id")) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index dae60002..5e6cb7a8 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -9,6 +9,7 @@ import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.client.KeyBindingsHandler; import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.player.Pony; @@ -88,7 +89,7 @@ public class UHud extends DrawableHelper { matrices.pop(); if (pony.getSpecies() == Race.CHANGELING && !client.player.isSneaking()) { - pony.getSpellOrEmpty(DisguiseSpell.class, false).map(DisguiseSpell::getDisguise) + pony.getSpellSlot().get(SpellType.DISGUISE, false).map(DisguiseSpell::getDisguise) .map(Disguise::getAppearance) .ifPresent(appearance -> { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java index f53a1f11..931c747c 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java @@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.client.render; import javax.annotation.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.ItemImpl; import com.minelittlepony.unicopia.entity.Living; @@ -83,7 +83,7 @@ public class WorldRenderDelegate { int fireTicks = pony.getMaster().doesRenderOnFire() ? 1 : 0; - return ((Caster)pony).getSpellOrEmpty(DisguiseSpell.class, true).map(effect -> { + return ((Caster)pony).getSpellSlot().get(SpellType.DISGUISE, true).map(effect -> { effect.update(pony, false); Disguise ve = effect.getDisguise(); diff --git a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java index 9d406619..effea17b 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/DisguiseCommand.java @@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.command; import java.util.function.Function; -import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; import com.mojang.brigadier.CommandDispatcher; @@ -61,13 +60,10 @@ public class DisguiseCommand { throw FAILED_EXCEPTION.create(); } - DisguiseSpell effect = iplayer.getSpell(DisguiseSpell.class, true); - - if (effect == null) { - iplayer.setSpell(SpellType.DISGUISE.create().setDisguise(entity)); - } else { - effect.setDisguise(entity); - } + iplayer.getSpellSlot() + .get(SpellType.DISGUISE, true) + .orElseGet(SpellType.DISGUISE::create) + .setDisguise(entity); if (!isSelf) { source.sendFeedback(new TranslatableText("commands.disguise.success.other", player.getName(), entity.getName()), true); @@ -83,7 +79,7 @@ public class DisguiseCommand { static int reveal(ServerCommandSource source, PlayerEntity player) { Pony iplayer = Pony.of(player); - iplayer.getSpellOrEmpty(DisguiseSpell.class).ifPresent(disguise -> { + iplayer.getSpellSlot().get(SpellType.DISGUISE, true).ifPresent(disguise -> { disguise.onDestroyed(iplayer); }); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index 926e1bf3..2d09bc4f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -4,7 +4,6 @@ import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Levelled; -import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; @@ -89,11 +88,9 @@ public class Creature extends Living { @Override public void toNBT(CompoundTag compound) { super.toNBT(compound); - Spell effect = getSpell(true); - - if (effect != null) { + getSpellSlot().get(true).ifPresent(effect -> { compound.put("effect", SpellType.toNBT(effect)); - } + }); physics.toNBT(compound); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 2fb8d021..a233e7ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -5,10 +5,9 @@ import java.util.stream.Stream; import javax.annotation.Nullable; -import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.Spell; -import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellPredicate; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.network.EffectSync; @@ -60,7 +59,7 @@ public abstract class Living implements Equine, Caste } @Override - public EffectSync getPrimarySpellSlot() { + public EffectSync getSpellSlot() { return effectDelegate; } @@ -79,15 +78,11 @@ public abstract class Living implements Equine, Caste @Override public void tick() { - if (hasSpell()) { - Attached effect = getSpell(Attached.class, true); - - if (effect != null) { - if (!effect.onBodyTick(this)) { - setSpell(null); - } + getSpellSlot().get(SpellPredicate.IS_ATTACHED, true).ifPresent(effect -> { + if (!effect.onBodyTick(this)) { + setSpell(null); } - } + }); if (invinsibilityTicks > 0) { invinsibilityTicks--; @@ -142,18 +137,13 @@ public abstract class Living implements Equine, Caste @Override public boolean onProjectileImpact(ProjectileEntity projectile) { - if (hasSpell()) { - Spell effect = getSpell(true); - if (!effect.isDead() && effect.handleProjectileImpact(projectile)) { - return true; - } - } - - return false; + return getSpellSlot().get(true) + .filter(effect -> !effect.isDead() && effect.handleProjectileImpact(projectile)) + .isPresent(); } protected void handleFall(float distance, float damageMultiplier) { - getSpellOrEmpty(DisguiseSpell.class, false).ifPresent(spell -> { + getSpellSlot().get(SpellType.DISGUISE, false).ifPresent(spell -> { spell.getDisguise().onImpact(this, distance, damageMultiplier); }); } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java index eb457427..b2c82ef0 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java @@ -14,7 +14,7 @@ import com.minelittlepony.unicopia.FlightType; import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.player.PlayerAttributes; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.projectile.ProjectileUtil; @@ -345,7 +345,7 @@ public class Disguise implements NbtSerialisable { VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D)); world.getOtherEntities(entity, box.expand(0.5), predicate.and(e -> { - Caster.of(e).flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false)).ifPresent(p -> { + Caster.of(e).flatMap(c -> c.getSpellSlot().get(SpellType.DISGUISE, false)).ifPresent(p -> { p.getDisguise().getCollissionShapes(ctx, shape -> { if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) { shapes.add(shape); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java index 67d62591..c0a1770d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java @@ -4,6 +4,7 @@ import java.util.Optional; import com.minelittlepony.common.util.animation.MotionCompositor; import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import net.minecraft.util.math.Vec3d; @@ -46,7 +47,8 @@ public class PlayerCamera extends MotionCompositor { } public Optional calculateDistance(double distance) { - return player.getSpellOrEmpty(DisguiseSpell.class, false) + return player.getSpellSlot() + .get(SpellType.DISGUISE, false) .map(DisguiseSpell::getDisguise) .flatMap(d -> d.getDistance(player)) .map(d -> distance * d); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java index 933a5545..b9577e77 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java @@ -5,7 +5,6 @@ import java.util.Optional; import javax.annotation.Nullable; import com.minelittlepony.unicopia.Unicopia; -import com.minelittlepony.unicopia.ability.magic.Spell; import net.minecraft.entity.EntityDimensions; @@ -72,13 +71,9 @@ public final class PlayerDimensions { } Optional getPredicate() { - if (pony.hasSpell()) { - Spell effect = pony.getSpell(true); - if (!effect.isDead() && effect instanceof Provider) { - return Optional.of(((Provider)effect)); - } - } - return Optional.empty(); + return pony.getSpellSlot().get(true) + .filter(effect -> !effect.isDead() && effect instanceof Provider) + .map(effect -> (Provider)effect); } public interface Provider { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index c278dc9c..dcf8332a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -3,8 +3,7 @@ package com.minelittlepony.unicopia.entity.player; import com.minelittlepony.unicopia.FlightType; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; -import com.minelittlepony.unicopia.ability.magic.Spell; -import com.minelittlepony.unicopia.ability.magic.spell.JoustingSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.Jumper; @@ -78,7 +77,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickable, Moti @Override public boolean isRainbooming() { - return pony.getSpellOrEmpty(JoustingSpell.class).isPresent(); + return pony.getSpellSlot().get(SpellType.JOUSTING, true).isPresent(); } @Override @@ -448,14 +447,10 @@ public class PlayerPhysics extends EntityPhysics implements Tickable, Moti return FlightType.ARTIFICIAL; } - if (pony.hasSpell()) { - Spell effect = pony.getSpell(true); - if (!effect.isDead() && effect instanceof FlightType.Provider) { - return ((FlightType.Provider)effect).getFlightType(pony); - } - } - - return pony.getSpecies().getFlightType(); + return pony.getSpellSlot().get(true) + .filter(effect -> !effect.isDead() && effect instanceof FlightType.Provider) + .map(effect -> ((FlightType.Provider)effect).getFlightType(pony)) + .orElse(pony.getSpecies().getFlightType()); } public void updateFlightStat(boolean flying) { 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 cabd4091..189318c2 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -14,7 +14,6 @@ import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.WorldTribeManager; import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.magic.Spell; -import com.minelittlepony.unicopia.ability.magic.spell.ShieldSpell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.entity.PonyContainer; @@ -134,7 +133,7 @@ public class Pony extends Living implements Transmittable, Copieab @Override public boolean isInvisible() { - return invisible && hasSpell(); + return invisible && getSpellSlot().isPresent(); } public boolean isSpeciesPersisted() { @@ -289,7 +288,7 @@ public class Pony extends Living implements Transmittable, Copieab float g = gravity.getGravityModifier(); - boolean extraProtection = getSpell(ShieldSpell.class, false) != null; + boolean extraProtection = getSpellSlot().get(SpellType.SHIELD, false).isPresent(); if (g != 1 || extraProtection || getSpecies().canFly() && !entity.isCreative() && !entity.isSpectator()) { @@ -384,11 +383,9 @@ public class Pony extends Living implements Transmittable, Copieab compound.put("powers", powers.toNBT()); compound.put("gravity", gravity.toNBT()); - Spell effect = getSpell(true); - - if (effect != null) { + getSpellSlot().get(true).ifPresent(effect ->{ compound.put("effect", SpellType.toNBT(effect)); - } + }); } @Override @@ -403,7 +400,7 @@ public class Pony extends Living implements Transmittable, Copieab magicExhaustion = compound.getFloat("magicExhaustion"); if (compound.contains("effect")) { - getPrimarySpellSlot().set(SpellType.fromNBT(compound.getCompound("effect"))); + getSpellSlot().put(SpellType.fromNBT(compound.getCompound("effect"))); } } @@ -411,7 +408,7 @@ public class Pony extends Living implements Transmittable, Copieab public void copyFrom(Pony oldPlayer) { speciesPersisted = oldPlayer.speciesPersisted; if (!oldPlayer.getEntity().removed) { - setSpell(oldPlayer.getSpell(true)); + setSpell(oldPlayer.getSpellSlot().get(true).orElse(null)); } setSpecies(oldPlayer.getSpecies()); setDirty(); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java index 8d2a79fa..b07758bd 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java @@ -14,6 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.PonyContainer; import com.minelittlepony.unicopia.entity.behaviour.Disguise; @@ -82,7 +83,7 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer info) { if (get() instanceof Pony && horizontalCollision) { - ((Pony)get()).getSpellOrEmpty(DisguiseSpell.class, false) + ((Pony)get()).getSpellSlot().get(SpellType.DISGUISE, false) .map(DisguiseSpell::getDisguise) .filter(Disguise::canClimbWalls) .ifPresent(v -> { @@ -95,7 +96,7 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer info) { Caster.of(this) - .flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false)) + .flatMap(c -> c.getSpellSlot().get(SpellType.DISGUISE, false)) .map(DisguiseSpell::getDisguise) .map(Disguise::getAppearance) .filter(Entity::isPushable) diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java index d6ebdf07..7811df2e 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinTargetPredicate.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.player.Pony; @@ -20,7 +20,7 @@ abstract class MixinTargetPredicate { public void onTest(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable info) { Equine eq = Equine.of(targetEntity); if (eq instanceof Pony) { - ((Pony)eq).getSpellOrEmpty(DisguiseSpell.class).ifPresent(spell -> { + ((Pony)eq).getSpellSlot().get(SpellType.DISGUISE, true).ifPresent(spell -> { if (spell.getDisguise().getAppearance() == baseEntity) { info.setReturnValue(false); } diff --git a/src/main/java/com/minelittlepony/unicopia/network/EffectSync.java b/src/main/java/com/minelittlepony/unicopia/network/EffectSync.java index fdb9ae33..ac2bc0f4 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/EffectSync.java +++ b/src/main/java/com/minelittlepony/unicopia/network/EffectSync.java @@ -6,6 +6,7 @@ import javax.annotation.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import net.minecraft.entity.data.TrackedData; @@ -13,7 +14,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Identifier; /** - * Synchronisation class for spell effects. + * Synchronisation class for spells. * Since we can't have our own serializers, we have to intelligently * determine whether to update it from an nbt tag. * @@ -21,85 +22,83 @@ import net.minecraft.util.Identifier; */ public class EffectSync { - @Nullable - private Spell effect; + private Optional spell = Optional.empty(); - private final Caster owned; + private final Caster owner; private final TrackedData param; @Nullable private CompoundTag lastValue; - public EffectSync(Caster owned, TrackedData param) { - this.owned = owned; + public EffectSync(Caster owner, TrackedData param) { + this.owner = owner; this.param = param; } - public Optional getOrEmpty(Class type, boolean update) { - T effect = get(type, update); - - if (effect == null || effect.isDead()) { - return Optional.empty(); - } - - return Optional.of(effect); + /** + * Gets the active effect for this caster updating it if needed. + */ + public Optional get(boolean update) { + return get(null, update); } + /** + * Gets the active effect for this caster updating it if needed. + */ @SuppressWarnings("unchecked") - public E get(Class type, boolean update) { + public Optional get(@Nullable SpellPredicate type, boolean update) { if (update) { sync(true); } - if (effect == null || type == null || type.isAssignableFrom(effect.getClass())) { - return (E)effect; + if (checkReference() && (type == null || type.test(spell.get()))) { + return (Optional)spell; } - return null; + return Optional.empty(); } - public boolean has() { + /** + * Returns true if this caster has an active effect attached to it. + */ + public boolean isPresent() { sync(false); - return effect != null; + return checkReference(); + } + + private boolean checkReference() { + return spell.isPresent() && !spell.get().isDead(); } private void sync(boolean force) { - CompoundTag comp = owned.getEntity().getDataTracker().get(param); + CompoundTag comp = owner.getEntity().getDataTracker().get(param); + + Spell effect = spell.orElse(null); if (comp == null || !comp.contains("effect_id")) { - if (effect != null) { - effect.setDead(); - effect = null; - } - return; - } else { - if (effect == null || !effect.getType().getId().equals(new Identifier(comp.getString("effect_id")))) { - if (effect != null) { - effect.setDead(); - } - effect = SpellType.fromNBT(comp); - } else if (owned.getEntity().world.isClient()) { - if (lastValue != comp || !(comp == null || comp.equals(lastValue))) { - lastValue = comp; - effect.fromNBT(comp); - } - } else if ((force || !owned.getEntity().world.isClient()) && effect.isDirty()) { - set(effect); + updateReference(null); + } else if (!checkReference() || !effect.getType().getId().equals(new Identifier(comp.getString("effect_id")))) { + updateReference(SpellType.fromNBT(comp)); + } else if (owner.getEntity().world.isClient()) { + if (lastValue != comp || !(comp == null || comp.equals(lastValue))) { + lastValue = comp; + effect.fromNBT(comp); } + } else if ((force || !owner.isClient()) && effect.isDirty()) { + put(effect); } } - public void set(@Nullable Spell effect) { - if (this.effect != null && this.effect != effect) { - this.effect.setDead(); - } - this.effect = effect; + public void put(@Nullable Spell effect) { + updateReference(effect); + owner.getEntity().getDataTracker().set(param, effect == null ? new CompoundTag() : SpellType.toNBT(effect)); + } - if (effect == null) { - owned.getEntity().getDataTracker().set(param, new CompoundTag()); - } else { - owned.getEntity().getDataTracker().set(param, SpellType.toNBT(effect)); + private void updateReference(@Nullable Spell effect) { + if (spell.isPresent() && spell.get() != effect) { + spell.get().setDead(); } + spell = Optional.ofNullable(effect); } } diff --git a/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java b/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java index ef30d270..ab9e0ed4 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java @@ -4,6 +4,7 @@ import java.util.Optional; import java.util.function.Consumer; import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.Equine; @@ -66,7 +67,7 @@ public class ParticleHandle { public void attach(Caster caster) { this.linked = true; this.caster = Optional.of(caster); - this.effect = caster.getSpell(false).getType(); + this.effect = caster.getSpellSlot().get(false).map(Spell::getType).orElse(null); } public void detach() { @@ -81,10 +82,10 @@ public class ParticleHandle { caster = caster.filter(c -> { Entity e = c.getEntity(); - return Equine.of(e) == c - && c.hasSpell() - && c.getSpell(false).getType().equals(effect) + && c.getSpellSlot().get(false) + .filter(s -> s.getType() == effect) + .isPresent() && e != null && c.getWorld().getEntityById(e.getEntityId()) != null; }); diff --git a/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java b/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java index c00d3302..6815b9f5 100644 --- a/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/projectile/MagicProjectileEntity.java @@ -2,11 +2,12 @@ package com.minelittlepony.unicopia.projectile; import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.UEntities; +import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.ability.magic.Magical; import com.minelittlepony.unicopia.ability.magic.Spell; -import com.minelittlepony.unicopia.ability.magic.Thrown; +import com.minelittlepony.unicopia.ability.magic.spell.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.Physics; @@ -77,7 +78,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, @Override protected Item getDefaultItem() { - switch (getSpellOrEmpty(Spell.class, false).map(Spell::getAffinity).orElse(Affinity.NEUTRAL)) { + switch (getSpellSlot().get(false).map(Spell::getAffinity).orElse(Affinity.NEUTRAL)) { case GOOD: return Items.SNOWBALL; case BAD: return Items.MAGMA_CREAM; default: return Items.AIR; @@ -111,11 +112,11 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, @Override public Affinity getAffinity() { - return hasSpell() ? getSpell(true).getAffinity() : Affinity.NEUTRAL; + return getSpellSlot().get(true).map(Affine::getAffinity).orElse(Affinity.NEUTRAL); } @Override - public EffectSync getPrimarySpellSlot() { + public EffectSync getSpellSlot() { return effectDelegate; } @@ -158,17 +159,13 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, setNoGravity(false); } - if (hasSpell()) { + if (getSpellSlot().isPresent()) { if (lastBlockPos == null || !lastBlockPos.equals(getBlockPos())) { lastBlockPos = getBlockPos(); } - Thrown spell = getSpell(Thrown.class, true); - - if (spell.isDead()) { + if (!getSpellSlot().get(SpellPredicate.IS_THROWN, true).filter(spell -> spell.onThrownTick(this)).isPresent()) { remove(); - } else { - spell.onThrownTick(this); } } @@ -228,10 +225,9 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, public void writeCustomDataToTag(CompoundTag compound) { super.writeCustomDataToTag(compound); physics.toNBT(compound); - - if (hasSpell()) { - compound.put("effect", SpellType.toNBT(getSpell(true))); - } + getSpellSlot().get(true).ifPresent(effect -> { + compound.put("effect", SpellType.toNBT(effect)); + }); } @Override @@ -249,13 +245,9 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical, @Override protected void onBlockHit(BlockHitResult hit) { - if (hasSpell()) { - Spell effect = getSpell(true); - - if (effect instanceof ProjectileDelegate) { - ((ProjectileDelegate)effect).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos())); - } - } + getSpellSlot().get(SpellPredicate.IS_THROWN, true).ifPresent(effect -> { + effect.onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos())); + }); if (getItem().getItem() instanceof ProjectileDelegate) { ((ProjectileDelegate)getItem().getItem()).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos()));