mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-01 03:26:44 +01:00
Better handle exceptions in ticking spells and try to prevent spells from being destroyed more than once
This commit is contained in:
parent
820856fdc4
commit
77d6e6d1b0
21 changed files with 87 additions and 76 deletions
|
@ -20,8 +20,9 @@ import net.minecraft.util.hit.EntityHitResult;
|
|||
public abstract class AbstractDelegatingSpell implements Spell,
|
||||
ProjectileDelegate.ConfigurationListener, ProjectileDelegate.BlockHitListener, ProjectileDelegate.EntityHitListener {
|
||||
|
||||
private boolean isDirty;
|
||||
private boolean dirty;
|
||||
private boolean hidden;
|
||||
private boolean destroyed;
|
||||
|
||||
private UUID uuid = UUID.randomUUID();
|
||||
|
||||
|
@ -59,7 +60,7 @@ public abstract class AbstractDelegatingSpell implements Spell,
|
|||
}
|
||||
|
||||
@Override
|
||||
public UUID getUuid() {
|
||||
public final UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
@ -75,12 +76,12 @@ public abstract class AbstractDelegatingSpell implements Spell,
|
|||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
return isDirty || getDelegates().stream().anyMatch(Spell::isDirty);
|
||||
return dirty || getDelegates().stream().anyMatch(Spell::isDirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirty() {
|
||||
isDirty = true;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,8 +95,17 @@ public abstract class AbstractDelegatingSpell implements Spell,
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
getDelegates().forEach(a -> a.onDestroyed(caster));
|
||||
public final void destroy(Caster<?> caster) {
|
||||
if (destroyed) {
|
||||
return;
|
||||
}
|
||||
destroyed = true;
|
||||
setDead();
|
||||
onDestroyed(caster);
|
||||
}
|
||||
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
getDelegates().forEach(a -> a.destroy(caster));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,7 +137,7 @@ public abstract class AbstractDelegatingSpell implements Spell,
|
|||
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound) {
|
||||
isDirty = false;
|
||||
dirty = false;
|
||||
hidden = compound.getBoolean("hidden");
|
||||
if (compound.contains("uuid")) {
|
||||
uuid = compound.getUuid("uuid");
|
||||
|
|
|
@ -27,7 +27,7 @@ public abstract class AbstractDisguiseSpell extends AbstractSpell implements Dis
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
caster.asEntity().calculateDimensions();
|
||||
caster.asEntity().setInvisible(false);
|
||||
if (caster instanceof Pony) {
|
||||
|
@ -51,12 +51,6 @@ public abstract class AbstractDisguiseSpell extends AbstractSpell implements Dis
|
|||
return situation == Situation.BODY && update(source, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
disguise.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound) {
|
||||
super.toNBT(compound);
|
||||
|
|
|
@ -24,6 +24,7 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I
|
|||
|
||||
public DispersableDisguiseSpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
setHidden(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,13 +93,4 @@ public class DispersableDisguiseSpell extends AbstractDisguiseSpell implements I
|
|||
public Optional<EntityAppearance> getAppearance() {
|
||||
return isSuppressed() ? Optional.empty() : super.getAppearance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHidden(boolean hidden) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> source) {
|
||||
protected void onDestroyed(Caster<?> source) {
|
||||
if (!source.isClient()) {
|
||||
castEntity.getTarget().ifPresent(target -> {
|
||||
getWorld(source).map(Ether::get)
|
||||
|
|
|
@ -32,11 +32,11 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
|||
|
||||
public RainboomAbilitySpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
setHidden(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
protected void onDestroyed(Caster<?> source) {
|
||||
particlEffect.destroy();
|
||||
}
|
||||
|
||||
|
@ -93,13 +93,4 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
|||
super.fromNBT(compound);
|
||||
age = compound.getInt("age");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHidden(boolean hidden) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ public interface Spell extends NbtSerialisable, Affine {
|
|||
/**
|
||||
* Called when a gem is destroyed.
|
||||
*/
|
||||
void onDestroyed(Caster<?> caster);
|
||||
void destroy(Caster<?> caster);
|
||||
|
||||
/**
|
||||
* Converts this spell into a placeable spell.
|
||||
|
|
|
@ -14,6 +14,7 @@ public abstract class AbstractSpell implements Spell {
|
|||
private boolean dead;
|
||||
private boolean dirty;
|
||||
private boolean hidden;
|
||||
private boolean destroyed;
|
||||
|
||||
private CustomisedSpellType<?> type;
|
||||
|
||||
|
@ -43,33 +44,33 @@ public abstract class AbstractSpell implements Spell {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
public final void setDead() {
|
||||
dead = true;
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDead() {
|
||||
public final boolean isDead() {
|
||||
return dead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
public final boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirty() {
|
||||
public final void setDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
public final boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHidden(boolean hidden) {
|
||||
public final void setHidden(boolean hidden) {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
|
@ -78,8 +79,17 @@ public abstract class AbstractSpell implements Spell {
|
|||
return getType().getAffinity();
|
||||
}
|
||||
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
public final void destroy(Caster<?> caster) {
|
||||
if (destroyed) {
|
||||
return;
|
||||
}
|
||||
destroyed = true;
|
||||
setDead();
|
||||
onDestroyed(caster);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -138,7 +138,8 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
super.onDestroyed(caster);
|
||||
target.getOrEmpty(caster.asWorld()).ifPresent(target -> target.setGlowing(false));
|
||||
}
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell,
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> source) {
|
||||
protected void onDestroyed(Caster<?> source) {
|
||||
particlEffect.destroy();
|
||||
if (source.asEntity() instanceof LivingEntity l) {
|
||||
MODIFIERS.forEach((attribute, modifier) -> {
|
||||
|
|
|
@ -104,7 +104,7 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pla
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
caster.getOriginatingCaster().asEntity().setGlowing(false);
|
||||
target.ifPresent(caster.asWorld(), e -> e.setGlowing(false));
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ public class HydrophobicSpell extends AbstractSpell {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
storedFluidPositions.removeIf(entry -> {
|
||||
entry.restore(caster.asWorld());
|
||||
return true;
|
||||
|
|
|
@ -90,7 +90,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
if (caster.isClient()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
super.onDestroyed(caster);
|
||||
if (initialized && !caster.isClient()) {
|
||||
counterpart.ifPresent(caster.asWorld(), e -> {
|
||||
|
|
|
@ -151,7 +151,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
if (caster.isClient()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -186,7 +186,8 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> caster) {
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
particleEffect.destroy();
|
||||
Ether ether = Ether.get(caster.asWorld());
|
||||
ether.remove(getType(), caster.asEntity().getUuid());
|
||||
getTarget(caster).ifPresent(e -> e.setTaken(false));
|
||||
|
@ -213,10 +214,4 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
|
|||
(180 - yaw) * MathHelper.RADIANS_PER_DEGREE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
particleEffect.destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,8 +54,7 @@ public class ShieldSpell extends AbstractSpell {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
protected void onDestroyed(Caster<?> caster) {
|
||||
particlEffect.destroy();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ import com.minelittlepony.unicopia.ability.Abilities;
|
|||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||
import com.minelittlepony.unicopia.advancement.UCriteria;
|
||||
|
@ -291,12 +290,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
|||
@Override
|
||||
public void tick() {
|
||||
tickers.forEach(Tickable::tick);
|
||||
|
||||
try {
|
||||
getSpellSlot().forEach(spell -> Operation.ofBoolean(spell.tick(this, Situation.BODY)), entity.getWorld().isClient);
|
||||
} catch (Exception e) {
|
||||
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", entity, e);
|
||||
}
|
||||
effectDelegate.tick(Situation.BODY);
|
||||
|
||||
if (!(entity instanceof PlayerEntity)) {
|
||||
if (!entity.hasVehicle() && getCarrierId().isPresent() && !asWorld().isClient && entity.age % 10 == 0) {
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.minelittlepony.unicopia.*;
|
|||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.Levelled;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
import com.minelittlepony.unicopia.entity.EntityPhysics;
|
||||
|
@ -67,7 +66,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<CastS
|
|||
return;
|
||||
}
|
||||
|
||||
if (!getSpellSlot().forEach(spell -> Operation.ofBoolean(spell.tick(this, Situation.GROUND_ENTITY)), getWorld().isClient)) {
|
||||
if (!effectDelegate.tick(Situation.GROUND_ENTITY)) {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,11 @@ import java.util.stream.Stream;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
|
||||
|
@ -41,6 +43,26 @@ public class EffectSync implements SpellContainer, NbtSerialisable {
|
|||
this.param = param;
|
||||
}
|
||||
|
||||
public boolean tick(Situation situation) {
|
||||
return tick(spell -> Operation.ofBoolean(spell.tick(owner, situation)));
|
||||
}
|
||||
|
||||
public boolean tick(Function<Spell, Operation> tickAction) {
|
||||
try {
|
||||
return forEach(spell -> {
|
||||
try {
|
||||
return tickAction.apply(spell);
|
||||
} catch (Throwable t) {
|
||||
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner, t);
|
||||
}
|
||||
return Operation.REMOVE;
|
||||
}, owner.isClient());
|
||||
} catch (Exception e) {
|
||||
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner.asEntity(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(UUID id) {
|
||||
return spells.containsReference(id) || spells.getReferences().anyMatch(s -> s.equalsOrContains(id));
|
||||
|
@ -60,8 +82,8 @@ public class EffectSync implements SpellContainer, NbtSerialisable {
|
|||
public void put(@Nullable Spell effect) {
|
||||
spells.addReference(effect);
|
||||
write();
|
||||
if (owner instanceof UpdateCallback) {
|
||||
((UpdateCallback)owner).onSpellSet(effect);
|
||||
if (owner instanceof UpdateCallback callback) {
|
||||
callback.onSpellSet(effect);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,8 +60,7 @@ public class SpellNetworkedReference<T extends Spell> implements NetworkedRefere
|
|||
currentValue = Optional.ofNullable(newValue);
|
||||
|
||||
if (oldValue != null && (newValue == null || !oldValue.getUuid().equals(newValue.getUuid()))) {
|
||||
oldValue.setDead();
|
||||
oldValue.onDestroyed(owner);
|
||||
oldValue.destroy(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import com.minelittlepony.unicopia.Affinity;
|
||||
import com.minelittlepony.unicopia.EquinePredicates;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.WeaklyOwned;
|
||||
import com.minelittlepony.unicopia.ability.magic.Affine;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
|
@ -198,7 +199,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
return;
|
||||
}
|
||||
|
||||
getSpellSlot().get(true).filter(spell -> spell.tick(this, Situation.PROJECTILE));
|
||||
effectDelegate.tick(Situation.PROJECTILE);
|
||||
|
||||
if (getHydrophobic()) {
|
||||
if (StatePredicate.isFluid(getWorld().getBlockState(getBlockPos()))) {
|
||||
|
@ -317,11 +318,15 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
}
|
||||
|
||||
protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
|
||||
getSpellSlot().forEach(spell -> {
|
||||
effectDelegate.tick(spell -> {
|
||||
Optional.ofNullable(predicate.apply(spell)).ifPresent(consumer);
|
||||
return Operation.SKIP;
|
||||
}, getWorld().isClient);
|
||||
Optional.ofNullable(predicate.apply(getItem().getItem())).ifPresent(consumer);
|
||||
});
|
||||
try {
|
||||
Optional.ofNullable(predicate.apply(getItem().getItem())).ifPresent(consumer);
|
||||
} catch (Throwable t) {
|
||||
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", owner, t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue