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.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
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.CastSpellEntity;
|
||||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||||
import com.minelittlepony.unicopia.entity.UEntities;
|
import com.minelittlepony.unicopia.entity.UEntities;
|
||||||
|
@ -86,6 +87,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
||||||
entity.getSpellSlot().put(spell.toPlaceable());
|
entity.getSpellSlot().put(spell.toPlaceable());
|
||||||
entity.setMaster(source);
|
entity.setMaster(source);
|
||||||
entity.world.spawnEntity(entity);
|
entity.world.spawnEntity(entity);
|
||||||
|
Ether.get(entity.world).put(getType(), entity);
|
||||||
|
|
||||||
castEntity.set(entity);
|
castEntity.set(entity);
|
||||||
setDirty();
|
setDirty();
|
||||||
|
@ -96,6 +98,16 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (situation == Situation.GROUND_ENTITY) {
|
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 -> {
|
particlEffect.update(getUuid(), source, spawner -> {
|
||||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
||||||
}).ifPresent(p -> {
|
}).ifPresent(p -> {
|
||||||
|
@ -108,24 +120,15 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
||||||
return !isDead();
|
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
|
@Override
|
||||||
public void onDestroyed(Caster<?> source) {
|
public void onDestroyed(Caster<?> source) {
|
||||||
if (!source.isClient()) {
|
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 -> {
|
getSpellEntity(source).ifPresent(e -> {
|
||||||
e.getSpellSlot().clear();
|
|
||||||
castEntity.set(null);
|
castEntity.set(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class PortalSpell extends AbstractSpell {
|
||||||
if (situation == Situation.GROUND) {
|
if (situation == Situation.GROUND) {
|
||||||
teleportationTarget.getPosition().ifPresentOrElse(
|
teleportationTarget.getPosition().ifPresentOrElse(
|
||||||
targetPos -> tickWithTargetLink(source, targetPos),
|
targetPos -> tickWithTargetLink(source, targetPos),
|
||||||
() -> advertiseAvailable(source)
|
() -> findLink(source)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!publishedPosition) {
|
if (!publishedPosition) {
|
||||||
|
@ -76,15 +76,15 @@ public class PortalSpell extends AbstractSpell {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void advertiseAvailable(Caster<?> source) {
|
private void findLink(Caster<?> source) {
|
||||||
Ether ether = Ether.get(source.getReferenceWorld());
|
Ether ether = Ether.get(source.getReferenceWorld());
|
||||||
ether.getIds(getType())
|
ether.getEntries(getType())
|
||||||
.stream()
|
.stream()
|
||||||
.filter(id -> !id.referenceEquals(source.getEntity()))
|
.filter(entry -> entry.isAvailable() && !entry.entity.referenceEquals(source.getEntity()))
|
||||||
.findAny()
|
.findAny()
|
||||||
.ifPresent(ref -> {
|
.ifPresent(entry -> {
|
||||||
ether.remove(getType(), ref.getId().get());
|
entry.setTaken(true);
|
||||||
teleportationTarget.copyFrom((EntityReference<CastSpellEntity>)ref);
|
teleportationTarget.copyFrom((EntityReference<CastSpellEntity>)entry.entity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,4 +106,10 @@ public class PortalSpell extends AbstractSpell {
|
||||||
publishedPosition = compound.getBoolean("publishedPosition");
|
publishedPosition = compound.getBoolean("publishedPosition");
|
||||||
teleportationTarget.fromNBT(compound.getCompound("teleportationTarget"));
|
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.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||||
|
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||||
|
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
@ -20,7 +21,7 @@ public class Ether extends PersistentState {
|
||||||
return WorldOverlay.getPersistableStorage(world, ID, Ether::new, Ether::new);
|
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();
|
private final Object locker = new Object();
|
||||||
|
|
||||||
|
@ -29,9 +30,11 @@ public class Ether extends PersistentState {
|
||||||
compound.getKeys().forEach(key -> {
|
compound.getKeys().forEach(key -> {
|
||||||
Identifier typeId = Identifier.tryParse(key);
|
Identifier typeId = Identifier.tryParse(key);
|
||||||
if (typeId != null) {
|
if (typeId != null) {
|
||||||
Set<EntityReference<?>> uuids = getIds(typeId);
|
Set<Entry> uuids = getEntries(typeId);
|
||||||
compound.getList(key, NbtElement.COMPOUND_TYPE).forEach(entry -> {
|
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) {
|
public void put(SpellType<?> spellType, Caster<?> caster) {
|
||||||
synchronized (locker) {
|
synchronized (locker) {
|
||||||
getIds(spellType.getId()).add(new EntityReference<>(caster.getEntity()));
|
getEntries(spellType.getId()).add(new Entry(caster));
|
||||||
}
|
}
|
||||||
markDirty();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
@ -64,9 +67,9 @@ public class Ether extends PersistentState {
|
||||||
public void remove(SpellType<?> spellType, UUID id) {
|
public void remove(SpellType<?> spellType, UUID id) {
|
||||||
synchronized (locker) {
|
synchronized (locker) {
|
||||||
Identifier typeId = spellType.getId();
|
Identifier typeId = spellType.getId();
|
||||||
Set<EntityReference<?>> refs = advertisingEndpoints.get(typeId);
|
Set<Entry> refs = advertisingEndpoints.get(typeId);
|
||||||
if (refs != null) {
|
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()) {
|
if (refs.isEmpty()) {
|
||||||
advertisingEndpoints.remove(typeId);
|
advertisingEndpoints.remove(typeId);
|
||||||
}
|
}
|
||||||
|
@ -75,13 +78,89 @@ public class Ether extends PersistentState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<EntityReference<?>> getIds(SpellType<?> spellType) {
|
public void remove(SpellType<?> spellType, Caster<?> caster) {
|
||||||
return getIds(spellType.getId());
|
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) {
|
synchronized (locker) {
|
||||||
return advertisingEndpoints.computeIfAbsent(typeId, i -> new HashSet<>());
|
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