Refactor projectile event handlers

This commit is contained in:
Sollace 2022-12-04 22:46:45 +00:00
parent 9421587f9d
commit 8a16a8b501
17 changed files with 119 additions and 114 deletions

View file

@ -11,7 +11,6 @@ import net.minecraft.entity.Entity;
public interface SpellPredicate<T extends Spell> extends Predicate<Spell> { public interface SpellPredicate<T extends Spell> extends Predicate<Spell> {
SpellPredicate<IllusionarySpell> CAN_SUPPRESS = s -> s instanceof IllusionarySpell; SpellPredicate<IllusionarySpell> CAN_SUPPRESS = s -> s instanceof IllusionarySpell;
SpellPredicate<PlaceableSpell> IS_PLACED = s -> s instanceof PlaceableSpell; SpellPredicate<PlaceableSpell> IS_PLACED = s -> s instanceof PlaceableSpell;
SpellPredicate<ProjectileSpell> HAS_PROJECTILE_EVENTS = s -> s instanceof ProjectileSpell;
SpellPredicate<AbstractDisguiseSpell> IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell; SpellPredicate<AbstractDisguiseSpell> IS_DISGUISE = s -> s instanceof AbstractDisguiseSpell;
SpellPredicate<MimicSpell> IS_MIMIC = s -> s instanceof MimicSpell; SpellPredicate<MimicSpell> IS_MIMIC = s -> s instanceof MimicSpell;
SpellPredicate<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell; SpellPredicate<ShieldSpell> IS_SHIELD_LIKE = spell -> spell instanceof ShieldSpell;

View file

@ -13,14 +13,12 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate; import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
public abstract class AbstractDelegatingSpell implements ProjectileSpell { public abstract class AbstractDelegatingSpell implements Spell,
private static final Function<Object, ProjectileSpell> PROJECTILE_SPELL = a -> a instanceof ProjectileSpell p ? p : null; ProjectileDelegate.ConfigurationListener, ProjectileDelegate.BlockHitListener, ProjectileDelegate.EntityHitListener {
private static final Function<Object, ProjectileDelegate> PROJECTILE_DELEGATE = a -> a instanceof ProjectileDelegate p ? p : null;
private boolean isDirty; private boolean isDirty;
@ -36,12 +34,12 @@ public abstract class AbstractDelegatingSpell implements ProjectileSpell {
@Override @Override
public boolean equalsOrContains(UUID id) { public boolean equalsOrContains(UUID id) {
return ProjectileSpell.super.equalsOrContains(id) || getDelegates().stream().anyMatch(s -> s.equalsOrContains(id)); return Spell.super.equalsOrContains(id) || getDelegates().stream().anyMatch(s -> s.equalsOrContains(id));
} }
@Override @Override
public Stream<Spell> findMatches(Predicate<Spell> predicate) { public Stream<Spell> findMatches(Predicate<Spell> predicate) {
return Stream.concat(ProjectileSpell.super.findMatches(predicate), getDelegates().stream().flatMap(s -> s.findMatches(predicate))); return Stream.concat(Spell.super.findMatches(predicate), getDelegates().stream().flatMap(s -> s.findMatches(predicate)));
} }
@Override @Override
@ -95,18 +93,18 @@ public abstract class AbstractDelegatingSpell implements ProjectileSpell {
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
getDelegates(PROJECTILE_DELEGATE).forEach(a -> a.onImpact(projectile, pos, state)); getDelegates(BlockHitListener.PREDICATE).forEach(a -> a.onImpact(projectile, hit));
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
getDelegates(PROJECTILE_DELEGATE).forEach(a -> a.onImpact(projectile, entity)); getDelegates(EntityHitListener.PREDICATE).forEach(a -> a.onImpact(projectile, hit));
} }
@Override @Override
public void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) { public void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) {
getDelegates(PROJECTILE_SPELL).forEach(a -> a.configureProjectile(projectile, caster)); getDelegates(ConfigurationListener.PREDICATE).forEach(a -> a.configureProjectile(projectile, caster));
} }
@Override @Override

View file

@ -1,22 +0,0 @@
package com.minelittlepony.unicopia.ability.magic.spell;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
/**
* Magic effects that can be thrown.
*/
public interface ProjectileSpell extends Spell, ProjectileDelegate {
@Override
default void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) {
if (!projectile.isClient()) {
tick(projectile, Situation.PROJECTILE);
}
}
default void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster) { }
}

View file

@ -5,7 +5,6 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.*; import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
import com.minelittlepony.unicopia.block.data.ModificationType; import com.minelittlepony.unicopia.block.data.ModificationType;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleHandle; import com.minelittlepony.unicopia.particle.ParticleHandle;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.MagicalDamageSource;

View file

@ -9,16 +9,18 @@ import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.ItemEntity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class AttractiveSpell extends ShieldSpell implements ProjectileSpell, HomingSpell, TimedSpell { public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSpell, ProjectileDelegate.EntityHitListener {
private final EntityReference<Entity> target = new EntityReference<>(); private final EntityReference<Entity> target = new EntityReference<>();
@ -140,10 +142,10 @@ public class AttractiveSpell extends ShieldSpell implements ProjectileSpell, Hom
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
if (!isDead() && getTraits().get(Trait.CHAOS) > 0) { if (!isDead() && getTraits().get(Trait.CHAOS) > 0) {
setDead(); setDead();
Caster.of(entity).ifPresent(getTypeAndTraits()::apply); Caster.of(hit.getEntity()).ifPresent(getTypeAndTraits()::apply);
} }
} }

View file

@ -5,18 +5,19 @@ import java.util.function.Consumer;
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.spell.ProjectileSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.mixin.MixinFallingBlockEntity; import com.minelittlepony.unicopia.mixin.MixinFallingBlockEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.Trace; import com.minelittlepony.unicopia.util.Trace;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -24,7 +25,7 @@ import net.minecraft.world.World;
/** /**
* Picks up and throws an entity or block. * Picks up and throws an entity or block.
*/ */
public class CatapultSpell extends AbstractSpell implements ProjectileSpell { public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.BlockHitListener, ProjectileDelegate.EntityHitListener {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.FOCUS, 50) .with(Trait.FOCUS, 50)
.with(Trait.KNOWLEDGE, 1) .with(Trait.KNOWLEDGE, 1)
@ -40,16 +41,16 @@ public class CatapultSpell extends AbstractSpell implements ProjectileSpell {
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
if (!projectile.isClient() && projectile.canModifyAt(pos)) { if (!projectile.isClient() && projectile.canModifyAt(hit.getBlockPos())) {
createBlockEntity(projectile.world, pos, e -> apply(projectile, e)); createBlockEntity(projectile.world, hit.getBlockPos(), e -> apply(projectile, e));
} }
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
if (!projectile.isClient()) { if (!projectile.isClient()) {
apply(projectile, entity); apply(projectile, hit.getEntity());
} }
} }

View file

@ -5,7 +5,6 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
@ -18,7 +17,6 @@ import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
@ -29,6 +27,8 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.explosion.Explosion.DestructionType; import net.minecraft.world.explosion.Explosion.DestructionType;
@ -40,7 +40,7 @@ import net.minecraft.world.explosion.Explosion.DestructionType;
* - Garbage bin * - Garbage bin
* - Link with a teleportation spell to create a wormhole * - Link with a teleportation spell to create a wormhole
*/ */
public class DarkVortexSpell extends AttractiveSpell implements ProjectileSpell { public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelegate.BlockHitListener {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.CHAOS, 5) .with(Trait.CHAOS, 5)
.with(Trait.KNOWLEDGE, 1) .with(Trait.KNOWLEDGE, 1)
@ -58,8 +58,9 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileSpell
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
if (!projectile.isClient()) { if (!projectile.isClient()) {
BlockPos pos = hit.getBlockPos();
projectile.world.createExplosion(projectile, pos.getX(), pos.getY(), pos.getZ(), 3, DestructionType.NONE); projectile.world.createExplosion(projectile, pos.getX(), pos.getY(), pos.getZ(), 3, DestructionType.NONE);
toPlaceable().tick(projectile, Situation.BODY); toPlaceable().tick(projectile, Situation.BODY);
} }
@ -212,8 +213,8 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileSpell
if (target instanceof MagicProjectileEntity projectile) { if (target instanceof MagicProjectileEntity projectile) {
Item item = projectile.getStack().getItem(); Item item = projectile.getStack().getItem();
if (item instanceof ProjectileDelegate p && master != null) { if (item instanceof ProjectileDelegate.EntityHitListener p && master != null) {
p.onImpact(projectile, master); p.onImpact(projectile, new EntityHitResult(master));
} }
} else if (target instanceof PersistentProjectileEntity) { } else if (target instanceof PersistentProjectileEntity) {
if (master != null) { if (master != null) {

View file

@ -3,18 +3,21 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell; import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.util.hit.EntityHitResult;
public class FireBoltSpell extends AbstractSpell implements ProjectileSpell, HomingSpell { public class FireBoltSpell extends AbstractSpell implements HomingSpell,
ProjectileDelegate.ConfigurationListener, ProjectileDelegate.EntityHitListener {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.FOCUS, 10) .with(Trait.FOCUS, 10)
.with(Trait.CHAOS, 1) .with(Trait.CHAOS, 1)
@ -35,8 +38,8 @@ public class FireBoltSpell extends AbstractSpell implements ProjectileSpell, Hom
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
entity.setOnFireFor(90); hit.getEntity().setOnFireFor(90);
} }
@Override @Override

View file

@ -6,12 +6,12 @@ import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell;
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.block.state.StateMaps; import com.minelittlepony.unicopia.block.state.StateMaps;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.VecHelper; import com.minelittlepony.unicopia.util.VecHelper;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
@ -29,6 +29,8 @@ import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.tag.BlockTags; import net.minecraft.tag.BlockTags;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -37,7 +39,7 @@ import net.minecraft.world.explosion.Explosion.DestructionType;
/** /**
* Simple fire spell that triggers an effect when used on a block. * Simple fire spell that triggers an effect when used on a block.
*/ */
public class FireSpell extends AbstractAreaEffectSpell implements ProjectileSpell { public class FireSpell extends AbstractAreaEffectSpell implements ProjectileDelegate.BlockHitListener, ProjectileDelegate.EntityHitListener {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.FIRE, 15) .with(Trait.FIRE, 15)
.build(); .build();
@ -47,16 +49,18 @@ public class FireSpell extends AbstractAreaEffectSpell implements ProjectileSpel
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
if (!projectile.isClient()) { if (!projectile.isClient()) {
projectile.getReferenceWorld().createExplosion(projectile.getEntity(), pos.getX(), pos.getY(), pos.getZ(), 2, DestructionType.DESTROY); Vec3d pos = hit.getPos();
projectile.getReferenceWorld().createExplosion(projectile.getOwner(), pos.getX(), pos.getY(), pos.getZ(), 2, DestructionType.DESTROY);
} }
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
if (!projectile.isClient()) { if (!projectile.isClient()) {
projectile.getReferenceWorld().createExplosion(entity, entity.getX(), entity.getY(), entity.getZ(), 2, DestructionType.DESTROY); Entity entity = hit.getEntity();
projectile.getReferenceWorld().createExplosion(projectile.getOwner(), entity.getX(), entity.getY(), entity.getZ(), 2, DestructionType.DESTROY);
} }
} }

View file

@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.block.state.StateMaps; import com.minelittlepony.unicopia.block.state.StateMaps;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
@ -14,7 +15,7 @@ import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class ScorchSpell extends FireSpell { public class ScorchSpell extends FireSpell implements ProjectileDelegate.ConfigurationListener {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder() public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.FIRE, 10) .with(Trait.FIRE, 10)
.build(); .build();

View file

@ -9,10 +9,10 @@ import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
import com.minelittlepony.unicopia.entity.UEntities; import com.minelittlepony.unicopia.entity.UEntities;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.Registries; import com.minelittlepony.unicopia.util.Registries;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@ -21,12 +21,13 @@ import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.util.Util; import net.minecraft.util.Util;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.world.World; import net.minecraft.world.World;
/** /**
* Transforms whatever entity it strikes into a random other entity. * Transforms whatever entity it strikes into a random other entity.
*/ */
public class TransformationSpell extends AbstractSpell implements ProjectileSpell { public class TransformationSpell extends AbstractSpell implements ProjectileDelegate.EntityHitListener {
protected TransformationSpell(CustomisedSpellType<?> type) { protected TransformationSpell(CustomisedSpellType<?> type) {
super(type); super(type);
} }
@ -37,10 +38,11 @@ public class TransformationSpell extends AbstractSpell implements ProjectileSpel
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
if (projectile.world.isClient) { if (projectile.world.isClient) {
return; return;
} }
Entity entity = hit.getEntity();
pickType(entity.getType(), entity.world).flatMap(type -> convert(entity, type)).ifPresentOrElse(e -> { pickType(entity.getType(), entity.world).flatMap(type -> convert(entity, type)).ifPresentOrElse(e -> {
entity.playSound(USounds.SPELL_TRANSFORM_TRANSMUTE_ENTITY, 1, 1); entity.playSound(USounds.SPELL_TRANSFORM_TRANSMUTE_ENTITY, 1, 1);
}, () -> { }, () -> {

View file

@ -21,6 +21,7 @@ import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.world.WorldEvents; import net.minecraft.world.WorldEvents;
@ -51,8 +52,10 @@ public class FilledJarItem extends JarItem implements ChameleonItem {
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) { public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
super.onImpact(projectile, entity); super.onImpact(projectile, hit);
Entity entity = hit.getEntity();
if (!entity.isAttackable() || !(projectile instanceof FlyingItemEntity)) { if (!entity.isAttackable() || !(projectile instanceof FlyingItemEntity)) {
return; return;
@ -121,7 +124,7 @@ public class FilledJarItem extends JarItem implements ChameleonItem {
} }
@Override @Override
protected void onImpact(MagicProjectileEntity projectile) { public void onImpact(MagicProjectileEntity projectile) {
ItemStack stack = getAppearanceStack(projectile.getStack()); ItemStack stack = getAppearanceStack(projectile.getStack());
stack.damage(1, projectile.world.random, null); stack.damage(1, projectile.world.random, null);
projectile.dropStack(stack); projectile.dropStack(stack);

View file

@ -6,8 +6,8 @@ import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.entity.PhysicsBodyProjectileEntity; import com.minelittlepony.unicopia.entity.PhysicsBodyProjectileEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.block.BlockState;
import net.minecraft.block.DispenserBlock; import net.minecraft.block.DispenserBlock;
import net.minecraft.block.dispenser.ProjectileDispenserBehavior; import net.minecraft.block.dispenser.ProjectileDispenserBehavior;
import net.minecraft.entity.FlyingItemEntity; import net.minecraft.entity.FlyingItemEntity;
@ -16,12 +16,12 @@ import net.minecraft.entity.projectile.PersistentProjectileEntity;
import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.Position; import net.minecraft.util.math.Position;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
import net.minecraft.world.World; import net.minecraft.world.World;
public class HeavyProjectileItem extends ProjectileItem { public class HeavyProjectileItem extends ProjectileItem implements ProjectileDelegate.BlockHitListener {
public HeavyProjectileItem(Settings settings, float projectileDamage) { public HeavyProjectileItem(Settings settings, float projectileDamage) {
super(settings, projectileDamage); super(settings, projectileDamage);
@ -52,13 +52,13 @@ public class HeavyProjectileItem extends ProjectileItem {
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
if (projectile.world.getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) { if (projectile.world.getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) {
float damage = projectile instanceof FlyingItemEntity ? getProjectileDamage(((FlyingItemEntity)projectile).getStack()) : 0; float damage = projectile instanceof FlyingItemEntity ? getProjectileDamage(((FlyingItemEntity)projectile).getStack()) : 0;
if (damage > 0 && projectile.world.random.nextInt(90) == 0) { if (damage > 0 && projectile.world.random.nextInt(90) == 0) {
if (state.isIn(UTags.FRAGILE)) { if (projectile.world.getBlockState(hit.getBlockPos()).isIn(UTags.FRAGILE)) {
projectile.world.breakBlock(pos, true); projectile.world.breakBlock(hit.getBlockPos(), true);
} }
} }
} }

View file

@ -7,11 +7,10 @@ import com.minelittlepony.unicopia.entity.ItemImpl;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LightningEntity; import net.minecraft.entity.LightningEntity;
@ -20,13 +19,12 @@ import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvent;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkSectionPos; import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Heightmap; import net.minecraft.world.Heightmap;
import net.minecraft.world.WorldEvents; import net.minecraft.world.WorldEvents;
public class JarItem extends ProjectileItem implements ItemImpl.GroundTickCallback { public class JarItem extends ProjectileItem implements ItemImpl.GroundTickCallback, ProjectileDelegate.HitListener {
private final boolean rain; private final boolean rain;
private final boolean thunder; private final boolean thunder;
@ -82,16 +80,7 @@ public class JarItem extends ProjectileItem implements ItemImpl.GroundTickCallba
} }
@Override @Override
public void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) { public void onImpact(MagicProjectileEntity projectile) {
onImpact(projectile);
}
@Override
public void onImpact(MagicProjectileEntity projectile, Entity entity) {
onImpact(projectile);
}
protected void onImpact(MagicProjectileEntity projectile) {
if (!projectile.world.isClient()) { if (!projectile.world.isClient()) {
ServerWorld world = (ServerWorld)projectile.world; ServerWorld world = (ServerWorld)projectile.world;

View file

@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.item;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
import com.minelittlepony.unicopia.util.SoundEmitter; import com.minelittlepony.unicopia.util.SoundEmitter;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -17,7 +16,7 @@ import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World; import net.minecraft.world.World;
abstract class ProjectileItem extends Item implements ProjectileDelegate { abstract class ProjectileItem extends Item {
private final float projectileDamage; private final float projectileDamage;

View file

@ -1,6 +1,8 @@
package com.minelittlepony.unicopia.projectile; package com.minelittlepony.unicopia.projectile;
import java.util.Optional;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -10,7 +12,6 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.ability.magic.Levelled;
import com.minelittlepony.unicopia.ability.magic.SpellContainer; import com.minelittlepony.unicopia.ability.magic.SpellContainer;
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityPhysics;
@ -273,7 +274,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
protected void onBlockHit(BlockHitResult hit) { protected void onBlockHit(BlockHitResult hit) {
super.onBlockHit(hit); super.onBlockHit(hit);
forEachDelegates(effect -> effect.onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos()))); forEachDelegates(effect -> effect.onImpact(this, hit), ProjectileDelegate.BlockHitListener.PREDICATE);
} }
@Override @Override
@ -291,20 +292,16 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
entity.damage(DamageSource.thrownProjectile(this, getOwner()), getThrowDamage()); entity.damage(DamageSource.thrownProjectile(this, getOwner()), getThrowDamage());
} }
forEachDelegates(effect -> effect.onImpact(this, entity)); forEachDelegates(effect -> effect.onImpact(this, hit), ProjectileDelegate.EntityHitListener.PREDICATE);
} }
} }
protected void forEachDelegates(Consumer<ProjectileDelegate> consumer) { protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
getSpellSlot().forEach(spell -> { getSpellSlot().forEach(spell -> {
if (SpellPredicate.HAS_PROJECTILE_EVENTS.test(spell)) { Optional.ofNullable(predicate.apply(spell)).ifPresent(consumer);
consumer.accept((ProjectileDelegate)spell);
}
return Operation.SKIP; return Operation.SKIP;
}, world.isClient); }, world.isClient);
if (getItem().getItem() instanceof ProjectileDelegate) { Optional.ofNullable(predicate.apply(getItem().getItem())).ifPresent(consumer);
consumer.accept(((ProjectileDelegate)getItem().getItem()));
}
} }
@Override @Override

View file

@ -1,17 +1,46 @@
package com.minelittlepony.unicopia.projectile; package com.minelittlepony.unicopia.projectile;
import net.minecraft.block.BlockState; import java.util.function.Function;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos; import com.minelittlepony.unicopia.ability.magic.Caster;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
public interface ProjectileDelegate { public interface ProjectileDelegate {
/** interface ConfigurationListener extends ProjectileDelegate {
* Called once the projectile lands either hitting the ground or an entity. Function<Object, ConfigurationListener> PREDICATE = a -> a instanceof ConfigurationListener ? (ConfigurationListener)a : null;
*/
default void onImpact(MagicProjectileEntity projectile, BlockPos pos, BlockState state) {}
void configureProjectile(MagicProjectileEntity projectile, Caster<?> caster);
}
interface HitListener extends BlockHitListener, EntityHitListener {
@Override
default void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
onImpact(projectile);
}
@Override
default void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
onImpact(projectile);
}
void onImpact(MagicProjectileEntity projectile);
}
interface BlockHitListener extends ProjectileDelegate {
Function<Object, BlockHitListener> PREDICATE = a -> a instanceof BlockHitListener ? (BlockHitListener)a : null;
/** /**
* Called once the projectile lands either hitting the ground or an entity. * Called once the projectile lands either hitting the ground or an entity.
*/ */
default void onImpact(MagicProjectileEntity projectile, Entity entity) {} void onImpact(MagicProjectileEntity projectile, BlockHitResult hit);
}
interface EntityHitListener extends ProjectileDelegate {
Function<Object, EntityHitListener> PREDICATE = a -> a instanceof EntityHitListener ? (EntityHitListener)a : null;
/**
* Called once the projectile lands either hitting the ground or an entity.
*/
void onImpact(MagicProjectileEntity projectile, EntityHitResult hit);
}
} }