Sync all spells onto the ether

This commit is contained in:
Sollace 2024-05-23 12:53:11 +01:00
parent 77de42dd09
commit 8a093a8a8b
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
16 changed files with 154 additions and 111 deletions

View file

@ -6,6 +6,8 @@ import java.util.stream.Stream;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.server.world.Ether;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
public abstract class AbstractDelegatingSpell implements Spell { public abstract class AbstractDelegatingSpell implements Spell {
@ -101,6 +103,9 @@ public abstract class AbstractDelegatingSpell implements Spell {
} }
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
if (!caster.isClient()) {
Ether.get(caster.asWorld()).remove(this, caster);
}
if (delegate.get() instanceof Spell s) { if (delegate.get() instanceof Spell s) {
s.destroy(caster); s.destroy(caster);
} }

View file

@ -28,10 +28,11 @@ public abstract class AbstractDisguiseSpell extends AbstractSpell implements Dis
@Override @Override
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
super.onDestroyed(caster);
caster.asEntity().calculateDimensions(); caster.asEntity().calculateDimensions();
caster.asEntity().setInvisible(false); caster.asEntity().setInvisible(false);
if (caster instanceof Pony) { if (caster instanceof Pony pony) {
((Pony) caster).setInvisible(false); pony.setInvisible(false);
} }
disguise.remove(); disguise.remove();
} }

View file

@ -51,16 +51,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
} }
} }
@Override
public boolean apply(Caster<?> caster) {
boolean result = super.apply(caster);
if (result && !caster.isClient()) {
Ether.get(caster.asWorld()).getOrCreate(this, caster);
}
setDirty();
return result;
}
public float getAge(float tickDelta) { public float getAge(float tickDelta) {
return MathHelper.lerp(tickDelta, prevAge, age); return MathHelper.lerp(tickDelta, prevAge, age);
} }
@ -91,9 +81,16 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
@Override @Override
public boolean tick(Caster<?> source, Situation situation) { public boolean tick(Caster<?> source, Situation situation) {
if (!source.isClient() && !checkConnection(source)) { if (!source.isClient()) {
if (!checkConnection(source)) {
setDead(); setDead();
return false; return true;
}
var entry = Ether.get(source.asWorld()).get(this, source);
if (entry != null && entry.hasChanged()) {
setOrientation(source, entry.getPitch(), entry.getYaw());
}
} }
prevAge = age; prevAge = age;
@ -115,14 +112,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
deathTicks--; deathTicks--;
} }
@Override
protected void onDestroyed(Caster<?> source) {
if (!source.isClient()) {
Ether.get(source.asWorld()).remove(this, source);
}
super.onDestroyed(source);
}
@Override @Override
public void setOrientation(Caster<?> caster, float pitch, float yaw) { public void setOrientation(Caster<?> caster, float pitch, float yaw) {
this.pitch = -pitch - 90; this.pitch = -pitch - 90;
@ -131,6 +120,15 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
entity.updatePositionAndAngles(entity.getX(), entity.getY(), entity.getZ(), this.yaw, this.pitch); entity.updatePositionAndAngles(entity.getX(), entity.getY(), entity.getZ(), this.yaw, this.pitch);
entity.setYaw(this.yaw); entity.setYaw(this.yaw);
entity.setPitch(this.pitch); entity.setPitch(this.pitch);
if (!caster.isClient()) {
var entry = Ether.get(caster.asWorld()).get(this, caster);
if (entry != null) {
entry.setPitch(pitch);
entry.setYaw(yaw);
}
}
setDirty(); setDirty();
} }

View file

@ -5,11 +5,9 @@ import java.util.UUID;
import org.jetbrains.annotations.Nullable; 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.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
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.EntityValues;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import com.minelittlepony.unicopia.entity.mob.UEntities; import com.minelittlepony.unicopia.entity.mob.UEntities;
import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.server.world.Ether;
@ -23,15 +21,18 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public class PlacementControlSpell extends AbstractDelegatingSpell implements OrientedSpell { public class PlacementControlSpell extends AbstractSpell implements OrientedSpell {
@Nullable @Nullable
private UUID placedSpellId; private UUID placedSpellId;
private final EntityReference<CastSpellEntity> castEntity = new EntityReference<>(); @Nullable
private UUID placedEntityId;
private Optional<RegistryKey<World>> dimension = Optional.empty(); private Optional<RegistryKey<World>> dimension = Optional.empty();
private Optional<Vec3d> position = Optional.empty(); private Optional<Vec3d> position = Optional.empty();
private Optional<Vec3d> orientation = Optional.empty(); private Optional<Vec3d> orientation = Optional.empty();
private SpellReference<Spell> delegate = new SpellReference<>();
public PlacementControlSpell(CustomisedSpellType<?> type) { public PlacementControlSpell(CustomisedSpellType<?> type) {
super(type); super(type);
} }
@ -41,6 +42,11 @@ public class PlacementControlSpell extends AbstractDelegatingSpell implements Or
this.delegate.set(delegate); this.delegate.set(delegate);
} }
@Nullable
public Spell getDelegate() {
return delegate.get();
}
public Optional<Vec3d> getPosition() { public Optional<Vec3d> getPosition() {
return position; return position;
} }
@ -56,54 +62,36 @@ public class PlacementControlSpell extends AbstractDelegatingSpell implements Or
@Override @Override
public void setOrientation(Caster<?> caster, float pitch, float yaw) { public void setOrientation(Caster<?> caster, float pitch, float yaw) {
this.orientation = Optional.of(new Vec3d(pitch, yaw, 0)); this.orientation = Optional.of(new Vec3d(pitch, yaw, 0));
castEntity.ifPresent(caster.asWorld(), entity -> { setDirty();
entity.getSpellSlot().stream(SpellPredicate.IS_ORIENTED).forEach(spell -> { if (!caster.isClient() && placedEntityId != null) {
if (!getTypeAndTraits().type().test(spell)) { getWorld(caster).ifPresent(world -> {
spell.setOrientation(caster, pitch, yaw); var entry = Ether.get(world).get(SpellType.PLACED_SPELL, placedEntityId, placedSpellId);
if (entry != null) {
entry.setPitch(pitch);
entry.setYaw(yaw);
} }
}); });
}); }
setDirty();
} }
@Override @Override
public boolean apply(Caster<?> caster) { public boolean apply(Caster<?> caster) {
boolean result = super.apply(caster); boolean result = super.apply(caster);
if (result) { if (result) {
if (!caster.isClient()) {
Ether.get(caster.asWorld()).getOrCreate(this, caster);
}
if (dimension.isEmpty()) { if (dimension.isEmpty()) {
setDimension(caster.asWorld().getRegistryKey()); setDimension(caster.asWorld().getRegistryKey());
} }
if (position.isEmpty()) { if (position.isEmpty()) {
setPosition(caster.asEntity().getPos()); setPosition(caster.asEntity().getPos());
} }
}
return result;
}
@Override PlaceableSpell copy = new PlaceableSpell(caster, this, delegate.get());
public boolean tick(Caster<?> source, Situation situation) {
if (!source.isClient()) {
Ether.get(source.asWorld()).getOrCreate(this, source);
castEntity.getTarget().ifPresentOrElse(target -> {
if (!checkConnection(source, target)) {
setDead();
}
}, () -> spawnPlacedEntity(source));
}
return !isDead();
}
private void spawnPlacedEntity(Caster<?> source) { Vec3d pos = position.orElse(caster.asEntity().getPos());
PlaceableSpell copy = new PlaceableSpell(source, this, getDelegate());
Vec3d pos = position.orElse(source.asEntity().getPos());
Vec3d rot = orientation.orElse(Vec3d.ZERO); Vec3d rot = orientation.orElse(Vec3d.ZERO);
CastSpellEntity entity = UEntities.CAST_SPELL.create(source.asWorld()); CastSpellEntity entity = UEntities.CAST_SPELL.create(caster.asWorld());
entity.setCaster(source); entity.setCaster(caster);
entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x); entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x);
entity.setYaw((float)rot.y); entity.setYaw((float)rot.y);
entity.setPitch((float)rot.x); entity.setPitch((float)rot.x);
@ -111,52 +99,54 @@ public class PlacementControlSpell extends AbstractDelegatingSpell implements Or
entity.getWorld().spawnEntity(entity); entity.getWorld().spawnEntity(entity);
placedSpellId = copy.getUuid(); placedSpellId = copy.getUuid();
castEntity.set(entity); placedEntityId = entity.getUuid();
setDirty(); setDirty();
} }
return result;
}
private boolean checkConnection(Caster<?> source, EntityValues<?> target) { @Override
return getWorld(source) public boolean tick(Caster<?> source, Situation situation) {
.map(Ether::get) if (!source.isClient() && !checkConnection(source)) {
.map(ether -> ether.get(SpellType.PLACED_SPELL, target, placedSpellId)) setDead();
.isPresent(); }
return !isDead();
}
private boolean checkConnection(Caster<?> source) {
return getWorld(source).map(world -> Ether.get(world).get(SpellType.PLACED_SPELL, placedEntityId, placedSpellId)).isPresent();
} }
private Optional<World> getWorld(Caster<?> source) { private Optional<World> getWorld(Caster<?> source) {
return dimension.map(source.asWorld().getServer()::getWorld); return dimension.map(source.asWorld().getServer()::getWorld);
} }
@Override
protected void onDestroyed(Caster<?> source) {
if (!source.isClient()) {
Ether.get(source.asWorld()).remove(this, source);
}
super.onDestroyed(source);
}
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
super.toNBT(compound); super.toNBT(compound);
compound.put("spell", delegate.toNBT());
position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos))); position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos)));
orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o))); orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o)));
dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString())); dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString()));
if (placedSpellId != null) { if (placedSpellId != null) {
compound.putUuid("placedSpellId", placedSpellId); compound.putUuid("placedSpellId", placedSpellId);
} }
compound.put("castEntity", castEntity.toNBT()); if (placedEntityId != null) {
compound.putUuid("placedEntityId", placedEntityId);
}
} }
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
super.fromNBT(compound); super.fromNBT(compound);
delegate.fromNBT(compound.getCompound("spell"));
placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null; placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null;
placedEntityId = compound.containsUuid("placedEntityId") ? compound.getUuid("placedEntityId") : null;
position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty(); position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty();
orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.FLOAT_TYPE))) : Optional.empty(); orientation = compound.contains("orientation") ? Optional.of(NbtSerialisable.readVector(compound.getList("orientation", NbtElement.FLOAT_TYPE))) : Optional.empty();
if (compound.contains("dimension", NbtElement.STRING_TYPE)) { if (compound.contains("dimension", NbtElement.STRING_TYPE)) {
dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id)); dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id));
} }
castEntity.fromNBT(compound.getCompound("castEntity"));
} }
public interface PlacementDelegate { public interface PlacementDelegate {

View file

@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
@ -81,6 +82,9 @@ public interface Spell extends NbtSerialisable, Affine {
*/ */
default boolean apply(Caster<?> caster) { default boolean apply(Caster<?> caster) {
caster.getSpellSlot().put(this); caster.getSpellSlot().put(this);
if (!caster.isClient()) {
Ether.get(caster.asWorld()).getOrCreate(this, caster);
}
return true; return true;
} }

View file

@ -5,6 +5,7 @@ import java.util.UUID;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.server.world.Ether;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
@ -78,9 +79,6 @@ public abstract class AbstractSpell implements Spell {
this.hidden = hidden; this.hidden = hidden;
} }
protected void onDestroyed(Caster<?> caster) {
}
@Override @Override
public void tickDying(Caster<?> caster) { public void tickDying(Caster<?> caster) {
dead = true; dead = true;
@ -96,6 +94,12 @@ public abstract class AbstractSpell implements Spell {
onDestroyed(caster); onDestroyed(caster);
} }
protected void onDestroyed(Caster<?> caster) {
if (!caster.isClient()) {
Ether.get(caster.asWorld()).remove(this, caster);
}
}
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
compound.putBoolean("dying", dying); compound.putBoolean("dying", dying);

View file

@ -54,11 +54,6 @@ public class AreaProtectionSpell extends AbstractAreaEffectSpell {
return !isDead(); return !isDead();
} }
@Override
protected void onDestroyed(Caster<?> caster) {
Ether.get(caster.asWorld()).remove(this, caster);
}
/** /**
* Calculates the maximum radius of the shield. aka The area of effect. * Calculates the maximum radius of the shield. aka The area of effect.
*/ */

View file

@ -139,6 +139,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell,
@Override @Override
protected void onDestroyed(Caster<?> source) { protected void onDestroyed(Caster<?> source) {
super.onDestroyed(source);
if (source.asEntity() instanceof LivingEntity l) { if (source.asEntity() instanceof LivingEntity l) {
MODIFIERS.forEach((attribute, modifier) -> { MODIFIERS.forEach((attribute, modifier) -> {
if (l.getAttributes().hasAttribute(attribute)) { if (l.getAttributes().hasAttribute(attribute)) {

View file

@ -90,6 +90,7 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pro
@Override @Override
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
super.onDestroyed(caster);
caster.getOriginatingCaster().asEntity().setGlowing(false); caster.getOriginatingCaster().asEntity().setGlowing(false);
target.ifPresent(caster.asWorld(), e -> e.setGlowing(false)); target.ifPresent(caster.asWorld(), e -> e.setGlowing(false));
} }

View file

@ -92,8 +92,7 @@ public class HydrophobicSpell extends AbstractSpell {
} }
double range = getRange(source); double range = getRange(source);
var entry = Ether.get(source.asWorld()).getOrCreate(this, source); Ether.get(source.asWorld()).getOrCreate(this, source).setRadius((float)range);
entry.radius = (float)range;
source.spawnParticles(new Sphere(true, range), 10, pos -> { source.spawnParticles(new Sphere(true, range), 10, pos -> {
BlockPos bp = BlockPos.ofFloored(pos); BlockPos bp = BlockPos.ofFloored(pos);
@ -116,7 +115,7 @@ public class HydrophobicSpell extends AbstractSpell {
@Override @Override
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
Ether.get(caster.asWorld()).remove(this, caster); super.onDestroyed(caster);
storedFluidPositions.removeIf(entry -> { storedFluidPositions.removeIf(entry -> {
if (caster.canModifyAt(entry.pos())) { if (caster.canModifyAt(entry.pos())) {
entry.restore(caster.asWorld()); entry.restore(caster.asWorld());
@ -175,7 +174,7 @@ public class HydrophobicSpell extends AbstractSpell {
} }
public boolean blocksFlow(Ether.Entry<?> entry, Vec3d center, BlockPos pos, FluidState fluid) { public boolean blocksFlow(Ether.Entry<?> entry, Vec3d center, BlockPos pos, FluidState fluid) {
return fluid.isIn(affectedFluid) && pos.isWithinDistance(center, (double)entry.radius + 1); return fluid.isIn(affectedFluid) && pos.isWithinDistance(center, (double)entry.getRadius() + 1);
} }
public static boolean blocksFluidFlow(BlockView world, BlockPos pos, FluidState state) { public static boolean blocksFluidFlow(BlockView world, BlockPos pos, FluidState state) {

View file

@ -91,6 +91,7 @@ public class LightSpell extends AbstractSpell implements TimedSpell, ProjectileD
@Override @Override
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
super.onDestroyed(caster);
if (caster.isClient()) { if (caster.isClient()) {
return; return;
} }

View file

@ -153,6 +153,7 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
@Override @Override
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
super.onDestroyed(caster);
if (caster.isClient()) { if (caster.isClient()) {
return; return;
} }

View file

@ -121,11 +121,9 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
); );
} }
Ether ether = Ether.get(source.asWorld()); var entry = Ether.get(source.asWorld()).getOrCreate(this, source);
var entry = ether.getOrCreate(this, source); entry.setPitch(pitch);
entry.pitch = pitch; entry.setYaw(yaw);
entry.yaw = yaw;
ether.markDirty();
} }
return !isDead(); return !isDead();
@ -133,13 +131,9 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
private void tickWithTargetLink(Caster<?> source, Ether.Entry<?> destination) { private void tickWithTargetLink(Caster<?> source, Ether.Entry<?> destination) {
if (!MathHelper.approximatelyEquals(targetPortalPitch, destination.pitch)) { if (destination.hasChanged()) {
targetPortalPitch = destination.pitch; targetPortalPitch = destination.getPitch();
setDirty(); targetPortalYaw = destination.getYaw();
}
if (!MathHelper.approximatelyEquals(targetPortalYaw, destination.yaw)) {
targetPortalYaw = destination.yaw;
setDirty();
} }
destination.entity.getTarget().ifPresent(target -> { destination.entity.getTarget().ifPresent(target -> {
@ -221,9 +215,11 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
@Override @Override
protected void onDestroyed(Caster<?> caster) { protected void onDestroyed(Caster<?> caster) {
Ether.get(caster.asWorld()).remove(getType(), caster); super.onDestroyed(caster);
if (!caster.isClient()) {
getDestination(caster).ifPresent(Ether.Entry::release); getDestination(caster).ifPresent(Ether.Entry::release);
} }
}
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {

View file

@ -19,6 +19,7 @@ import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.projectile.ProjectileUtil;
import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.util.ColorHelper; import com.minelittlepony.unicopia.util.ColorHelper;
import com.minelittlepony.unicopia.util.Lerp; import com.minelittlepony.unicopia.util.Lerp;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
@ -115,6 +116,8 @@ public class ShieldSpell extends AbstractSpell {
if (source.isClient()) { if (source.isClient()) {
generateParticles(source); generateParticles(source);
} else {
Ether.get(source.asWorld()).getOrCreate(this, source).setRadius(radius.getValue());
} }
if (situation == Situation.PROJECTILE) { if (situation == Situation.PROJECTILE) {

View file

@ -136,7 +136,9 @@ public class DismissSpellScreen extends GameGui {
} }
private Spell getActualSpell() { private Spell getActualSpell() {
return spell instanceof AbstractDelegatingSpell s && s.getDelegate() instanceof Spell p ? p : spell; return spell instanceof AbstractDelegatingSpell s && s.getDelegate() instanceof Spell p ? p
: spell instanceof PlacementControlSpell s && s.getDelegate() instanceof Spell p ? p
: spell;
} }
@Override @Override
@ -161,11 +163,10 @@ public class DismissSpellScreen extends GameGui {
MatrixStack matrices = context.getMatrices(); MatrixStack matrices = context.getMatrices();
var type = actualSpell.getTypeAndTraits(); var type = actualSpell.getTypeAndTraits();
var affinity = actualSpell.getAffinity();
copy.set(mouseX - width * 0.5F - x * 0.5F, mouseY - height * 0.5F - y * 0.5F, 0, 0); copy.set(mouseX - width * 0.5F - x * 0.5F, mouseY - height * 0.5F - y * 0.5F, 0, 0);
DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, affinity.getColor().getColorValue()); DrawableUtil.drawLine(matrices, 0, 0, (int)x, (int)y, actualSpell.getAffinity().getColor().getColorValue());
DrawableUtil.renderItemIcon(context, actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(), DrawableUtil.renderItemIcon(context, actualSpell.isDead() ? UItems.BOTCHED_GEM.getDefaultStack() : type.getDefaultStack(),
x - 8 - copy.x * 0.2F, x - 8 - copy.x * 0.2F,
y - 8 - copy.y * 0.2F, y - 8 - copy.y * 0.2F,

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.server.world;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -15,6 +16,7 @@ import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.*; import net.minecraft.nbt.*;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.PersistentState; import net.minecraft.world.PersistentState;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -168,9 +170,10 @@ public class Ether extends PersistentState {
private boolean removed; private boolean removed;
private boolean taken; private boolean taken;
public float pitch; private float pitch;
public float yaw; private final AtomicBoolean changed = new AtomicBoolean(true);
public float radius; private float yaw;
private float radius;
private Entry(NbtElement nbt) { private Entry(NbtElement nbt) {
this.entity = new EntityReference<>(); this.entity = new EntityReference<>();
@ -184,6 +187,46 @@ public class Ether extends PersistentState {
spellId = spell.getUuid(); spellId = spell.getUuid();
} }
public boolean hasChanged() {
return changed.getAndSet(false);
}
public float getPitch() {
return pitch;
}
public void setPitch(float pitch) {
if (!MathHelper.approximatelyEquals(this.pitch, pitch)) {
this.pitch = pitch;
changed.set(true);
}
markDirty();
}
public float getYaw() {
return yaw;
}
public void setYaw(float yaw) {
if (!MathHelper.approximatelyEquals(this.yaw, yaw)) {
this.yaw = yaw;
changed.set(true);
}
markDirty();
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
if (!MathHelper.approximatelyEquals(this.radius, radius)) {
this.radius = radius;
changed.set(true);
}
markDirty();
}
boolean isAlive() { boolean isAlive() {
return !isDead(); return !isDead();
} }