mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-08 06:26:43 +01:00
Fixed spell entities becoming detached when cancelling the spell from very far away
This commit is contained in:
parent
734c256822
commit
2a9f19fc9f
3 changed files with 118 additions and 30 deletions
|
@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||
import com.minelittlepony.unicopia.block.data.Ether;
|
||||
import com.minelittlepony.unicopia.entity.CastSpellEntity;
|
||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||
import com.minelittlepony.unicopia.entity.UEntities;
|
||||
|
@ -86,6 +87,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
entity.getSpellSlot().put(spell.toPlaceable());
|
||||
entity.setMaster(source);
|
||||
entity.world.spawnEntity(entity);
|
||||
Ether.get(entity.world).put(getType(), entity);
|
||||
|
||||
castEntity.set(entity);
|
||||
setDirty();
|
||||
|
@ -96,6 +98,16 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
}
|
||||
|
||||
if (situation == Situation.GROUND_ENTITY) {
|
||||
|
||||
if (!source.isClient()) {
|
||||
Ether ether = Ether.get(source.getReferenceWorld());
|
||||
if (ether.getEntry(getType(), source).filter(Ether.Entry::isAlive).isEmpty()) {
|
||||
ether.remove(getType(), source);
|
||||
setDead();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
particlEffect.update(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
||||
}).ifPresent(p -> {
|
||||
|
@ -108,24 +120,15 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
return !isDead();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches this spell from the placed version.
|
||||
* This spell and the placed entity effectively become independent.
|
||||
*
|
||||
* @return The previous cast spell entity if one existed, otherwise empty.
|
||||
*/
|
||||
protected Optional<CastSpellEntity> detach(Caster<?> source) {
|
||||
return getSpellEntity(source).map(e -> {
|
||||
castEntity.set(null);
|
||||
return e;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Caster<?> source) {
|
||||
if (!source.isClient()) {
|
||||
castEntity.getId().ifPresent(id -> {
|
||||
getWorld(source).map(Ether::get)
|
||||
.flatMap(ether -> ether.getEntry(getType(), id))
|
||||
.ifPresent(Ether.Entry::markDead);
|
||||
});
|
||||
getSpellEntity(source).ifPresent(e -> {
|
||||
e.getSpellSlot().clear();
|
||||
castEntity.set(null);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class PortalSpell extends AbstractSpell {
|
|||
if (situation == Situation.GROUND) {
|
||||
teleportationTarget.getPosition().ifPresentOrElse(
|
||||
targetPos -> tickWithTargetLink(source, targetPos),
|
||||
() -> advertiseAvailable(source)
|
||||
() -> findLink(source)
|
||||
);
|
||||
|
||||
if (!publishedPosition) {
|
||||
|
@ -76,15 +76,15 @@ public class PortalSpell extends AbstractSpell {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void advertiseAvailable(Caster<?> source) {
|
||||
private void findLink(Caster<?> source) {
|
||||
Ether ether = Ether.get(source.getReferenceWorld());
|
||||
ether.getIds(getType())
|
||||
ether.getEntries(getType())
|
||||
.stream()
|
||||
.filter(id -> !id.referenceEquals(source.getEntity()))
|
||||
.filter(entry -> entry.isAvailable() && !entry.entity.referenceEquals(source.getEntity()))
|
||||
.findAny()
|
||||
.ifPresent(ref -> {
|
||||
ether.remove(getType(), ref.getId().get());
|
||||
teleportationTarget.copyFrom((EntityReference<CastSpellEntity>)ref);
|
||||
.ifPresent(entry -> {
|
||||
entry.setTaken(true);
|
||||
teleportationTarget.copyFrom((EntityReference<CastSpellEntity>)entry.entity);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,4 +106,10 @@ public class PortalSpell extends AbstractSpell {
|
|||
publishedPosition = compound.getBoolean("publishedPosition");
|
||||
teleportationTarget.fromNBT(compound.getCompound("teleportationTarget"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
particlEffect.destroy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.Unicopia;
|
|||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
|
||||
import net.minecraft.nbt.*;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
@ -20,7 +21,7 @@ public class Ether extends PersistentState {
|
|||
return WorldOverlay.getPersistableStorage(world, ID, Ether::new, Ether::new);
|
||||
}
|
||||
|
||||
private final Map<Identifier, Set<EntityReference<?>>> advertisingEndpoints = new HashMap<>();
|
||||
private final Map<Identifier, Set<Entry>> advertisingEndpoints = new HashMap<>();
|
||||
|
||||
private final Object locker = new Object();
|
||||
|
||||
|
@ -29,9 +30,11 @@ public class Ether extends PersistentState {
|
|||
compound.getKeys().forEach(key -> {
|
||||
Identifier typeId = Identifier.tryParse(key);
|
||||
if (typeId != null) {
|
||||
Set<EntityReference<?>> uuids = getIds(typeId);
|
||||
Set<Entry> uuids = getEntries(typeId);
|
||||
compound.getList(key, NbtElement.COMPOUND_TYPE).forEach(entry -> {
|
||||
uuids.add(new EntityReference<>((NbtCompound)entry));
|
||||
Entry e = new Entry();
|
||||
e.fromNBT((NbtCompound)entry);
|
||||
uuids.add(e);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -56,7 +59,7 @@ public class Ether extends PersistentState {
|
|||
|
||||
public void put(SpellType<?> spellType, Caster<?> caster) {
|
||||
synchronized (locker) {
|
||||
getIds(spellType.getId()).add(new EntityReference<>(caster.getEntity()));
|
||||
getEntries(spellType.getId()).add(new Entry(caster));
|
||||
}
|
||||
markDirty();
|
||||
}
|
||||
|
@ -64,9 +67,9 @@ public class Ether extends PersistentState {
|
|||
public void remove(SpellType<?> spellType, UUID id) {
|
||||
synchronized (locker) {
|
||||
Identifier typeId = spellType.getId();
|
||||
Set<EntityReference<?>> refs = advertisingEndpoints.get(typeId);
|
||||
Set<Entry> refs = advertisingEndpoints.get(typeId);
|
||||
if (refs != null) {
|
||||
refs.removeIf(ref -> ref.getId().orElse(Util.NIL_UUID).equals(id));
|
||||
refs.removeIf(ref -> ref.entity.getId().orElse(Util.NIL_UUID).equals(id));
|
||||
if (refs.isEmpty()) {
|
||||
advertisingEndpoints.remove(typeId);
|
||||
}
|
||||
|
@ -75,13 +78,89 @@ public class Ether extends PersistentState {
|
|||
}
|
||||
}
|
||||
|
||||
public Set<EntityReference<?>> getIds(SpellType<?> spellType) {
|
||||
return getIds(spellType.getId());
|
||||
public void remove(SpellType<?> spellType, Caster<?> caster) {
|
||||
remove(spellType, caster.getEntity().getUuid());
|
||||
}
|
||||
|
||||
private Set<EntityReference<?>> getIds(Identifier typeId) {
|
||||
public Set<Entry> getEntries(SpellType<?> spellType) {
|
||||
return getEntries(spellType.getId());
|
||||
}
|
||||
|
||||
private Set<Entry> getEntries(Identifier typeId) {
|
||||
synchronized (locker) {
|
||||
return advertisingEndpoints.computeIfAbsent(typeId, i -> new HashSet<>());
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Entry> getEntry(SpellType<?> spellType, Caster<?> caster) {
|
||||
synchronized (locker) {
|
||||
return getEntries(spellType).stream().filter(e -> e.entity.referenceEquals(caster.getEntity())).findFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Entry> getEntry(SpellType<?> spellType, UUID uuid) {
|
||||
synchronized (locker) {
|
||||
return getEntries(spellType).stream().filter(e -> e.equals(uuid)).findFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public class Entry implements NbtSerialisable {
|
||||
public final EntityReference<?> entity;
|
||||
private boolean removed;
|
||||
private boolean taken;
|
||||
|
||||
public Entry() {
|
||||
entity = new EntityReference<>();
|
||||
}
|
||||
|
||||
public Entry(Caster<?> caster) {
|
||||
entity = new EntityReference<>(caster.getEntity());
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return !removed;
|
||||
}
|
||||
|
||||
public void markDead() {
|
||||
removed = true;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
return !removed && !taken;
|
||||
}
|
||||
|
||||
public void setTaken(boolean taken) {
|
||||
this.taken = taken;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toNBT(NbtCompound compound) {
|
||||
entity.toNBT(compound);
|
||||
compound.putBoolean("remove", removed);
|
||||
compound.putBoolean("taken", taken);
|
||||
}
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound) {
|
||||
entity.fromNBT(compound);
|
||||
removed = compound.getBoolean("removed");
|
||||
taken = compound.getBoolean("taken");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof Entry e
|
||||
&& e.equals(entity.getId().orElse(Util.NIL_UUID));
|
||||
}
|
||||
|
||||
public boolean equals(UUID uuid) {
|
||||
return entity.getId().orElse(Util.NIL_UUID).equals(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return entity.getId().orElse(Util.NIL_UUID).hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue