From 36e22f1eadc7fc25a35ab27466a4611d91dab25e Mon Sep 17 00:00:00 2001 From: Sollace Date: Wed, 7 Feb 2024 12:24:53 +0000 Subject: [PATCH] Improve network syncing of spells and fix some shield radius resets --- .../ability/magic/spell/PlaceableSpell.java | 15 ++-- .../unicopia/ability/magic/spell/Spell.java | 10 ++- .../ability/magic/spell/SpellReference.java | 65 ++++++++++++++++ .../ability/magic/spell/ThrowableSpell.java | 14 ++-- .../magic/spell/effect/AbstractSpell.java | 2 +- .../magic/spell/effect/ShieldSpell.java | 7 +- .../render/spell/ShieldSpellRenderer.java | 1 + .../datasync/SpellNetworkedReference.java | 74 ++----------------- 8 files changed, 101 insertions(+), 87 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index 408b345d..9a135942 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -51,7 +51,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS /** * The spell being cast */ - private Spell spell; + private final SpellReference spell = new SpellReference<>(); public float pitch; public float yaw; @@ -70,7 +70,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS } public PlaceableSpell setSpell(Spell spell) { - this.spell = spell; + this.spell.set(spell); return this; } @@ -103,7 +103,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public Collection getDelegates() { - return List.of(spell); + return List.of(spell.get()); } @Override @@ -162,8 +162,8 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS CastSpellEntity entity = UEntities.CAST_SPELL.create(source.asWorld()); Vec3d pos = getPosition().orElse(position.orElse(source.asEntity().getPos())); entity.updatePositionAndAngles(pos.x, pos.y, pos.z, source.asEntity().getYaw(), source.asEntity().getPitch()); - PlaceableSpell copy = spell.toPlaceable(); - if (spell instanceof PlacementDelegate delegate) { + PlaceableSpell copy = spell.get().toPlaceable(); + if (spell.get() instanceof PlacementDelegate delegate) { delegate.onPlaced(source, copy, entity); } entity.getSpellSlot().put(copy); @@ -272,13 +272,12 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override protected void loadDelegates(NbtCompound compound) { - spell = Spell.SERIALIZER.read(compound.getCompound("spell")); + spell.fromNBT(compound.getCompound("spell")); } @Override protected void saveDelegates(NbtCompound compound) { - compound.put("spell", Spell.SERIALIZER.write(spell)); - + compound.put("spell", spell.toNBT()); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java index 2472b348..0c504041 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/Spell.java @@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.util.NbtSerialisable; import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.Util; /** * Interface for a magic spells @@ -129,10 +130,11 @@ public interface Spell extends NbtSerialisable, Affine { } @Nullable - static Spell readNbt(@Nullable NbtCompound compound) { + static T readNbt(@Nullable NbtCompound compound) { try { if (compound != null && compound.contains("effect_id")) { - Spell effect = SpellType.getKey(compound).withTraits().create(); + @SuppressWarnings("unchecked") + T effect = (T)SpellType.getKey(compound).withTraits().create(); if (effect != null) { effect.fromNBT(compound); @@ -147,6 +149,10 @@ public interface Spell extends NbtSerialisable, Affine { return null; } + static UUID getUuid(@Nullable NbtCompound compound) { + return compound == null || !compound.containsUuid("uuid") ? Util.NIL_UUID : compound.getUuid("uuid"); + } + static NbtCompound writeNbt(Spell effect) { NbtCompound compound = effect.toNBT(); effect.getType().toNbt(compound); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java new file mode 100644 index 00000000..c8b504f8 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/SpellReference.java @@ -0,0 +1,65 @@ +package com.minelittlepony.unicopia.ability.magic.spell; + +import java.util.Objects; +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.util.NbtSerialisable; + +import net.minecraft.nbt.NbtCompound; + +public final class SpellReference implements NbtSerialisable { + @Nullable + private transient T spell; + private int nbtHash; + + @Nullable + public T get() { + return spell == null || spell.isDead() ? null : spell; + } + + public void set(T spell) { + set(spell, null); + } + + public boolean hasDirtySpell() { + return spell != null && spell.isDirty(); + } + + public boolean set(T spell, @Nullable Caster owner) { + spell = spell == null || spell.isDead() ? null : spell; + if (spell == this.spell) { + return false; + } + T oldValue = this.spell; + this.spell = spell; + nbtHash = 0; + if (owner != null && oldValue != null && (spell == null || !oldValue.getUuid().equals(spell.getUuid()))) { + oldValue.destroy(owner); + } + return true; + } + + @Override + public void toNBT(NbtCompound compound) { + if (spell != null && !spell.isDead()) { + spell.toNBT(compound); + spell.getType().toNbt(compound); + } + } + + @Override + public void fromNBT(NbtCompound compound) { + final int hash = compound.hashCode(); + if (nbtHash == hash) { + return; + } + nbtHash = hash; + + if (spell == null || !Objects.equals(Spell.getUuid(compound), spell.getUuid())) { + spell = Spell.readNbt(compound); + } else { + spell.fromNBT(compound); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java index 20c4c9b0..ddb3a43f 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/ThrowableSpell.java @@ -17,20 +17,20 @@ import net.minecraft.world.World; public final class ThrowableSpell extends AbstractDelegatingSpell { - private Spell spell; + private final SpellReference spell = new SpellReference<>(); public ThrowableSpell(CustomisedSpellType type) { super(type); } public ThrowableSpell setSpell(Spell spell) { - this.spell = spell; + this.spell.set(spell); return this; } @Override public Collection getDelegates() { - return List.of(spell); + return List.of(spell.get()); } @Override @@ -63,7 +63,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { return Optional.empty(); } - Spell s = spell.prepareForCast(caster, CastingMethod.STORED); + Spell s = spell.get().prepareForCast(caster, CastingMethod.STORED); if (s == null) { return Optional.empty(); } @@ -71,7 +71,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { MagicProjectileEntity projectile = UEntities.MAGIC_BEAM.create(world); projectile.setPosition(entity.getX(), entity.getEyeY() - 0.1F, entity.getZ()); projectile.setOwner(entity); - projectile.setItem(UItems.GEMSTONE.getDefaultStack(spell.getType())); + projectile.setItem(UItems.GEMSTONE.getDefaultStack(spell.get().getType())); s.apply(projectile); projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, divergance); projectile.setNoGravity(true); @@ -83,12 +83,12 @@ public final class ThrowableSpell extends AbstractDelegatingSpell { @Override protected void loadDelegates(NbtCompound compound) { - spell = Spell.SERIALIZER.read(compound.getCompound("spell")); + spell.fromNBT(compound.getCompound("spell")); } @Override protected void saveDelegates(NbtCompound compound) { - compound.put("spell", Spell.SERIALIZER.write(spell)); + compound.put("spell", spell.toNBT()); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java index 8b64d9c3..1660c01e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AbstractSpell.java @@ -115,7 +115,7 @@ public abstract class AbstractSpell implements Spell { @Override public void fromNBT(NbtCompound compound) { dirty = false; - if (compound.contains("uuid")) { + if (compound.containsUuid("uuid")) { uuid = compound.getUuid("uuid"); } dying = compound.getBoolean("dying"); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index 5107f3d9..22fd5b47 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -78,6 +78,7 @@ public class ShieldSpell extends AbstractSpell { @Override public boolean tick(Caster source, Situation situation) { + rangeMultiplier.update(source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2, 500L); radius.update((float)getDrawDropOffRange(source), 200L); if (source.isClient()) { @@ -104,6 +105,8 @@ public class ShieldSpell extends AbstractSpell { @Override public void tickDying(Caster caster) { + rangeMultiplier.update(caster instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2, 10L); + radius.update((float)getDrawDropOffRange(caster), 10L); prevTicksDying = ticksDying; if (ticksDying++ > 25) { super.tickDying(caster); @@ -124,7 +127,7 @@ public class ShieldSpell extends AbstractSpell { public float getRadius(float tickDelta) { float base = radius.getValue(); - float scale = 1 - MathHelper.clamp(MathHelper.lerp(tickDelta, (float)prevTicksDying, ticksDying), 0, 1); + float scale = 1 - MathHelper.clamp(MathHelper.lerp(tickDelta, (float)prevTicksDying, ticksDying) / 25F, 0, 1); return base * scale; } @@ -132,8 +135,6 @@ public class ShieldSpell extends AbstractSpell { * Calculates the maximum radius of the shield. aka The area of effect. */ public double getDrawDropOffRange(Caster source) { - rangeMultiplier.update(source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2, 500L); - float min = (source instanceof Pony ? 4 : 6) + getTraits().get(Trait.POWER); double range = (min + (source.getLevel().getScaled(source instanceof Pony ? 4 : 40) * (source instanceof Pony ? 2 : 10))) / rangeMultiplier.getValue(); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java index a006f77d..c3f2e7fb 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java @@ -36,6 +36,7 @@ public class ShieldSpellRenderer extends SpellRenderer { float thickness = 0.02F * MathHelper.sin(animationProgress / 30F); float alpha = 1 - Math.abs(MathHelper.sin(animationProgress / 20F)) * 0.2F; + alpha *= MathHelper.clamp(radius - 1, 0, 1); if (firstPerson) { matrices.translate(0, -1.75F, 0); diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java index 9618b330..9ae9f29a 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java +++ b/src/main/java/com/minelittlepony/unicopia/network/datasync/SpellNetworkedReference.java @@ -1,23 +1,17 @@ package com.minelittlepony.unicopia.network.datasync; -import java.util.Objects; import java.util.Optional; - import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.SpellReference; import net.minecraft.nbt.NbtCompound; public class SpellNetworkedReference implements NetworkedReference { - private Optional currentValue = Optional.empty(); - - @Nullable - private NbtCompound lastValue; - + private final SpellReference currentValue = new SpellReference<>(); private final Caster owner; - private boolean dirty; public SpellNetworkedReference(Caster owner) { @@ -26,81 +20,29 @@ public class SpellNetworkedReference implements NetworkedRefere @Override public Optional getReference() { - return currentValue.filter(s -> !s.isDead()); - } - - private boolean mustDelete(@Nullable NbtCompound comp) { - return comp == null || !comp.contains("effect_id") || !comp.contains("uuid"); - } - - private boolean mustReplace(NbtCompound comp) { - return currentValue.isEmpty() || !currentValue.get().getUuid().equals(comp.getUuid("uuid")); - } - - private boolean mustUpdate(NbtCompound comp) { - if (owner.isClient() && !Objects.equals(lastValue, comp)) { - lastValue = comp; - return true; - } - return false; - } - - private boolean mustSend() { - return currentValue.filter(Spell::isDirty).isPresent(); + return Optional.ofNullable(currentValue.get()); } @Override public void updateReference(@Nullable T newValue) { - newValue = newValue == null || newValue.isDead() ? null : newValue; - - @Nullable - T oldValue = currentValue.orElse(null); - if (oldValue != newValue) { - dirty = true; - currentValue = Optional.ofNullable(newValue); - - if (oldValue != null && (newValue == null || !oldValue.getUuid().equals(newValue.getUuid()))) { - oldValue.destroy(owner); - } - } + dirty |= currentValue.set(newValue, owner); } @Override - @SuppressWarnings("unchecked") public boolean fromNbt(NbtCompound comp) { dirty = false; - - if (mustDelete(comp)) { - updateReference(null); - return false; - } - - if (mustReplace(comp)) { - updateReference((T)Spell.readNbt(comp)); - return false; - } - - if (mustUpdate(comp)) { - currentValue.ifPresent(s -> s.fromNBT(comp)); - return false; - } - - if (mustSend()) { - updateReference(getReference().orElse(null)); - return true; - } - - return false; + currentValue.fromNBT(comp); + return isDirty(); } @Override public NbtCompound toNbt() { dirty = false; - return getReference().map(Spell::writeNbt).orElseGet(NbtCompound::new); + return currentValue.toNBT(); } @Override public boolean isDirty() { - return dirty || mustSend(); + return !owner.isClient() && (dirty || currentValue.hasDirtySpell()); } }