Store the level with the spellcast entity so it can still be used when the owner is offline

This commit is contained in:
Sollace 2022-09-17 22:11:24 +02:00
parent 5d9ef41672
commit cbd80270e3
7 changed files with 85 additions and 20 deletions

View file

@ -25,8 +25,9 @@ public interface WeaklyOwned<E extends Entity> extends Owned<E> {
*
* @param sibling
*/
@Override
@SuppressWarnings("unchecked")
default void setMaster(WeaklyOwned<? extends E> sibling) {
default void setMaster(Owned<? extends E> sibling) {
if (sibling instanceof WeaklyOwned) {
getMasterReference().copyFrom(((WeaklyOwned<E>)sibling).getMasterReference());
} else {

View file

@ -1,10 +1,46 @@
package com.minelittlepony.unicopia.ability.magic;
import java.util.function.IntSupplier;
import net.minecraft.nbt.NbtCompound;
/**
* Object with levelling capabilities.
*/
public interface Levelled {
LevelStore EMPTY = fixed(0);
static LevelStore fixed(int level) {
return of(() -> level);
}
static LevelStore of(IntSupplier supplier) {
return new LevelStore() {
@Override
public int get() {
return supplier.getAsInt();
}
@Override
public void set(int level) {
}
@Override
public int getMax() {
return get();
}
};
}
static LevelStore copyOf(LevelStore store) {
return of(store.get(), store.getMax());
}
static LevelStore fromNbt(NbtCompound compound) {
return of(compound.getInt("value"), compound.getInt("max"));
}
static LevelStore of(int level, int max) {
return new LevelStore() {
@Override
public int get() {
@ -17,9 +53,8 @@ public interface Levelled {
@Override
public int getMax() {
return get();
return max;
}
};
}
@ -46,5 +81,12 @@ public interface Levelled {
default void add(int levels) {
set(get() + levels);
}
default NbtCompound toNbt() {
NbtCompound compound = new NbtCompound();
compound.putInt("value", get());
compound.putInt("max", getMax());
return compound;
}
}
}

View file

@ -92,7 +92,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
delegate.onPlaced(source, copy, entity);
}
entity.getSpellSlot().put(copy);
entity.setMaster(source);
entity.setCaster(source);
entity.world.spawnEntity(entity);
Ether.get(entity.world).put(getType(), entity);

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.entity;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.WeaklyOwned;
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;
@ -27,14 +26,15 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<Livin
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(CastSpellEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
private static final LevelStore LEVELS = Levelled.fixed(0);
private final EntityPhysics<CastSpellEntity> physics = new EntityPhysics<>(this, GRAVITY);
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
private final EntityReference<LivingEntity> owner = new EntityReference<>();
private LevelStore level = Levelled.EMPTY;
private LevelStore corruption = Levelled.EMPTY;
public CastSpellEntity(EntityType<?> type, World world) {
super(type, world);
}
@ -81,14 +81,20 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<Livin
return this;
}
public void setCaster(Caster<?> caster) {
this.level = Levelled.copyOf(caster.getLevel());
this.corruption = Levelled.copyOf(caster.getCorruption());
setMaster(caster);
}
@Override
public LevelStore getLevel() {
return Caster.of(getMaster()).map(Caster::getLevel).orElse(LEVELS);
return level;
}
@Override
public LevelStore getCorruption() {
return Caster.of(getMaster()).map(Caster::getCorruption).orElse(LEVELS);
return corruption;
}
@Override
@ -120,6 +126,8 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<Livin
@Override
protected void writeCustomDataToNbt(NbtCompound tag) {
tag.put("owner", owner.toNBT());
tag.put("level", level.toNbt());
tag.put("corruption", corruption.toNbt());
getSpellSlot().get(true).ifPresent(effect -> {
tag.put("effect", Spell.writeNbt(effect));
});
@ -133,6 +141,8 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<Livin
if (tag.contains("effect")) {
getSpellSlot().put(Spell.readNbt(tag.getCompound("effect")));
}
level = Levelled.fromNbt(tag.getCompound("level"));
corruption = Levelled.fromNbt(tag.getCompound("corruption"));
}
@Override

View file

@ -44,8 +44,6 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
public static final TrackedData<Float> GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Integer> EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final LevelStore LEVELS = Levelled.fixed(0);
public static void boostrap() {}
private final EntityPhysics<LivingEntity> physics;
@ -205,12 +203,12 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
@Override
public LevelStore getLevel() {
return LEVELS;
return Levelled.EMPTY;
}
@Override
public LevelStore getCorruption() {
return LEVELS;
return Levelled.EMPTY;
}
@Override

View file

@ -16,11 +16,26 @@ import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
/**
* An indirect reference to an entity by its unique id.
* Used to store the 'owner' reference for certain objects that allows them to\
* remember who they belong to even when the entity has been unloaded.
*
* @param <T> The type of the entity this reference points to.
*/
public class EntityReference<T extends Entity> implements NbtSerialisable {
/**
* Server UUID of the entity used to look up the entity instance on the server.
*/
private Optional<UUID> uuid = Optional.empty();
/**
* Corresponding client id used to look up the entity instance on the client.
*/
private int clientId;
/**
* The last-known position of the entity.
*/
private Optional<Vec3d> pos = Optional.empty();
public EntityReference() {}
@ -88,8 +103,8 @@ public class EntityReference<T extends Entity> implements NbtSerialisable {
@SuppressWarnings("unchecked")
public Optional<T> getOrEmpty(World world) {
if (uuid.isPresent() && world instanceof ServerWorld) {
return uuid.map(((ServerWorld)world)::getEntity).map(e -> (T)e).filter(this::checkReference);
if (uuid.isPresent() && world instanceof ServerWorld serverWorld) {
return uuid.map(serverWorld::getEntity).map(e -> (T)e).filter(this::checkReference);
}
if (clientId != 0) {

View file

@ -55,7 +55,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Boolean> HYDROPHOBIC = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
private static final LevelStore LEVELS = Levelled.fixed(1);
public static final byte PROJECTILE_COLLISSION = 3;
@ -117,12 +116,12 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
@Override
public LevelStore getLevel() {
return Caster.of(getMaster()).map(Caster::getLevel).orElse(LEVELS);
return Caster.of(getMaster()).map(Caster::getLevel).orElse(Levelled.EMPTY);
}
@Override
public LevelStore getCorruption() {
return Caster.of(getMaster()).map(Caster::getCorruption).orElse(LEVELS);
return Caster.of(getMaster()).map(Caster::getCorruption).orElse(Levelled.EMPTY);
}
@Override