2020-09-22 15:11:20 +02:00
|
|
|
package com.minelittlepony.unicopia.projectile;
|
2020-01-16 12:35:46 +01:00
|
|
|
|
2022-12-04 23:46:45 +01:00
|
|
|
import java.util.Optional;
|
2021-08-25 00:32:39 +02:00
|
|
|
import java.util.function.Consumer;
|
2022-12-04 23:46:45 +01:00
|
|
|
import java.util.function.Function;
|
2021-08-25 00:32:39 +02:00
|
|
|
|
2021-12-28 17:22:47 +01:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
|
2023-08-28 15:37:36 +02:00
|
|
|
import com.minelittlepony.unicopia.EquinePredicates;
|
2023-09-02 20:59:42 +02:00
|
|
|
import com.minelittlepony.unicopia.Unicopia;
|
2023-08-06 19:29:33 +02:00
|
|
|
import com.minelittlepony.unicopia.WeaklyOwned;
|
2021-12-28 17:22:47 +01:00
|
|
|
import com.minelittlepony.unicopia.entity.EntityReference;
|
2023-09-02 19:34:57 +02:00
|
|
|
import com.minelittlepony.unicopia.entity.mob.UEntities;
|
2021-02-14 21:15:30 +01:00
|
|
|
import com.minelittlepony.unicopia.item.UItems;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
import net.minecraft.entity.EntityType;
|
2024-05-28 15:32:22 +02:00
|
|
|
import net.minecraft.entity.FallingBlockEntity;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.entity.LivingEntity;
|
|
|
|
import net.minecraft.entity.data.DataTracker;
|
|
|
|
import net.minecraft.entity.data.TrackedData;
|
|
|
|
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
2020-06-26 11:44:47 +02:00
|
|
|
import net.minecraft.entity.projectile.thrown.ThrownItemEntity;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.item.Item;
|
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
import net.minecraft.item.Items;
|
2021-08-04 15:38:03 +02:00
|
|
|
import net.minecraft.nbt.NbtCompound;
|
2023-09-04 12:56:08 +02:00
|
|
|
import net.minecraft.nbt.NbtElement;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.particle.ItemStackParticleEffect;
|
|
|
|
import net.minecraft.particle.ParticleEffect;
|
|
|
|
import net.minecraft.particle.ParticleTypes;
|
|
|
|
import net.minecraft.util.hit.BlockHitResult;
|
|
|
|
import net.minecraft.util.hit.EntityHitResult;
|
|
|
|
import net.minecraft.util.hit.HitResult;
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A generalised version of Mojang's projectile entity class with added support for a custom appearance and water phobia.
|
|
|
|
*/
|
2024-03-03 15:07:36 +01:00
|
|
|
public class MagicProjectileEntity extends ThrownItemEntity implements WeaklyOwned.Mutable<LivingEntity> {
|
2020-06-26 11:44:47 +02:00
|
|
|
private static final TrackedData<Float> DAMAGE = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
2020-01-16 12:35:46 +01:00
|
|
|
|
2022-01-06 14:31:33 +01:00
|
|
|
public static final byte PROJECTILE_COLLISSION = 3;
|
|
|
|
|
2021-12-28 17:22:47 +01:00
|
|
|
private final EntityReference<Entity> homingTarget = new EntityReference<>();
|
2023-09-03 20:39:47 +02:00
|
|
|
private EntityReference<LivingEntity> owner;
|
2021-12-28 17:22:47 +01:00
|
|
|
|
2023-09-04 12:56:08 +02:00
|
|
|
private int maxAge = 90;
|
|
|
|
|
2024-03-03 15:07:36 +01:00
|
|
|
public MagicProjectileEntity(EntityType<? extends MagicProjectileEntity> type, World world) {
|
2020-01-16 12:35:46 +01:00
|
|
|
super(type, world);
|
|
|
|
}
|
|
|
|
|
2022-03-27 16:02:14 +02:00
|
|
|
public MagicProjectileEntity(World world) {
|
|
|
|
this(UEntities.THROWN_ITEM, world);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MagicProjectileEntity(World world, LivingEntity thrower) {
|
2021-02-14 16:53:44 +01:00
|
|
|
super(UEntities.THROWN_ITEM, thrower, world);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
2024-03-03 15:07:36 +01:00
|
|
|
protected MagicProjectileEntity(EntityType<? extends MagicProjectileEntity> type, World world, LivingEntity thrower) {
|
|
|
|
super(type, thrower, world);
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
@Override
|
2024-09-26 22:36:35 +02:00
|
|
|
protected void initDataTracker(DataTracker.Builder builder) {
|
|
|
|
super.initDataTracker(builder);
|
|
|
|
builder.add(DAMAGE, 0F);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2024-03-03 15:07:36 +01:00
|
|
|
public World asWorld() {
|
|
|
|
return getWorld();
|
2021-03-06 11:26:54 +01:00
|
|
|
}
|
2020-01-16 12:35:46 +01:00
|
|
|
|
|
|
|
@Override
|
2024-03-03 15:07:36 +01:00
|
|
|
protected Item getDefaultItem() {
|
|
|
|
return Items.AIR;
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2024-05-22 14:58:20 +02:00
|
|
|
public final void setMaster(LivingEntity owner) {
|
2020-10-08 19:22:20 +02:00
|
|
|
setOwner(owner);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
2023-08-06 19:29:33 +02:00
|
|
|
@Override
|
|
|
|
public void setOwner(@Nullable Entity entity) {
|
|
|
|
super.setOwner(entity);
|
|
|
|
if (entity instanceof LivingEntity l) {
|
2024-05-22 14:58:20 +02:00
|
|
|
WeaklyOwned.Mutable.super.setMaster(l);
|
2023-08-06 19:29:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
@Override
|
2022-01-01 21:08:50 +01:00
|
|
|
@Nullable
|
2024-05-22 14:58:20 +02:00
|
|
|
public final Entity getOwner() {
|
2023-08-06 19:29:33 +02:00
|
|
|
return getMaster();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public EntityReference<LivingEntity> getMasterReference() {
|
2023-09-03 20:39:47 +02:00
|
|
|
if (owner == null) {
|
|
|
|
owner = new EntityReference<>();
|
|
|
|
}
|
2023-08-06 19:29:33 +02:00
|
|
|
return owner;
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
2022-12-19 17:27:24 +01:00
|
|
|
public void setHomingTarget(@Nullable Entity target) {
|
|
|
|
homingTarget.set(target);
|
|
|
|
}
|
|
|
|
|
2021-12-12 11:49:30 +01:00
|
|
|
public void addThrowDamage(float damage) {
|
|
|
|
setThrowDamage(getThrowDamage() + damage);
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
public void setThrowDamage(float damage) {
|
|
|
|
getDataTracker().set(DAMAGE, Math.max(0, damage));
|
|
|
|
}
|
|
|
|
|
|
|
|
public float getThrowDamage() {
|
|
|
|
return getDataTracker().get(DAMAGE);
|
|
|
|
}
|
|
|
|
|
2023-09-04 12:56:08 +02:00
|
|
|
public void setMaxAge(int maxAge) {
|
|
|
|
this.maxAge = maxAge;
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
@Override
|
|
|
|
public void tick() {
|
2023-09-04 12:56:08 +02:00
|
|
|
if (maxAge > 0 && !getWorld().isClient() && homingTarget.getOrEmpty(asWorld()).isEmpty() && (getVelocity().length() < 0.1 || age > maxAge)) {
|
|
|
|
discard();
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
super.tick();
|
|
|
|
|
2023-06-03 13:40:54 +02:00
|
|
|
homingTarget.ifPresent(getWorld(), e -> {
|
2021-12-28 17:22:47 +01:00
|
|
|
setNoGravity(true);
|
|
|
|
noClip = true;
|
|
|
|
setVelocity(getVelocity().add(e.getPos().subtract(getPos()).normalize().multiply(0.2)).multiply(0.6, 0.6, 0.6));
|
|
|
|
});
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private ParticleEffect getParticleParameters() {
|
2024-09-26 22:36:35 +02:00
|
|
|
ItemStack stack = getStack();
|
2020-01-16 12:35:46 +01:00
|
|
|
|
|
|
|
if (stack.isEmpty()) {
|
|
|
|
return ParticleTypes.ITEM_SNOWBALL;
|
|
|
|
}
|
|
|
|
|
2021-02-14 21:15:30 +01:00
|
|
|
if (stack.getItem() == UItems.FILLED_JAR) {
|
|
|
|
stack = UItems.EMPTY_JAR.getDefaultStack();
|
|
|
|
}
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
return new ItemStackParticleEffect(ParticleTypes.ITEM, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-05-07 13:15:53 +02:00
|
|
|
public void handleStatus(byte id) {
|
2022-01-06 14:31:33 +01:00
|
|
|
if (id == PROJECTILE_COLLISSION) {
|
2020-01-16 12:35:46 +01:00
|
|
|
ParticleEffect effect = getParticleParameters();
|
|
|
|
|
|
|
|
for(int i = 0; i < 8; i++) {
|
2023-06-03 13:40:54 +02:00
|
|
|
getWorld().addParticle(effect, getX(), getY(), getZ(), 0, 0, 0);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
2022-01-06 14:31:33 +01:00
|
|
|
} else {
|
|
|
|
super.handleStatus(id);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-08-04 15:38:03 +02:00
|
|
|
public void readCustomDataFromNbt(NbtCompound compound) {
|
|
|
|
super.readCustomDataFromNbt(compound);
|
2024-09-28 23:27:46 +02:00
|
|
|
homingTarget.fromNBT(compound.getCompound("homingTarget"), getWorld().getRegistryManager());
|
|
|
|
getMasterReference().fromNBT(compound.getCompound("owner"), getWorld().getRegistryManager());
|
2023-09-04 12:56:08 +02:00
|
|
|
if (compound.contains("maxAge", NbtElement.INT_TYPE)) {
|
|
|
|
maxAge = compound.getInt("maxAge");
|
|
|
|
}
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-08-04 15:38:03 +02:00
|
|
|
public void writeCustomDataToNbt(NbtCompound compound) {
|
|
|
|
super.writeCustomDataToNbt(compound);
|
2024-09-26 22:36:35 +02:00
|
|
|
compound.put("homingTarget", homingTarget.toNBT(getWorld().getRegistryManager()));
|
|
|
|
compound.put("owner", getMasterReference().toNBT(getWorld().getRegistryManager()));
|
2023-09-04 12:56:08 +02:00
|
|
|
compound.putInt("maxAge", maxAge);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onCollision(HitResult result) {
|
2021-08-04 15:38:03 +02:00
|
|
|
if (!isRemoved()) {
|
2020-10-08 19:22:20 +02:00
|
|
|
super.onCollision(result);
|
2020-05-07 13:15:53 +02:00
|
|
|
|
2023-06-03 13:40:54 +02:00
|
|
|
if (!getWorld().isClient()) {
|
|
|
|
getWorld().sendEntityStatus(this, PROJECTILE_COLLISSION);
|
2021-08-25 00:32:39 +02:00
|
|
|
discard();
|
2020-05-07 13:15:53 +02:00
|
|
|
}
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-08 19:22:20 +02:00
|
|
|
@Override
|
|
|
|
protected void onBlockHit(BlockHitResult hit) {
|
2021-08-25 00:32:39 +02:00
|
|
|
super.onBlockHit(hit);
|
2021-02-14 16:53:44 +01:00
|
|
|
|
2022-12-04 23:46:45 +01:00
|
|
|
forEachDelegates(effect -> effect.onImpact(this, hit), ProjectileDelegate.BlockHitListener.PREDICATE);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
|
2020-10-08 19:22:20 +02:00
|
|
|
@Override
|
|
|
|
protected void onEntityHit(EntityHitResult hit) {
|
2020-01-16 12:35:46 +01:00
|
|
|
Entity entity = hit.getEntity();
|
|
|
|
|
2024-05-28 15:32:22 +02:00
|
|
|
if (!(entity instanceof FallingBlockEntity) && EquinePredicates.IS_MAGIC_IMMUNE.test(entity)) {
|
2020-01-16 12:35:46 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entity != null) {
|
2021-08-25 00:32:39 +02:00
|
|
|
float damage = getThrowDamage();
|
|
|
|
|
|
|
|
if (damage > 0) {
|
2023-06-02 21:20:30 +02:00
|
|
|
entity.damage(getDamageSources().thrown(this, getOwner()), getThrowDamage());
|
2021-08-25 00:32:39 +02:00
|
|
|
}
|
|
|
|
|
2022-12-04 23:46:45 +01:00
|
|
|
forEachDelegates(effect -> effect.onImpact(this, hit), ProjectileDelegate.EntityHitListener.PREDICATE);
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
2021-08-25 00:32:39 +02:00
|
|
|
}
|
2021-02-14 16:53:44 +01:00
|
|
|
|
2022-12-04 23:46:45 +01:00
|
|
|
protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
|
2023-09-02 20:59:42 +02:00
|
|
|
try {
|
2024-09-26 22:36:35 +02:00
|
|
|
Optional.ofNullable(predicate.apply(getStack().getItem())).ifPresent(consumer);
|
2023-09-02 20:59:42 +02:00
|
|
|
} catch (Throwable t) {
|
2023-09-03 20:39:47 +02:00
|
|
|
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", getMasterReference(), t);
|
2023-09-02 20:59:42 +02:00
|
|
|
}
|
2020-01-16 12:35:46 +01:00
|
|
|
}
|
|
|
|
}
|