Further cleanup to the magic system

This commit is contained in:
Sollace 2021-03-03 11:33:23 +02:00
parent b3e196c404
commit 269db7bdc9
25 changed files with 160 additions and 224 deletions

View file

@ -2,8 +2,10 @@ package com.minelittlepony.unicopia;
import java.util.function.Predicate; import java.util.function.Predicate;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.Equine;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
@ -28,7 +30,7 @@ public interface EquinePredicates {
Predicate<LivingEntity> HAS_WANT_IT_NEED_IT = e -> EnchantmentHelper.getEquipmentLevel(UEnchantments.WANT_IT_NEED_IT, e) > 0; Predicate<LivingEntity> HAS_WANT_IT_NEED_IT = e -> EnchantmentHelper.getEquipmentLevel(UEnchantments.WANT_IT_NEED_IT, e) > 0;
static Predicate<Entity> carryingSpell(Class<? extends Spell> type) { static Predicate<Entity> carryingSpell(@Nullable SpellType<?> type) {
return IS_PLAYER.and(entity -> Pony.of((PlayerEntity)entity).getSpellOrEmpty(type, false).isPresent()); return IS_PLAYER.and(entity -> Pony.of((PlayerEntity)entity).getSpellSlot().get(type, false).isPresent());
} }
} }

View file

@ -8,7 +8,7 @@ import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Race; 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.ability.magic.spell.ShieldSpell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.MagicalDamageSource;
@ -23,7 +23,7 @@ import net.minecraft.util.math.Vec3d;
*/ */
public class BatEeeeAbility implements Ability<Hit> { public class BatEeeeAbility implements Ability<Hit> {
private static final Predicate<Entity> HAS_SHIELD = EquinePredicates.carryingSpell(ShieldSpell.class); private static final Predicate<Entity> HAS_SHIELD = EquinePredicates.carryingSpell(SpellType.SHIELD);
@Override @Override
public int getWarmupTime(Pony player) { public int getWarmupTime(Pony player) {

View file

@ -44,7 +44,8 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
Entity looked = trace.getEntity().map(e -> { Entity looked = trace.getEntity().map(e -> {
return e instanceof PlayerEntity ? Pony.of((PlayerEntity)e) return e instanceof PlayerEntity ? Pony.of((PlayerEntity)e)
.getSpellOrEmpty(DisguiseSpell.class) .getSpellSlot()
.get(SpellType.DISGUISE, true)
.map(DisguiseSpell::getDisguise) .map(DisguiseSpell::getDisguise)
.map(Disguise::getAppearance) .map(Disguise::getAppearance)
.orElse(e) : e; .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); 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(); DisguiseSpell disc = SpellType.DISGUISE.create();
iplayer.setSpell(disc); iplayer.setSpell(disc);

View file

@ -40,7 +40,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
return null; return null;
} }
if (player.getPhysics().isFlying() && !player.hasSpell()) { if (player.getPhysics().isFlying() && !player.getSpellSlot().isPresent()) {
return Hit.INSTANCE; return Hit.INSTANCE;
} }
@ -64,7 +64,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
return; return;
} }
if (player.getPhysics().isFlying() && !player.hasSpell()) { if (player.getPhysics().isFlying() && !player.getSpellSlot().isPresent()) {
player.getMagicalReserves().getMana().multiply(0.1F); player.getMagicalReserves().getMana().multiply(0.1F);
player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO); player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO);
player.setSpell(SpellType.JOUSTING.create()); player.setSpell(SpellType.JOUSTING.create());

View file

@ -7,6 +7,7 @@ import javax.annotation.Nullable;
import com.google.common.collect.Streams; import com.google.common.collect.Streams;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; 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.ability.magic.spell.SpellType;
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.AmuletItem;
@ -60,7 +61,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
return Hit.of(spell != ActionResult.FAIL && manaLevel > 4F); 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 @Override
@ -82,7 +83,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
return 4F; return 4F;
} }
if (player.hasSpell()) { if (player.getSpellSlot().isPresent()) {
return 2F; return 2F;
} }
@ -112,7 +113,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
if (newSpell.getResult() != ActionResult.FAIL) { if (newSpell.getResult() != ActionResult.FAIL) {
@Nullable @Nullable
SpellType<?> spell = newSpell.getValue(); SpellType<?> spell = newSpell.getValue();
if (!player.hasSpell() && spell == null) { if (!player.getSpellSlot().isPresent() && spell == null) {
spell = SpellType.SHIELD; spell = SpellType.SHIELD;
} }
@ -138,7 +139,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
} }
private TypedActionResult<SpellType<?>> getNewSpell(Pony player) { private TypedActionResult<SpellType<?>> 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()) return Streams.stream(player.getMaster().getItemsHand())
.filter(GemstoneItem::isEnchanted) .filter(GemstoneItem::isEnchanted)
.map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), current, SpellType::mayAttach)) .map(stack -> GemstoneItem.consumeSpell(stack, player.getMaster(), current, SpellType::mayAttach))

View file

@ -27,48 +27,10 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
Physics getPhysics(); Physics getPhysics();
EffectSync getPrimarySpellSlot(); EffectSync getSpellSlot();
default void setSpell(@Nullable Spell spell) { default void setSpell(@Nullable Spell spell) {
getPrimarySpellSlot().set(spell); getSpellSlot().put(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 extends Spell> T getSpell(@Nullable Class<T> type, boolean update) {
return getPrimarySpellSlot().get(type, update);
}
/**
* Gets the active effect for this caster updating it if needed.
*/
default <T extends Spell> Optional<T> getSpellOrEmpty(Class<T> type, boolean update) {
return getPrimarySpellSlot().getOrEmpty(type, update);
}
/**
* Gets the active effect for this caster updating it if needed.
*/
default <T extends Spell> Optional<T> getSpellOrEmpty(Class<T> type) {
return getSpellOrEmpty(type, true);
}
/**
* Returns true if this caster has an active effect attached to it.
*/
default boolean hasSpell() {
return getPrimarySpellSlot().has();
} }
/** /**
@ -80,7 +42,7 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
} }
/** /**
* gets the minecraft world * Gets the minecraft world
*/ */
@Override @Override
default World getWorld() { default World getWorld() {

View file

@ -52,11 +52,4 @@ public interface Spell extends NbtSerialisable, Affine {
default boolean handleProjectileImpact(ProjectileEntity projectile) { default boolean handleProjectileImpact(ProjectileEntity projectile) {
return false; return false;
} }
/**
* Returns a new, deep-copied instance of this spell.
*/
default Spell copy() {
return SpellType.copy(this);
}
} }

View file

@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.ability.magic.Attached; import com.minelittlepony.unicopia.ability.magic.Attached;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.ability.magic.Thrown;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Shape;
@ -45,12 +44,12 @@ public class RevealingSpell extends AbstractSpell implements Attached, Thrown {
} }
source.findAllSpellsInRange(15).forEach(e -> { source.findAllSpellsInRange(15).forEach(e -> {
Suppressable spell = e.getSpell(Suppressable.class, false); e.getSpellSlot().get(SpellPredicate.IS_SUPPRESSABLE, false)
.filter(spell -> spell.isVulnerable(source, this))
if (spell != null && spell.isVulnerable(source, this)) { .ifPresent(spell -> {
spell.onSuppressed(source); spell.onSuppressed(source);
source.getWorld().playSound(null, e.getOrigin(), SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, SoundCategory.PLAYERS, 0.2F, 0.5F); source.getWorld().playSound(null, e.getOrigin(), SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, SoundCategory.PLAYERS, 0.2F, 0.5F);
} });
}); });
return true; return true;

View file

@ -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<T> extends Predicate<Spell> {
SpellPredicate<Thrown> IS_THROWN = s -> s instanceof Thrown;
SpellPredicate<Attached> IS_ATTACHED = s -> s instanceof Attached;
SpellPredicate<Suppressable> IS_SUPPRESSABLE = s -> s instanceof Suppressable;
}

View file

@ -10,9 +10,7 @@ import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Affine; 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.Spell;
import com.minelittlepony.unicopia.ability.magic.Thrown;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@ -20,7 +18,7 @@ import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.Util; import net.minecraft.util.Util;
public class SpellType<T extends Spell> implements Affine { public final class SpellType<T extends Spell> implements Affine, SpellPredicate<T> {
public static final Identifier EMPTY_ID = new Identifier("unicopia", "null"); 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); public static final SpellType<?> EMPTY_KEY = new SpellType<>(EMPTY_ID, Affinity.NEUTRAL, 0xFFFFFF, false, t -> null);
@ -57,7 +55,7 @@ public class SpellType<T extends Spell> implements Affine {
@Nullable @Nullable
private String translationKey; private String translationKey;
SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) { private SpellType(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
this.id = id; this.id = id;
this.affinity = affinity; this.affinity = affinity;
this.color = color; this.color = color;
@ -65,8 +63,8 @@ public class SpellType<T extends Spell> implements Affine {
this.factory = factory; this.factory = factory;
Spell inst = create(); Spell inst = create();
thrown = inst instanceof Thrown; thrown = SpellPredicate.IS_THROWN.test(inst);
attached = inst instanceof Attached; attached = SpellPredicate.IS_ATTACHED.test(inst);
} }
public boolean isObtainable() { public boolean isObtainable() {
@ -119,6 +117,11 @@ public class SpellType<T extends Spell> implements Affine {
return null; return null;
} }
@Override
public boolean test(@Nullable Spell spell) {
return spell != null && spell.getType() == this;
}
public static <T extends Spell> SpellType<T> register(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) { public static <T extends Spell> SpellType<T> register(Identifier id, Affinity affinity, int color, boolean obtainable, Factory<T> factory) {
SpellType<T> type = new SpellType<>(id, affinity, color, obtainable, factory); SpellType<T> type = new SpellType<>(id, affinity, color, obtainable, factory);
byAffinity(affinity).add(type); byAffinity(affinity).add(type);
@ -132,18 +135,13 @@ public class SpellType<T extends Spell> implements Affine {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T extends Spell> SpellType<T> getKey(Identifier id) { public static <T extends Spell> SpellType<T> getKey(Identifier id) {
return (SpellType<T>)REGISTRY.getOrDefault(id, EMPTY_KEY); return (SpellType<T>)(EMPTY_ID.equals(id) ? EMPTY_KEY : REGISTRY.getOrDefault(id, EMPTY_KEY));
} }
public static Set<SpellType<?>> byAffinity(Affinity affinity) { public static Set<SpellType<?>> byAffinity(Affinity affinity) {
return BY_AFFINITY.computeIfAbsent(affinity, a -> new HashSet<>()); return BY_AFFINITY.computeIfAbsent(affinity, a -> new HashSet<>());
} }
@SuppressWarnings("unchecked")
public static <T extends Spell> T copy(T effect) {
return (T)fromNBT(toNBT(effect));
}
@Nullable @Nullable
public static Spell fromNBT(CompoundTag compound) { public static Spell fromNBT(CompoundTag compound) {
if (compound.contains("effect_id")) { if (compound.contains("effect_id")) {

View file

@ -9,6 +9,7 @@ import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ability.AbilitySlot; import com.minelittlepony.unicopia.ability.AbilitySlot;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; 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.client.KeyBindingsHandler;
import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -88,7 +89,7 @@ public class UHud extends DrawableHelper {
matrices.pop(); matrices.pop();
if (pony.getSpecies() == Race.CHANGELING && !client.player.isSneaking()) { 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) .map(Disguise::getAppearance)
.ifPresent(appearance -> { .ifPresent(appearance -> {

View file

@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.client.render;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.Equine;
import com.minelittlepony.unicopia.entity.ItemImpl; import com.minelittlepony.unicopia.entity.ItemImpl;
import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.Living;
@ -83,7 +83,7 @@ public class WorldRenderDelegate {
int fireTicks = pony.getMaster().doesRenderOnFire() ? 1 : 0; 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); effect.update(pony, false);
Disguise ve = effect.getDisguise(); Disguise ve = effect.getDisguise();

View file

@ -2,7 +2,6 @@ package com.minelittlepony.unicopia.command;
import java.util.function.Function; 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.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.CommandDispatcher;
@ -61,13 +60,10 @@ public class DisguiseCommand {
throw FAILED_EXCEPTION.create(); throw FAILED_EXCEPTION.create();
} }
DisguiseSpell effect = iplayer.getSpell(DisguiseSpell.class, true); iplayer.getSpellSlot()
.get(SpellType.DISGUISE, true)
if (effect == null) { .orElseGet(SpellType.DISGUISE::create)
iplayer.setSpell(SpellType.DISGUISE.create().setDisguise(entity)); .setDisguise(entity);
} else {
effect.setDisguise(entity);
}
if (!isSelf) { if (!isSelf) {
source.sendFeedback(new TranslatableText("commands.disguise.success.other", player.getName(), entity.getName()), true); 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) { static int reveal(ServerCommandSource source, PlayerEntity player) {
Pony iplayer = Pony.of(player); Pony iplayer = Pony.of(player);
iplayer.getSpellOrEmpty(DisguiseSpell.class).ifPresent(disguise -> { iplayer.getSpellSlot().get(SpellType.DISGUISE, true).ifPresent(disguise -> {
disguise.onDestroyed(iplayer); disguise.onDestroyed(iplayer);
}); });

View file

@ -4,7 +4,6 @@ import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Levelled; 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.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal;
import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal;
@ -89,11 +88,9 @@ public class Creature extends Living<LivingEntity> {
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
super.toNBT(compound); super.toNBT(compound);
Spell effect = getSpell(true); getSpellSlot().get(true).ifPresent(effect -> {
if (effect != null) {
compound.put("effect", SpellType.toNBT(effect)); compound.put("effect", SpellType.toNBT(effect));
} });
physics.toNBT(compound); physics.toNBT(compound);
} }

View file

@ -5,10 +5,9 @@ import java.util.stream.Stream;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.magic.Attached;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.DisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.network.EffectSync; import com.minelittlepony.unicopia.network.EffectSync;
@ -60,7 +59,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
} }
@Override @Override
public EffectSync getPrimarySpellSlot() { public EffectSync getSpellSlot() {
return effectDelegate; return effectDelegate;
} }
@ -79,15 +78,11 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
@Override @Override
public void tick() { public void tick() {
if (hasSpell()) { getSpellSlot().get(SpellPredicate.IS_ATTACHED, true).ifPresent(effect -> {
Attached effect = getSpell(Attached.class, true); if (!effect.onBodyTick(this)) {
setSpell(null);
if (effect != null) {
if (!effect.onBodyTick(this)) {
setSpell(null);
}
} }
} });
if (invinsibilityTicks > 0) { if (invinsibilityTicks > 0) {
invinsibilityTicks--; invinsibilityTicks--;
@ -142,18 +137,13 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
@Override @Override
public boolean onProjectileImpact(ProjectileEntity projectile) { public boolean onProjectileImpact(ProjectileEntity projectile) {
if (hasSpell()) { return getSpellSlot().get(true)
Spell effect = getSpell(true); .filter(effect -> !effect.isDead() && effect.handleProjectileImpact(projectile))
if (!effect.isDead() && effect.handleProjectileImpact(projectile)) { .isPresent();
return true;
}
}
return false;
} }
protected void handleFall(float distance, float damageMultiplier) { 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); spell.getDisguise().onImpact(this, distance, damageMultiplier);
}); });
} }

View file

@ -14,7 +14,7 @@ import com.minelittlepony.unicopia.FlightType;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.PlayerAttributes;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.projectile.ProjectileUtil;
@ -345,7 +345,7 @@ public class Disguise implements NbtSerialisable {
VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D)); VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
world.getOtherEntities(entity, box.expand(0.5), predicate.and(e -> { 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 -> { p.getDisguise().getCollissionShapes(ctx, shape -> {
if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) { if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
shapes.add(shape); shapes.add(shape);

View file

@ -4,6 +4,7 @@ import java.util.Optional;
import com.minelittlepony.common.util.animation.MotionCompositor; import com.minelittlepony.common.util.animation.MotionCompositor;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -46,7 +47,8 @@ public class PlayerCamera extends MotionCompositor {
} }
public Optional<Double> calculateDistance(double distance) { public Optional<Double> calculateDistance(double distance) {
return player.getSpellOrEmpty(DisguiseSpell.class, false) return player.getSpellSlot()
.get(SpellType.DISGUISE, false)
.map(DisguiseSpell::getDisguise) .map(DisguiseSpell::getDisguise)
.flatMap(d -> d.getDistance(player)) .flatMap(d -> d.getDistance(player))
.map(d -> distance * d); .map(d -> distance * d);

View file

@ -5,7 +5,6 @@ import java.util.Optional;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Spell;
import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityDimensions;
@ -72,13 +71,9 @@ public final class PlayerDimensions {
} }
Optional<Provider> getPredicate() { Optional<Provider> getPredicate() {
if (pony.hasSpell()) { return pony.getSpellSlot().get(true)
Spell effect = pony.getSpell(true); .filter(effect -> !effect.isDead() && effect instanceof Provider)
if (!effect.isDead() && effect instanceof Provider) { .map(effect -> (Provider)effect);
return Optional.of(((Provider)effect));
}
}
return Optional.empty();
} }
public interface Provider { public interface Provider {

View file

@ -3,8 +3,7 @@ package com.minelittlepony.unicopia.entity.player;
import com.minelittlepony.unicopia.FlightType; import com.minelittlepony.unicopia.FlightType;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.JoustingSpell;
import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.Jumper; import com.minelittlepony.unicopia.entity.Jumper;
@ -78,7 +77,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
@Override @Override
public boolean isRainbooming() { public boolean isRainbooming() {
return pony.getSpellOrEmpty(JoustingSpell.class).isPresent(); return pony.getSpellSlot().get(SpellType.JOUSTING, true).isPresent();
} }
@Override @Override
@ -448,14 +447,10 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
return FlightType.ARTIFICIAL; return FlightType.ARTIFICIAL;
} }
if (pony.hasSpell()) { return pony.getSpellSlot().get(true)
Spell effect = pony.getSpell(true); .filter(effect -> !effect.isDead() && effect instanceof FlightType.Provider)
if (!effect.isDead() && effect instanceof FlightType.Provider) { .map(effect -> ((FlightType.Provider)effect).getFlightType(pony))
return ((FlightType.Provider)effect).getFlightType(pony); .orElse(pony.getSpecies().getFlightType());
}
}
return pony.getSpecies().getFlightType();
} }
public void updateFlightStat(boolean flying) { public void updateFlightStat(boolean flying) {

View file

@ -14,7 +14,6 @@ import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.WorldTribeManager; import com.minelittlepony.unicopia.WorldTribeManager;
import com.minelittlepony.unicopia.ability.AbilityDispatcher; import com.minelittlepony.unicopia.ability.AbilityDispatcher;
import com.minelittlepony.unicopia.ability.magic.Spell; 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.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.entity.Physics;
import com.minelittlepony.unicopia.entity.PonyContainer; import com.minelittlepony.unicopia.entity.PonyContainer;
@ -134,7 +133,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
@Override @Override
public boolean isInvisible() { public boolean isInvisible() {
return invisible && hasSpell(); return invisible && getSpellSlot().isPresent();
} }
public boolean isSpeciesPersisted() { public boolean isSpeciesPersisted() {
@ -289,7 +288,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
float g = gravity.getGravityModifier(); 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()) { if (g != 1 || extraProtection || getSpecies().canFly() && !entity.isCreative() && !entity.isSpectator()) {
@ -384,11 +383,9 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
compound.put("powers", powers.toNBT()); compound.put("powers", powers.toNBT());
compound.put("gravity", gravity.toNBT()); compound.put("gravity", gravity.toNBT());
Spell effect = getSpell(true); getSpellSlot().get(true).ifPresent(effect ->{
if (effect != null) {
compound.put("effect", SpellType.toNBT(effect)); compound.put("effect", SpellType.toNBT(effect));
} });
} }
@Override @Override
@ -403,7 +400,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
magicExhaustion = compound.getFloat("magicExhaustion"); magicExhaustion = compound.getFloat("magicExhaustion");
if (compound.contains("effect")) { 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<PlayerEntity> implements Transmittable, Copieab
public void copyFrom(Pony oldPlayer) { public void copyFrom(Pony oldPlayer) {
speciesPersisted = oldPlayer.speciesPersisted; speciesPersisted = oldPlayer.speciesPersisted;
if (!oldPlayer.getEntity().removed) { if (!oldPlayer.getEntity().removed) {
setSpell(oldPlayer.getSpell(true)); setSpell(oldPlayer.getSpellSlot().get(true).orElse(null));
} }
setSpecies(oldPlayer.getSpecies()); setSpecies(oldPlayer.getSpecies());
setDirty(); setDirty();

View file

@ -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.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; 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.Creature;
import com.minelittlepony.unicopia.entity.PonyContainer; import com.minelittlepony.unicopia.entity.PonyContainer;
import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.behaviour.Disguise;
@ -82,7 +83,7 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
@Inject(method = "isClimbing()Z", at = @At("HEAD"), cancellable = true) @Inject(method = "isClimbing()Z", at = @At("HEAD"), cancellable = true)
public void onIsClimbing(CallbackInfoReturnable<Boolean> info) { public void onIsClimbing(CallbackInfoReturnable<Boolean> info) {
if (get() instanceof Pony && horizontalCollision) { if (get() instanceof Pony && horizontalCollision) {
((Pony)get()).getSpellOrEmpty(DisguiseSpell.class, false) ((Pony)get()).getSpellSlot().get(SpellType.DISGUISE, false)
.map(DisguiseSpell::getDisguise) .map(DisguiseSpell::getDisguise)
.filter(Disguise::canClimbWalls) .filter(Disguise::canClimbWalls)
.ifPresent(v -> { .ifPresent(v -> {
@ -95,7 +96,7 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
@Inject(method = "isPushable()Z", at = @At("HEAD"), cancellable = true) @Inject(method = "isPushable()Z", at = @At("HEAD"), cancellable = true)
private void onIsPushable(CallbackInfoReturnable<Boolean> info) { private void onIsPushable(CallbackInfoReturnable<Boolean> info) {
Caster.of(this) Caster.of(this)
.flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false)) .flatMap(c -> c.getSpellSlot().get(SpellType.DISGUISE, false))
.map(DisguiseSpell::getDisguise) .map(DisguiseSpell::getDisguise)
.map(Disguise::getAppearance) .map(Disguise::getAppearance)
.filter(Entity::isPushable) .filter(Entity::isPushable)

View file

@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 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.Equine;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
@ -20,7 +20,7 @@ abstract class MixinTargetPredicate {
public void onTest(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> info) { public void onTest(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> info) {
Equine<?> eq = Equine.of(targetEntity); Equine<?> eq = Equine.of(targetEntity);
if (eq instanceof Pony) { 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) { if (spell.getDisguise().getAppearance() == baseEntity) {
info.setReturnValue(false); info.setReturnValue(false);
} }

View file

@ -6,6 +6,7 @@ import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.SpellType;
import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedData;
@ -13,7 +14,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Identifier; 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 * Since we can't have our own serializers, we have to intelligently
* determine whether to update it from an nbt tag. * determine whether to update it from an nbt tag.
* *
@ -21,85 +22,83 @@ import net.minecraft.util.Identifier;
*/ */
public class EffectSync { public class EffectSync {
@Nullable private Optional<Spell> spell = Optional.empty();
private Spell effect;
private final Caster<?> owned; private final Caster<?> owner;
private final TrackedData<CompoundTag> param; private final TrackedData<CompoundTag> param;
@Nullable @Nullable
private CompoundTag lastValue; private CompoundTag lastValue;
public EffectSync(Caster<?> owned, TrackedData<CompoundTag> param) { public EffectSync(Caster<?> owner, TrackedData<CompoundTag> param) {
this.owned = owned; this.owner = owner;
this.param = param; this.param = param;
} }
public <T extends Spell> Optional<T> getOrEmpty(Class<T> type, boolean update) { /**
T effect = get(type, update); * Gets the active effect for this caster updating it if needed.
*/
if (effect == null || effect.isDead()) { public <T extends Spell> Optional<T> get(boolean update) {
return Optional.empty(); return get(null, update);
}
return Optional.of(effect);
} }
/**
* Gets the active effect for this caster updating it if needed.
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <E extends Spell> E get(Class<E> type, boolean update) { public <T extends Spell> Optional<T> get(@Nullable SpellPredicate<T> type, boolean update) {
if (update) { if (update) {
sync(true); sync(true);
} }
if (effect == null || type == null || type.isAssignableFrom(effect.getClass())) { if (checkReference() && (type == null || type.test(spell.get()))) {
return (E)effect; return (Optional<T>)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); sync(false);
return effect != null; return checkReference();
}
private boolean checkReference() {
return spell.isPresent() && !spell.get().isDead();
} }
private void sync(boolean force) { 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 (comp == null || !comp.contains("effect_id")) {
if (effect != null) { updateReference(null);
effect.setDead(); } else if (!checkReference() || !effect.getType().getId().equals(new Identifier(comp.getString("effect_id")))) {
effect = null; updateReference(SpellType.fromNBT(comp));
} } else if (owner.getEntity().world.isClient()) {
return; if (lastValue != comp || !(comp == null || comp.equals(lastValue))) {
} else { lastValue = comp;
if (effect == null || !effect.getType().getId().equals(new Identifier(comp.getString("effect_id")))) { effect.fromNBT(comp);
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);
} }
} else if ((force || !owner.isClient()) && effect.isDirty()) {
put(effect);
} }
} }
public void set(@Nullable Spell effect) { public void put(@Nullable Spell effect) {
if (this.effect != null && this.effect != effect) { updateReference(effect);
this.effect.setDead(); owner.getEntity().getDataTracker().set(param, effect == null ? new CompoundTag() : SpellType.toNBT(effect));
} }
this.effect = effect;
if (effect == null) { private void updateReference(@Nullable Spell effect) {
owned.getEntity().getDataTracker().set(param, new CompoundTag()); if (spell.isPresent() && spell.get() != effect) {
} else { spell.get().setDead();
owned.getEntity().getDataTracker().set(param, SpellType.toNBT(effect));
} }
spell = Optional.ofNullable(effect);
} }
} }

View file

@ -4,6 +4,7 @@ import java.util.Optional;
import java.util.function.Consumer; import java.util.function.Consumer;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.Equine;
@ -66,7 +67,7 @@ public class ParticleHandle {
public void attach(Caster<?> caster) { public void attach(Caster<?> caster) {
this.linked = true; this.linked = true;
this.caster = Optional.of(caster); 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() { public void detach() {
@ -81,10 +82,10 @@ public class ParticleHandle {
caster = caster.filter(c -> { caster = caster.filter(c -> {
Entity e = c.getEntity(); Entity e = c.getEntity();
return Equine.of(e) == c return Equine.of(e) == c
&& c.hasSpell() && c.getSpellSlot().get(false)
&& c.getSpell(false).getType().equals(effect) .filter(s -> s.getType() == effect)
.isPresent()
&& e != null && e != null
&& c.getWorld().getEntityById(e.getEntityId()) != null; && c.getWorld().getEntityById(e.getEntityId()) != null;
}); });

View file

@ -2,11 +2,12 @@ package com.minelittlepony.unicopia.projectile;
import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.UEntities; 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.Caster;
import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.ability.magic.Levelled;
import com.minelittlepony.unicopia.ability.magic.Magical; import com.minelittlepony.unicopia.ability.magic.Magical;
import com.minelittlepony.unicopia.ability.magic.Spell; 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.ability.magic.spell.SpellType;
import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.Physics; import com.minelittlepony.unicopia.entity.Physics;
@ -77,7 +78,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override @Override
protected Item getDefaultItem() { 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 GOOD: return Items.SNOWBALL;
case BAD: return Items.MAGMA_CREAM; case BAD: return Items.MAGMA_CREAM;
default: return Items.AIR; default: return Items.AIR;
@ -111,11 +112,11 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override @Override
public Affinity getAffinity() { public Affinity getAffinity() {
return hasSpell() ? getSpell(true).getAffinity() : Affinity.NEUTRAL; return getSpellSlot().get(true).map(Affine::getAffinity).orElse(Affinity.NEUTRAL);
} }
@Override @Override
public EffectSync getPrimarySpellSlot() { public EffectSync getSpellSlot() {
return effectDelegate; return effectDelegate;
} }
@ -158,17 +159,13 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
setNoGravity(false); setNoGravity(false);
} }
if (hasSpell()) { if (getSpellSlot().isPresent()) {
if (lastBlockPos == null || !lastBlockPos.equals(getBlockPos())) { if (lastBlockPos == null || !lastBlockPos.equals(getBlockPos())) {
lastBlockPos = getBlockPos(); lastBlockPos = getBlockPos();
} }
Thrown spell = getSpell(Thrown.class, true); if (!getSpellSlot().get(SpellPredicate.IS_THROWN, true).filter(spell -> spell.onThrownTick(this)).isPresent()) {
if (spell.isDead()) {
remove(); remove();
} else {
spell.onThrownTick(this);
} }
} }
@ -228,10 +225,9 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
public void writeCustomDataToTag(CompoundTag compound) { public void writeCustomDataToTag(CompoundTag compound) {
super.writeCustomDataToTag(compound); super.writeCustomDataToTag(compound);
physics.toNBT(compound); physics.toNBT(compound);
getSpellSlot().get(true).ifPresent(effect -> {
if (hasSpell()) { compound.put("effect", SpellType.toNBT(effect));
compound.put("effect", SpellType.toNBT(getSpell(true))); });
}
} }
@Override @Override
@ -249,13 +245,9 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override @Override
protected void onBlockHit(BlockHitResult hit) { protected void onBlockHit(BlockHitResult hit) {
if (hasSpell()) { getSpellSlot().get(SpellPredicate.IS_THROWN, true).ifPresent(effect -> {
Spell effect = getSpell(true); effect.onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos()));
});
if (effect instanceof ProjectileDelegate) {
((ProjectileDelegate)effect).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos()));
}
}
if (getItem().getItem() instanceof ProjectileDelegate) { if (getItem().getItem() instanceof ProjectileDelegate) {
((ProjectileDelegate)getItem().getItem()).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos())); ((ProjectileDelegate)getItem().getItem()).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos()));