mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 07:17:58 +01:00
Split the placed spell into separate types
This commit is contained in:
parent
575c1f7438
commit
77de42dd09
13 changed files with 261 additions and 211 deletions
|
@ -1,11 +1,12 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.data.Rot;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
|
||||
public interface OrientedSpell extends Spell {
|
||||
void setOrientation(float pitch, float yaw);
|
||||
void setOrientation(Caster<?> caster, float pitch, float yaw);
|
||||
|
||||
default void setOrientation(Rot rotation) {
|
||||
setOrientation(rotation.pitch(), rotation.yaw());
|
||||
default void setOrientation(Caster<?> caster, Rot rotation) {
|
||||
setOrientation(caster, rotation.pitch(), rotation.yaw());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,16 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell.PlacementDelegate;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||
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.UEntities;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.network.Channel;
|
||||
import com.minelittlepony.unicopia.network.MsgCasterLookRequest;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||
import com.minelittlepony.unicopia.server.world.Ether;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.nbt.*;
|
||||
import net.minecraft.registry.*;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* A spell that can be attached to a specific location in the world.
|
||||
|
@ -33,29 +21,8 @@ import net.minecraft.world.World;
|
|||
* When cast two copies of this spell are created. One is attached to the player and is the controlling spell,
|
||||
* the other is attached to a cast spell entity and placed in the world.
|
||||
*
|
||||
* TODO: Split this up into separate classes.
|
||||
*/
|
||||
public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedSpell {
|
||||
/**
|
||||
* Dimension the spell was originally cast in
|
||||
*/
|
||||
@Nullable
|
||||
private RegistryKey<World> dimension;
|
||||
|
||||
/**
|
||||
* ID of the placed counterpart of this spell.
|
||||
*/
|
||||
@Nullable
|
||||
private UUID placedSpellId;
|
||||
|
||||
/**
|
||||
* The cast spell entity
|
||||
*/
|
||||
private final EntityReference<CastSpellEntity> castEntity = new EntityReference<>();
|
||||
|
||||
public float pitch;
|
||||
public float yaw;
|
||||
|
||||
private int prevAge;
|
||||
private int age;
|
||||
|
||||
|
@ -63,15 +30,35 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
private int prevDeathTicks;
|
||||
private int deathTicks;
|
||||
|
||||
private Optional<Vec3d> position = Optional.empty();
|
||||
private UUID controllingEntityUuid;
|
||||
private UUID controllingSpellUuid;
|
||||
|
||||
public float pitch;
|
||||
public float yaw;
|
||||
|
||||
public PlaceableSpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public PlaceableSpell setSpell(Spell spell) {
|
||||
delegate.set(spell);
|
||||
return this;
|
||||
PlaceableSpell(Caster<?> caster, PlacementControlSpell control, Spell delegate) {
|
||||
this(SpellType.PLACED_SPELL.withTraits());
|
||||
this.controllingEntityUuid = caster.asEntity().getUuid();
|
||||
this.controllingSpellUuid = control.getUuid();
|
||||
this.delegate.set(delegate);
|
||||
|
||||
if (delegate instanceof PlacementDelegate s) {
|
||||
s.onPlaced(caster, control);
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
@ -86,7 +73,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
|
||||
@Override
|
||||
public boolean isDying() {
|
||||
return dead && deathTicks > 0;
|
||||
return dead && deathTicks > 0 || super.isDying();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,6 +81,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
super.setDead();
|
||||
dead = true;
|
||||
deathTicks = 20;
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -103,32 +91,10 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
|
||||
@Override
|
||||
public boolean tick(Caster<?> source, Situation situation) {
|
||||
if (situation == Situation.BODY) {
|
||||
if (!source.isClient()) {
|
||||
if (dimension == null) {
|
||||
dimension = source.asWorld().getRegistryKey();
|
||||
if (source instanceof Pony) {
|
||||
Channel.SERVER_REQUEST_PLAYER_LOOK.sendToPlayer(new MsgCasterLookRequest(getUuid()), (ServerPlayerEntity)source.asEntity());
|
||||
}
|
||||
setDirty();
|
||||
}
|
||||
|
||||
castEntity.getTarget().ifPresentOrElse(
|
||||
target -> checkDetachment(source, target),
|
||||
() -> spawnPlacedEntity(source)
|
||||
);
|
||||
}
|
||||
|
||||
return !isDead();
|
||||
}
|
||||
|
||||
if (situation == Situation.GROUND_ENTITY) {
|
||||
if (!source.isClient()) {
|
||||
if (Ether.get(source.asWorld()).get(this, source) == null) {
|
||||
if (!source.isClient() && !checkConnection(source)) {
|
||||
setDead();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
prevAge = age;
|
||||
if (age < 25) {
|
||||
|
@ -138,91 +104,34 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
return super.tick(source, Situation.GROUND);
|
||||
}
|
||||
|
||||
return !isDead();
|
||||
private boolean checkConnection(Caster<?> source) {
|
||||
return Ether.get(source.asWorld()).get(SpellType.PLACE_CONTROL_SPELL, controllingEntityUuid, controllingSpellUuid) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickDying(Caster<?> caster) {
|
||||
super.tickDying(caster);
|
||||
prevDeathTicks = deathTicks;
|
||||
deathTicks--;
|
||||
}
|
||||
|
||||
private void checkDetachment(Caster<?> source, EntityValues<?> target) {
|
||||
if (getWorld(source).map(Ether::get).map(ether -> ether.get(getTypeAndTraits().type(), target, placedSpellId)).isEmpty()) {
|
||||
setDead();
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnPlacedEntity(Caster<?> source) {
|
||||
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 = delegate.get().toPlaceable();
|
||||
if (delegate.get() instanceof PlacementDelegate delegate) {
|
||||
delegate.onPlaced(source, copy, entity);
|
||||
}
|
||||
entity.getSpellSlot().put(copy);
|
||||
entity.setCaster(source);
|
||||
entity.getWorld().spawnEntity(entity);
|
||||
placedSpellId = copy.getUuid();
|
||||
Ether.get(entity.getWorld()).getOrCreate(copy, entity);
|
||||
|
||||
castEntity.set(entity);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrientation(float pitch, float yaw) {
|
||||
this.pitch = -90 - pitch;
|
||||
this.yaw = -yaw;
|
||||
if (delegate.get() instanceof OrientedSpell o) {
|
||||
o.setOrientation(pitch, yaw);
|
||||
}
|
||||
setDirty();
|
||||
}
|
||||
|
||||
public void setPosition(Caster<?> source, Vec3d position) {
|
||||
this.position = Optional.of(position);
|
||||
this.dimension = source.asWorld().getRegistryKey();
|
||||
castEntity.ifPresent(source.asWorld(), entity -> {
|
||||
entity.updatePositionAndAngles(position.x, position.y, position.z, entity.getYaw(), entity.getPitch());
|
||||
});
|
||||
if (delegate.get() instanceof PlaceableSpell o) {
|
||||
o.setPosition(source, position);
|
||||
}
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyed(Caster<?> source) {
|
||||
if (!source.isClient()) {
|
||||
castEntity.getTarget().ifPresent(target -> {
|
||||
getWorld(source).map(Ether::get)
|
||||
.ifPresent(ether -> ether.remove(getTypeAndTraits().type(), target.uuid()));
|
||||
});
|
||||
castEntity.set(null);
|
||||
getSpellEntity(source).ifPresent(e -> {
|
||||
castEntity.set(null);
|
||||
});
|
||||
|
||||
if (source.asEntity() instanceof CastSpellEntity) {
|
||||
Ether.get(source.asWorld()).remove(this, source);
|
||||
}
|
||||
}
|
||||
super.onDestroyed(source);
|
||||
}
|
||||
|
||||
public Optional<CastSpellEntity> getSpellEntity(Caster<?> source) {
|
||||
return getWorld(source).map(castEntity::get);
|
||||
}
|
||||
|
||||
public Optional<Vec3d> getPosition() {
|
||||
return castEntity.getTarget().map(EntityValues::pos);
|
||||
}
|
||||
|
||||
protected Optional<World> getWorld(Caster<?> source) {
|
||||
return Optional.ofNullable(dimension)
|
||||
.map(dim -> source.asWorld().getServer().getWorld(dim));
|
||||
@Override
|
||||
public void setOrientation(Caster<?> caster, float pitch, float yaw) {
|
||||
this.pitch = -pitch - 90;
|
||||
this.yaw = -yaw;
|
||||
Entity entity = caster.asEntity();
|
||||
entity.updatePositionAndAngles(entity.getX(), entity.getY(), entity.getZ(), this.yaw, this.pitch);
|
||||
entity.setYaw(this.yaw);
|
||||
entity.setPitch(this.pitch);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -233,17 +142,12 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
compound.putInt("age", age);
|
||||
compound.putFloat("pitch", pitch);
|
||||
compound.putFloat("yaw", yaw);
|
||||
position.ifPresent(pos -> {
|
||||
compound.put("position", NbtSerialisable.writeVector(pos));
|
||||
});
|
||||
if (placedSpellId != null) {
|
||||
compound.putUuid("placedSpellId", placedSpellId);
|
||||
if (controllingEntityUuid != null) {
|
||||
compound.putUuid("owningEntity", controllingEntityUuid);
|
||||
}
|
||||
if (dimension != null) {
|
||||
compound.putString("dimension", dimension.getValue().toString());
|
||||
if (controllingSpellUuid != null) {
|
||||
compound.putUuid("owningSpell", controllingSpellUuid);
|
||||
}
|
||||
compound.put("castEntity", castEntity.toNBT());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -252,27 +156,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
|
|||
dead = compound.getBoolean("dead");
|
||||
deathTicks = compound.getInt("deathTicks");
|
||||
age = compound.getInt("age");
|
||||
controllingEntityUuid = compound.containsUuid("owningEntity") ? compound.getUuid("owningEntity") : null;
|
||||
controllingSpellUuid = compound.containsUuid("owningSpell") ? compound.getUuid("owningSpell") : null;
|
||||
pitch = compound.getFloat("pitch");
|
||||
yaw = compound.getFloat("yaw");
|
||||
position = compound.contains("position") ? Optional.of(NbtSerialisable.readVector(compound.getList("position", NbtElement.FLOAT_TYPE))) : Optional.empty();
|
||||
placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null;
|
||||
if (compound.contains("dimension", NbtElement.STRING_TYPE)) {
|
||||
Identifier id = Identifier.tryParse(compound.getString("dimension"));
|
||||
if (id != null) {
|
||||
dimension = RegistryKey.of(RegistryKeys.WORLD, id);
|
||||
}
|
||||
}
|
||||
if (compound.contains("castEntity")) {
|
||||
castEntity.fromNBT(compound.getCompound("castEntity"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaceableSpell toPlaceable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public interface PlacementDelegate {
|
||||
void onPlaced(Caster<?> source, PlaceableSpell parent, CastSpellEntity entity);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||
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.UEntities;
|
||||
import com.minelittlepony.unicopia.server.world.Ether;
|
||||
import com.minelittlepony.unicopia.util.NbtSerialisable;
|
||||
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class PlacementControlSpell extends AbstractDelegatingSpell implements OrientedSpell {
|
||||
@Nullable
|
||||
private UUID placedSpellId;
|
||||
private final EntityReference<CastSpellEntity> castEntity = new EntityReference<>();
|
||||
|
||||
private Optional<RegistryKey<World>> dimension = Optional.empty();
|
||||
private Optional<Vec3d> position = Optional.empty();
|
||||
private Optional<Vec3d> orientation = Optional.empty();
|
||||
|
||||
public PlacementControlSpell(CustomisedSpellType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
PlacementControlSpell(CustomisedSpellType<?> type, Spell delegate) {
|
||||
super(type);
|
||||
this.delegate.set(delegate);
|
||||
}
|
||||
|
||||
public Optional<Vec3d> getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setDimension(RegistryKey<World> dimension) {
|
||||
this.dimension = Optional.of(dimension);
|
||||
}
|
||||
|
||||
public void setPosition(Vec3d position) {
|
||||
this.position = Optional.of(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrientation(Caster<?> caster, float pitch, float yaw) {
|
||||
this.orientation = Optional.of(new Vec3d(pitch, yaw, 0));
|
||||
castEntity.ifPresent(caster.asWorld(), entity -> {
|
||||
entity.getSpellSlot().stream(SpellPredicate.IS_ORIENTED).forEach(spell -> {
|
||||
if (!getTypeAndTraits().type().test(spell)) {
|
||||
spell.setOrientation(caster, pitch, yaw);
|
||||
}
|
||||
});
|
||||
});
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Caster<?> caster) {
|
||||
boolean result = super.apply(caster);
|
||||
if (result) {
|
||||
if (!caster.isClient()) {
|
||||
Ether.get(caster.asWorld()).getOrCreate(this, caster);
|
||||
}
|
||||
if (dimension.isEmpty()) {
|
||||
setDimension(caster.asWorld().getRegistryKey());
|
||||
}
|
||||
if (position.isEmpty()) {
|
||||
setPosition(caster.asEntity().getPos());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
PlaceableSpell copy = new PlaceableSpell(source, this, getDelegate());
|
||||
|
||||
Vec3d pos = position.orElse(source.asEntity().getPos());
|
||||
Vec3d rot = orientation.orElse(Vec3d.ZERO);
|
||||
|
||||
CastSpellEntity entity = UEntities.CAST_SPELL.create(source.asWorld());
|
||||
entity.setCaster(source);
|
||||
entity.updatePositionAndAngles(pos.x, pos.y, pos.z, (float)rot.y, (float)rot.x);
|
||||
entity.setYaw((float)rot.y);
|
||||
entity.setPitch((float)rot.x);
|
||||
copy.apply(entity);
|
||||
entity.getWorld().spawnEntity(entity);
|
||||
|
||||
placedSpellId = copy.getUuid();
|
||||
castEntity.set(entity);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
private boolean checkConnection(Caster<?> source, EntityValues<?> target) {
|
||||
return getWorld(source)
|
||||
.map(Ether::get)
|
||||
.map(ether -> ether.get(SpellType.PLACED_SPELL, target, placedSpellId))
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
private Optional<World> getWorld(Caster<?> source) {
|
||||
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
|
||||
public void toNBT(NbtCompound compound) {
|
||||
super.toNBT(compound);
|
||||
position.ifPresent(pos -> compound.put("position", NbtSerialisable.writeVector(pos)));
|
||||
orientation.ifPresent(o -> compound.put("orientation", NbtSerialisable.writeVector(o)));
|
||||
dimension.ifPresent(d -> compound.putString("dimension", d.getValue().toString()));
|
||||
if (placedSpellId != null) {
|
||||
compound.putUuid("placedSpellId", placedSpellId);
|
||||
}
|
||||
compound.put("castEntity", castEntity.toNBT());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNBT(NbtCompound compound) {
|
||||
super.fromNBT(compound);
|
||||
placedSpellId = compound.containsUuid("placedSpellId") ? compound.getUuid("placedSpellId") : null;
|
||||
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();
|
||||
if (compound.contains("dimension", NbtElement.STRING_TYPE)) {
|
||||
dimension = Optional.ofNullable(Identifier.tryParse(compound.getString("dimension"))).map(id -> RegistryKey.of(RegistryKeys.WORLD, id));
|
||||
}
|
||||
castEntity.fromNBT(compound.getCompound("castEntity"));
|
||||
}
|
||||
|
||||
public interface PlacementDelegate {
|
||||
void onPlaced(Caster<?> source, PlacementControlSpell parent);
|
||||
}
|
||||
}
|
|
@ -123,8 +123,8 @@ public interface Spell extends NbtSerialisable, Affine {
|
|||
/**
|
||||
* Converts this spell into a placeable spell.
|
||||
*/
|
||||
default PlaceableSpell toPlaceable() {
|
||||
return SpellType.PLACED_SPELL.withTraits().create().setSpell(this);
|
||||
default PlacementControlSpell toPlaceable() {
|
||||
return new PlacementControlSpell(SpellType.PLACE_CONTROL_SPELL.withTraits(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,9 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
|||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.network.Channel;
|
||||
import com.minelittlepony.unicopia.network.MsgCasterLookRequest;
|
||||
import com.minelittlepony.unicopia.particle.*;
|
||||
import com.minelittlepony.unicopia.server.world.Ether;
|
||||
import com.minelittlepony.unicopia.util.shape.*;
|
||||
|
@ -25,13 +27,14 @@ import net.minecraft.entity.LivingEntity;
|
|||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.network.packet.s2c.play.PositionFlag;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.WorldEvents;
|
||||
|
||||
public class PortalSpell extends AbstractSpell implements PlaceableSpell.PlacementDelegate, OrientedSpell {
|
||||
public class PortalSpell extends AbstractSpell implements PlacementControlSpell.PlacementDelegate, OrientedSpell {
|
||||
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
||||
.with(Trait.LIFE, 10)
|
||||
.with(Trait.KNOWLEDGE, 1)
|
||||
|
@ -91,7 +94,7 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
|
|||
|
||||
@Override
|
||||
public boolean apply(Caster<?> caster) {
|
||||
setOrientation(caster.asEntity().getPitch(), caster.asEntity().getYaw());
|
||||
setOrientation(caster, caster.asEntity().getPitch(), caster.asEntity().getYaw());
|
||||
return toPlaceable().apply(caster);
|
||||
}
|
||||
|
||||
|
@ -195,22 +198,25 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setOrientation(float pitch, float yaw) {
|
||||
public void setOrientation(Caster<?> caster, float pitch, float yaw) {
|
||||
this.pitch = pitch;
|
||||
this.yaw = yaw;
|
||||
particleArea = PARTICLE_AREA.rotate(
|
||||
pitch * MathHelper.RADIANS_PER_DEGREE,
|
||||
(180 - yaw) * MathHelper.RADIANS_PER_DEGREE
|
||||
yaw * MathHelper.RADIANS_PER_DEGREE
|
||||
);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaced(Caster<?> source, PlaceableSpell parent, CastSpellEntity entity) {
|
||||
public void onPlaced(Caster<?> source, PlacementControlSpell parent) {
|
||||
parent.setOrientation(source, source.asEntity().getPitch(), source.asEntity().getYaw());
|
||||
LivingEntity caster = source.getMaster();
|
||||
Vec3d targetPos = caster.getRotationVector().multiply(3).add(caster.getEyePos());
|
||||
parent.setOrientation(pitch, yaw);
|
||||
entity.setPos(targetPos.x, Math.abs(pitch) > 15 ? targetPos.y : caster.getPos().y, targetPos.z);
|
||||
parent.setPosition(new Vec3d(targetPos.x, caster.getPos().y, targetPos.z));
|
||||
if (source instanceof Pony pony) {
|
||||
Channel.SERVER_REQUEST_PLAYER_LOOK.sendToPlayer(new MsgCasterLookRequest(parent.getUuid()), (ServerPlayerEntity)pony.asEntity());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell;
|
|||
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.RageAbilitySpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.ThrowableSpell;
|
||||
|
@ -43,6 +44,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
|
|||
|
||||
private static final DynamicCommandExceptionType UNKNOWN_SPELL_TYPE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("spell_type.unknown", id));
|
||||
|
||||
public static final SpellType<PlacementControlSpell> PLACE_CONTROL_SPELL = register("place_controller", SpellType.<PlacementControlSpell>builder(PlacementControlSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT));
|
||||
public static final SpellType<PlaceableSpell> PLACED_SPELL = register("placed", builder(PlaceableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().stackable().shape(GemstoneItem.Shape.DONUT));
|
||||
public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", builder(ThrowableSpell::new).affinity(Affinity.NEUTRAL).unobtainable().shape(GemstoneItem.Shape.DONUT));
|
||||
|
||||
|
|
|
@ -40,11 +40,11 @@ public class DismissSpellScreen extends GameGui {
|
|||
double azimuth = 0;
|
||||
double ring = 2;
|
||||
|
||||
List<PlaceableSpell> placeableSpells = new ArrayList<>();
|
||||
List<PlacementControlSpell> placeableSpells = new ArrayList<>();
|
||||
|
||||
for (Spell spell : pony.getSpellSlot().stream().filter(SpellPredicate.IS_VISIBLE).toList()) {
|
||||
|
||||
if (spell instanceof PlaceableSpell placeable) {
|
||||
if (spell instanceof PlacementControlSpell placeable) {
|
||||
if (placeable.getPosition().isPresent()) {
|
||||
placeableSpells.add(placeable);
|
||||
continue;
|
||||
|
|
|
@ -6,7 +6,6 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
|
|||
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
import com.minelittlepony.unicopia.client.render.model.PlaneModel;
|
||||
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
|
||||
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
|
@ -27,12 +26,7 @@ public class PlacedSpellRenderer extends SpellRenderer<PlaceableSpell> {
|
|||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider vertices, PlaceableSpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
|
||||
if (!(caster.asEntity() instanceof CastSpellEntity castSpell)) {
|
||||
return;
|
||||
}
|
||||
|
||||
matrices.push();
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-castSpell.getYaw()));
|
||||
|
||||
Spell delegate = spell.getDelegate();
|
||||
|
||||
|
@ -42,8 +36,8 @@ public class PlacedSpellRenderer extends SpellRenderer<PlaceableSpell> {
|
|||
matrices.push();
|
||||
float height = caster.asEntity().getHeight();
|
||||
matrices.translate(0, (-spell.pitch / 90F) * height * 0.5F, 0);
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.yaw));
|
||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch));
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw));
|
||||
SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertices, delegate, caster, light, spell.getScale(tickDelta), limbDistance, tickDelta, animationProgress, headYaw, headPitch);
|
||||
matrices.pop();
|
||||
}
|
||||
|
@ -58,8 +52,8 @@ public class PlacedSpellRenderer extends SpellRenderer<PlaceableSpell> {
|
|||
float height = caster.asEntity().getHeight();
|
||||
matrices.translate(0, (-spell.pitch / 90F) * height * 0.5F, 0);
|
||||
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.yaw));
|
||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch));
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw));
|
||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
|
||||
|
||||
float scale = spell.getScale(tickDelta) * 3;
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.Optional;
|
|||
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.PlacementControlSpell;
|
||||
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.trait.SpellTraits;
|
||||
|
@ -98,11 +98,11 @@ public class CastCommand {
|
|||
|
||||
private static int placed(CommandContext<ServerCommandSource> source, TraitsFunc traits, Optional<Vec3d> position, Vec2f rotation) throws CommandSyntaxException {
|
||||
ServerPlayerEntity player = source.getSource().getPlayerOrThrow();
|
||||
PlaceableSpell spell = getSpell(source, traits).create().toPlaceable();
|
||||
PlacementControlSpell spell = getSpell(source, traits).create().toPlaceable();
|
||||
Caster<?> caster = Caster.of(player).orElseThrow();
|
||||
|
||||
spell.setOrientation(rotation.x, rotation.y);
|
||||
position.ifPresent(pos -> spell.setPosition(caster, pos));
|
||||
spell.setOrientation(caster, rotation.x, rotation.y);
|
||||
position.ifPresent(spell::setPosition);
|
||||
spell.apply(caster);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -81,14 +81,12 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster<CastS
|
|||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (isRemoved()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!spells.tick(Situation.GROUND_ENTITY)) {
|
||||
if (!isRemoved() && !spells.tick(Situation.GROUND_ENTITY)) {
|
||||
if (!isClient()) {
|
||||
discard();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDimensions(EntityPose pose) {
|
||||
|
|
|
@ -49,11 +49,10 @@ public record MsgCasterLookRequest (UUID spellId) implements Packet<PlayerEntity
|
|||
|
||||
@Override
|
||||
public void handle(ServerPlayerEntity sender) {
|
||||
Pony.of(sender).getSpellSlot()
|
||||
Pony pony = Pony.of(sender);
|
||||
pony.getSpellSlot()
|
||||
.get(SpellPredicate.IS_ORIENTED.withId(spellId))
|
||||
.ifPresent(spell -> {
|
||||
spell.setOrientation(rotation);
|
||||
});
|
||||
.ifPresent(spell -> spell.setOrientation(pony, rotation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ public class Ether extends PersistentState {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private <T extends Spell> Entry<T> get(SpellType<T> spell, UUID entityId, @Nullable UUID spellId) {
|
||||
public <T extends Spell> Entry<T> get(SpellType<T> spell, UUID entityId, @Nullable UUID spellId) {
|
||||
if (spellId == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ public interface NbtSerialisable {
|
|||
}
|
||||
|
||||
static Vec3d readVector(NbtList list) {
|
||||
|
||||
return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue