More refinements to portal spells

This commit is contained in:
Sollace 2022-09-16 21:19:54 +02:00
parent b83f947488
commit 88e078cfc7
3 changed files with 87 additions and 16 deletions

View file

@ -91,6 +91,13 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
castEntity.set(entity); castEntity.set(entity);
setDirty(); setDirty();
} else {
if (getWorld(source).map(Ether::get)
.flatMap(ether -> castEntity.getId().flatMap(id -> ether.getEntry(getType(), id)))
.isEmpty()) {
setDead();
}
} }
} }
@ -100,9 +107,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
if (situation == Situation.GROUND_ENTITY) { if (situation == Situation.GROUND_ENTITY) {
if (!source.isClient()) { if (!source.isClient()) {
Ether ether = Ether.get(source.getReferenceWorld()); if (Ether.get(source.getReferenceWorld()).getEntry(getType(), source).isEmpty()) {
if (ether.getEntry(getType(), source).filter(Ether.Entry::isAlive).isEmpty()) {
ether.remove(getType(), source);
setDead(); setDead();
return false; return false;
} }
@ -128,6 +133,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
.flatMap(ether -> ether.getEntry(getType(), id)) .flatMap(ether -> ether.getEntry(getType(), id))
.ifPresent(Ether.Entry::markDead); .ifPresent(Ether.Entry::markDead);
}); });
castEntity.set(null);
getSpellEntity(source).ifPresent(e -> { getSpellEntity(source).ifPresent(e -> {
castEntity.set(null); castEntity.set(null);
}); });

View file

@ -1,25 +1,33 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect; package com.minelittlepony.unicopia.ability.magic.spell.effect;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.block.data.Ether; import com.minelittlepony.unicopia.block.data.Ether;
import com.minelittlepony.unicopia.entity.CastSpellEntity; import com.minelittlepony.unicopia.entity.CastSpellEntity;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.particle.*; import com.minelittlepony.unicopia.particle.*;
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.WorldEvents;
public class PortalSpell extends AbstractSpell { public class PortalSpell extends AbstractSpell {
public static final int MAX_COOLDOWN = 20;
private final EntityReference<CastSpellEntity> teleportationTarget = new EntityReference<>(); private final EntityReference<CastSpellEntity> teleportationTarget = new EntityReference<>();
private boolean publishedPosition; private boolean publishedPosition;
private final ParticleHandle particlEffect = new ParticleHandle(); private final ParticleHandle particlEffect = new ParticleHandle();
private int cooldown = MAX_COOLDOWN;
protected PortalSpell(CustomisedSpellType<?> type) { protected PortalSpell(CustomisedSpellType<?> type) {
super(type); super(type);
} }
@ -31,7 +39,20 @@ public class PortalSpell extends AbstractSpell {
@Override @Override
public boolean tick(Caster<?> source, Situation situation) { public boolean tick(Caster<?> source, Situation situation) {
if (situation == Situation.GROUND) { if (situation == Situation.GROUND) {
if (!source.isClient()) {
teleportationTarget.getId().ifPresent(id -> {
Ether ether = Ether.get(source.getReferenceWorld());
if (ether.getEntry(getType(), id).isEmpty()) {
Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + id);
teleportationTarget.set(null);
setDirty();
source.getReferenceWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, source.getOrigin(), Block.getRawIdFromState(Blocks.GLASS.getDefaultState()));
}
});
}
teleportationTarget.getPosition().ifPresentOrElse( teleportationTarget.getPosition().ifPresentOrElse(
targetPos -> tickWithTargetLink(source, targetPos), targetPos -> tickWithTargetLink(source, targetPos),
() -> findLink(source) () -> findLink(source)
@ -42,11 +63,21 @@ public class PortalSpell extends AbstractSpell {
Ether.get(source.getReferenceWorld()).put(getType(), source); Ether.get(source.getReferenceWorld()).put(getType(), source);
} }
if (source.isClient()) { if (source.isClient() && cooldown <= 0) {
Vec3d origin = source.getOriginVector(); Vec3d origin = source.getOriginVector();
source.spawnParticles(origin, new Sphere(true, 2, 1, 0, 1), 17, pos -> { ParticleEffect effect = teleportationTarget.getPosition()
source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO); .map(target -> {
getType();
return new FollowingParticleEffect(UParticles.HEALTH_DRAIN, target, 0.2F).withChild(ParticleTypes.ELECTRIC_SPARK);
})
.orElseGet(() -> {
new MagicParticleEffect(getType().getColor());
return ParticleTypes.ELECTRIC_SPARK;
});
source.spawnParticles(origin, new Sphere(true, 2, 1, 0, 1), 3, pos -> {
source.addParticle(effect, pos, Vec3d.ZERO);
}); });
} }
} }
@ -56,11 +87,15 @@ public class PortalSpell extends AbstractSpell {
private void tickWithTargetLink(Caster<?> source, Vec3d targetPos) { private void tickWithTargetLink(Caster<?> source, Vec3d targetPos) {
particlEffect.update(getUuid(), source, spawner -> { particlEffect.update(getUuid(), source, spawner -> {
spawner.addParticle(new SphereParticleEffect(UParticles.DISK, getType().getColor(), 0.9F, 2), source.getOriginVector(), Vec3d.ZERO); spawner.addParticle(new SphereParticleEffect(UParticles.DISK, getType().getColor(), 0.8F, 2), source.getOriginVector(), Vec3d.ZERO);
}).ifPresent(p -> {
p.setAttribute(Attachment.ATTR_COLOR, getType().getColor());
}); });
if (cooldown > 0) {
cooldown--;
setDirty();
return;
}
Vec3d center = source.getOriginVector(); Vec3d center = source.getOriginVector();
source.findAllEntitiesInRange(1).filter(e -> true).forEach(entity -> { source.findAllEntitiesInRange(1).filter(e -> true).forEach(entity -> {
if (!entity.hasPortalCooldown() && entity.timeUntilRegen <= 0) { if (!entity.hasPortalCooldown() && entity.timeUntilRegen <= 0) {
@ -70,13 +105,21 @@ public class PortalSpell extends AbstractSpell {
entity.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1, 1); entity.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1, 1);
entity.teleport(destination.x, destination.y, destination.z); entity.teleport(destination.x, destination.y, destination.z);
entity.playSound(USounds.ENTITY_PLAYER_UNICORN_TELEPORT, 1, 1);
setDirty();
} }
ParticleUtils.spawnParticles(new MagicParticleEffect(getType().getColor()), entity, 7); ParticleUtils.spawnParticles(new MagicParticleEffect(getType().getColor()), entity, 7);
}); });
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void findLink(Caster<?> source) { private void findLink(Caster<?> source) {
if (source.isClient()) {
return;
}
Ether ether = Ether.get(source.getReferenceWorld()); Ether ether = Ether.get(source.getReferenceWorld());
ether.getEntries(getType()) ether.getEntries(getType())
.stream() .stream()
@ -85,12 +128,15 @@ public class PortalSpell extends AbstractSpell {
.ifPresent(entry -> { .ifPresent(entry -> {
entry.setTaken(true); entry.setTaken(true);
teleportationTarget.copyFrom((EntityReference<CastSpellEntity>)entry.entity); teleportationTarget.copyFrom((EntityReference<CastSpellEntity>)entry.entity);
setDirty();
}); });
} }
@Override @Override
public void onDestroyed(Caster<?> caster) { public void onDestroyed(Caster<?> caster) {
Ether.get(caster.getReferenceWorld()).remove(getType(), caster.getEntity().getUuid()); Ether ether = Ether.get(caster.getReferenceWorld());
ether.remove(getType(), caster.getEntity().getUuid());
teleportationTarget.getId().flatMap(id -> ether.getEntry(getType(), id)).ifPresent(e -> e.setTaken(false));
} }
@Override @Override
@ -98,6 +144,7 @@ public class PortalSpell extends AbstractSpell {
super.toNBT(compound); super.toNBT(compound);
compound.putBoolean("publishedPosition", publishedPosition); compound.putBoolean("publishedPosition", publishedPosition);
compound.put("teleportationTarget", teleportationTarget.toNBT()); compound.put("teleportationTarget", teleportationTarget.toNBT());
compound.putInt("cooldown", cooldown);
} }
@Override @Override
@ -105,6 +152,7 @@ public class PortalSpell extends AbstractSpell {
super.fromNBT(compound); super.fromNBT(compound);
publishedPosition = compound.getBoolean("publishedPosition"); publishedPosition = compound.getBoolean("publishedPosition");
teleportationTarget.fromNBT(compound.getCompound("teleportationTarget")); teleportationTarget.fromNBT(compound.getCompound("teleportationTarget"));
cooldown = compound.getInt("cooldown");
} }
@Override @Override

View file

@ -49,7 +49,11 @@ public class Ether extends PersistentState {
synchronized (locker) { synchronized (locker) {
advertisingEndpoints.forEach((id, uuids) -> { advertisingEndpoints.forEach((id, uuids) -> {
NbtList list = new NbtList(); NbtList list = new NbtList();
uuids.forEach(uuid -> list.add(uuid.toNBT())); uuids.forEach(uuid -> {
if (uuid.isAlive()) {
list.add(uuid.toNBT());
}
});
compound.put(id.toString(), list); compound.put(id.toString(), list);
}); });
@ -69,7 +73,7 @@ public class Ether extends PersistentState {
Identifier typeId = spellType.getId(); Identifier typeId = spellType.getId();
Set<Entry> refs = advertisingEndpoints.get(typeId); Set<Entry> refs = advertisingEndpoints.get(typeId);
if (refs != null) { if (refs != null) {
refs.removeIf(ref -> ref.entity.getId().orElse(Util.NIL_UUID).equals(id)); refs.removeIf(ref -> ref.removed || ref.entity.getId().orElse(Util.NIL_UUID).equals(id));
if (refs.isEmpty()) { if (refs.isEmpty()) {
advertisingEndpoints.remove(typeId); advertisingEndpoints.remove(typeId);
} }
@ -88,7 +92,14 @@ public class Ether extends PersistentState {
private Set<Entry> getEntries(Identifier typeId) { private Set<Entry> getEntries(Identifier typeId) {
synchronized (locker) { synchronized (locker) {
return advertisingEndpoints.computeIfAbsent(typeId, i -> new HashSet<>()); return advertisingEndpoints.compute(typeId, (k, old) -> {
if (old == null) {
old = new HashSet<>();
} else {
old.removeIf(Entry::isDead);
}
return old;
});
} }
} }
@ -117,11 +128,16 @@ public class Ether extends PersistentState {
entity = new EntityReference<>(caster.getEntity()); entity = new EntityReference<>(caster.getEntity());
} }
public boolean isAlive() { boolean isAlive() {
return !removed; return !removed;
} }
boolean isDead() {
return removed;
}
public void markDead() { public void markDead() {
Unicopia.LOGGER.debug("Marking " + entity.getId().orElse(null) + " as dead");
removed = true; removed = true;
markDirty(); markDirty();
} }
@ -138,9 +154,10 @@ public class Ether extends PersistentState {
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
entity.toNBT(compound); entity.toNBT(compound);
compound.putBoolean("remove", removed); compound.putBoolean("removed", removed);
compound.putBoolean("taken", taken); compound.putBoolean("taken", taken);
} }
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
entity.fromNBT(compound); entity.fromNBT(compound);