mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-01 03:26:44 +01:00
Separate the magic beam into its own entity
This commit is contained in:
parent
3165f3cd2a
commit
308cb721cd
12 changed files with 220 additions and 203 deletions
|
@ -7,11 +7,7 @@ import java.util.Optional;
|
|||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
|
||||
import com.minelittlepony.unicopia.entity.mob.UEntities;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -43,7 +39,7 @@ public final class ThrowableSpell extends AbstractDelegatingSpell {
|
|||
*
|
||||
* Returns the resulting projectile entity for customization (or null if on the client).
|
||||
*/
|
||||
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster) {
|
||||
public Optional<MagicBeamEntity> throwProjectile(Caster<?> caster) {
|
||||
return throwProjectile(caster, 1);
|
||||
}
|
||||
|
||||
|
@ -52,33 +48,23 @@ public final class ThrowableSpell extends AbstractDelegatingSpell {
|
|||
*
|
||||
* Returns the resulting projectile entity for customization (or null if on the client).
|
||||
*/
|
||||
public Optional<MagicProjectileEntity> throwProjectile(Caster<?> caster, float divergance) {
|
||||
public Optional<MagicBeamEntity> throwProjectile(Caster<?> caster, float divergance) {
|
||||
World world = caster.asWorld();
|
||||
|
||||
Entity entity = caster.asEntity();
|
||||
|
||||
caster.playSound(USounds.SPELL_CAST_SHOOT, 0.7F, 0.4F / (world.random.nextFloat() * 0.4F + 0.8F));
|
||||
|
||||
if (caster.isClient()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Spell s = spell.get().prepareForCast(caster, CastingMethod.STORED);
|
||||
if (s == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(spell.get().prepareForCast(caster, CastingMethod.STORED)).map(s -> {
|
||||
MagicBeamEntity projectile = new MagicBeamEntity(world, caster.asEntity(), divergance, s);
|
||||
|
||||
MagicProjectileEntity projectile = UEntities.MAGIC_BEAM.create(world);
|
||||
projectile.setPosition(entity.getX(), entity.getEyeY() - 0.1F, entity.getZ());
|
||||
projectile.setOwner(entity);
|
||||
projectile.setItem(UItems.GEMSTONE.getDefaultStack(spell.get().getType()));
|
||||
s.apply(projectile);
|
||||
projectile.setVelocity(entity, entity.getPitch(), entity.getYaw(), 0, 1.5F, divergance);
|
||||
projectile.setNoGravity(true);
|
||||
configureProjectile(projectile, caster);
|
||||
world.spawnEntity(projectile);
|
||||
|
||||
return Optional.of(projectile);
|
||||
return projectile;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,7 @@ 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.Trait;
|
||||
import com.minelittlepony.unicopia.mixin.MixinFallingBlockEntity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
||||
|
||||
|
@ -42,15 +43,15 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B
|
|||
|
||||
@Override
|
||||
public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
|
||||
if (!projectile.isClient() && projectile.canModifyAt(hit.getBlockPos())) {
|
||||
createBlockEntity(projectile.getWorld(), hit.getBlockPos(), e -> apply(projectile, e));
|
||||
if (!projectile.isClient() && projectile instanceof MagicBeamEntity source && source.canModifyAt(hit.getBlockPos())) {
|
||||
createBlockEntity(projectile.getWorld(), hit.getBlockPos(), e -> apply(source, e));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImpact(MagicProjectileEntity projectile, EntityHitResult hit) {
|
||||
if (!projectile.isClient()) {
|
||||
apply(projectile, hit.getEntity());
|
||||
if (!projectile.isClient() && projectile instanceof MagicBeamEntity source) {
|
||||
apply(source, hit.getEntity());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
|||
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||
|
@ -55,10 +56,10 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega
|
|||
|
||||
@Override
|
||||
public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
|
||||
if (!projectile.isClient()) {
|
||||
if (!projectile.isClient() && projectile instanceof MagicBeamEntity source) {
|
||||
BlockPos pos = hit.getBlockPos();
|
||||
projectile.getWorld().createExplosion(projectile, pos.getX(), pos.getY(), pos.getZ(), 3, ExplosionSourceType.NONE);
|
||||
toPlaceable().tick(projectile, Situation.BODY);
|
||||
toPlaceable().tick(source, Situation.BODY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.*;
|
|||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
|
||||
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
||||
|
||||
|
@ -48,6 +49,8 @@ public class DispellEvilSpell extends AbstractSpell implements ProjectileDelegat
|
|||
|
||||
@Override
|
||||
public void onImpact(MagicProjectileEntity projectile) {
|
||||
tick(projectile, Situation.GROUND);
|
||||
if (projectile instanceof MagicBeamEntity source) {
|
||||
tick(source, Situation.GROUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,13 +45,11 @@ public class FireBoltSpell extends AbstractSpell implements HomingSpell,
|
|||
@Override
|
||||
public boolean tick(Caster<?> caster, Situation situation) {
|
||||
if (situation == Situation.PROJECTILE) {
|
||||
if (caster instanceof MagicProjectileEntity && getTraits().get(Trait.FOCUS) >= 50) {
|
||||
if (caster instanceof MagicProjectileEntity projectile && getTraits().get(Trait.FOCUS) >= 50) {
|
||||
caster.findAllEntitiesInRange(
|
||||
getTraits().get(Trait.FOCUS) - 49,
|
||||
EntityPredicates.VALID_LIVING_ENTITY.and(TargetSelecter.validTarget(this, caster))
|
||||
).findFirst().ifPresent(target -> {
|
||||
((MagicProjectileEntity)caster).setHomingTarget(target);
|
||||
});
|
||||
).findFirst().ifPresent(target -> projectile.setHomingTarget(target));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
|||
import com.minelittlepony.unicopia.entity.Creature;
|
||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||
import com.minelittlepony.unicopia.entity.Equine;
|
||||
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
||||
import com.minelittlepony.unicopia.util.Weighted;
|
||||
|
@ -231,9 +232,10 @@ public class NecromancySpell extends AbstractAreaEffectSpell implements Projecti
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onImpact(MagicProjectileEntity source, BlockHitResult hit) {
|
||||
|
||||
// source.asWorld().createExplosion(source, hit.getPos().x, hit.getPos().y, hit.getPos().z, 3, ExplosionSourceType.MOB);
|
||||
public void onImpact(MagicProjectileEntity projectile, BlockHitResult hit) {
|
||||
if (!(projectile instanceof MagicBeamEntity source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Shape affectRegion = new Sphere(false, 3);
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package com.minelittlepony.unicopia.client.render.entity;
|
||||
|
||||
import com.minelittlepony.unicopia.client.render.RenderLayers;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
|
||||
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
|
||||
import net.minecraft.client.model.Dilation;
|
||||
import net.minecraft.client.model.ModelData;
|
||||
import net.minecraft.client.model.ModelPart;
|
||||
|
@ -23,7 +22,7 @@ import net.minecraft.util.Identifier;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntity> {
|
||||
public class MagicBeamEntityRenderer extends EntityRenderer<MagicBeamEntity> {
|
||||
private final Model model;
|
||||
|
||||
public MagicBeamEntityRenderer(EntityRendererFactory.Context ctx) {
|
||||
|
@ -32,17 +31,17 @@ public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntit
|
|||
}
|
||||
|
||||
@Override
|
||||
public Identifier getTexture(MagicProjectileEntity entity) {
|
||||
public Identifier getTexture(MagicBeamEntity entity) {
|
||||
return PlayerScreenHandler.BLOCK_ATLAS_TEXTURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBlockLight(MagicProjectileEntity entity, BlockPos pos) {
|
||||
protected int getBlockLight(MagicBeamEntity entity, BlockPos pos) {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MagicProjectileEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) {
|
||||
public void render(MagicBeamEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) {
|
||||
if (entity.age < 2 && dispatcher.camera.getFocusedEntity().squaredDistanceTo(entity) < 8) {
|
||||
return;
|
||||
}
|
||||
|
@ -68,7 +67,7 @@ public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntit
|
|||
super.render(entity, yaw, tickDelta, matrices, vertexConsumers, light);
|
||||
}
|
||||
|
||||
public class Model extends EntityModel<MagicProjectileEntity> {
|
||||
public class Model extends EntityModel<MagicBeamEntity> {
|
||||
|
||||
private final ModelPart part;
|
||||
|
||||
|
@ -89,7 +88,7 @@ public class MagicBeamEntityRenderer extends EntityRenderer<MagicProjectileEntit
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAngles(MagicProjectileEntity entity, float limbAngle, float limbDistance, float customAngle, float headYaw, float headPitch) {
|
||||
public void setAngles(MagicBeamEntity entity, float limbAngle, float limbDistance, float customAngle, float headYaw, float headPitch) {
|
||||
part.pitch = headPitch;
|
||||
part.yaw = headYaw;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.function.Predicate;
|
|||
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour;
|
||||
import com.minelittlepony.unicopia.projectile.MagicBeamEntity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
import com.minelittlepony.unicopia.projectile.PhysicsBodyProjectileEntity;
|
||||
|
||||
|
@ -32,7 +33,7 @@ public interface UEntities {
|
|||
.trackRangeBlocks(100)
|
||||
.trackedUpdateRate(2)
|
||||
.dimensions(EntityDimensions.fixed(0.25F, 0.25F)));
|
||||
EntityType<MagicProjectileEntity> MAGIC_BEAM = register("magic_beam", FabricEntityTypeBuilder.<MagicProjectileEntity>create(SpawnGroup.MISC, MagicProjectileEntity::new)
|
||||
EntityType<MagicBeamEntity> MAGIC_BEAM = register("magic_beam", FabricEntityTypeBuilder.<MagicBeamEntity>create(SpawnGroup.MISC, MagicBeamEntity::new)
|
||||
.trackRangeBlocks(100)
|
||||
.trackedUpdateRate(2)
|
||||
.dimensions(EntityDimensions.fixed(0.25F, 0.25F)));
|
||||
|
|
|
@ -19,7 +19,6 @@ public interface Channel {
|
|||
C2SPacketType<MsgPlayerFlightControlsInput> FLIGHT_CONTROLS_INPUT = SimpleNetworking.clientToServer(Unicopia.id("flight_controls"), MsgPlayerFlightControlsInput::new);
|
||||
|
||||
S2CPacketType<MsgPlayerCapabilities> SERVER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClient(Unicopia.id("player_capabilities"), MsgPlayerCapabilities::new);
|
||||
S2CPacketType<MsgSpawnProjectile> SERVER_SPAWN_PROJECTILE = SimpleNetworking.serverToClient(Unicopia.id("projectile_entity"), MsgSpawnProjectile::new);
|
||||
S2CPacketType<MsgBlockDestruction> SERVER_BLOCK_DESTRUCTION = SimpleNetworking.serverToClient(Unicopia.id("block_destruction"), MsgBlockDestruction::new);
|
||||
S2CPacketType<MsgCancelPlayerAbility> CANCEL_PLAYER_ABILITY = SimpleNetworking.serverToClient(Unicopia.id("player_ability_cancel"), MsgCancelPlayerAbility::read);
|
||||
S2CPacketType<MsgCasterLookRequest> SERVER_REQUEST_PLAYER_LOOK = SimpleNetworking.serverToClient(Unicopia.id("request_player_look"), MsgCasterLookRequest::new);
|
||||
|
|
|
@ -2,8 +2,6 @@ package com.minelittlepony.unicopia.network.handler;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.minelittlepony.unicopia.InteractionManager;
|
||||
import com.minelittlepony.unicopia.Owned;
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.ability.data.Rot;
|
||||
import com.minelittlepony.unicopia.ability.data.tree.TreeTypes;
|
||||
|
@ -16,14 +14,11 @@ import com.minelittlepony.unicopia.client.gui.TribeSelectionScreen;
|
|||
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
|
||||
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Chapter;
|
||||
import com.minelittlepony.unicopia.diet.PonyDiets;
|
||||
import com.minelittlepony.unicopia.entity.mob.UEntities;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.network.*;
|
||||
import com.minelittlepony.unicopia.network.MsgCasterLookRequest.Reply;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
|
@ -32,7 +27,6 @@ public class ClientNetworkHandlerImpl {
|
|||
|
||||
public ClientNetworkHandlerImpl() {
|
||||
Channel.SERVER_SELECT_TRIBE.receiver().addPersistentListener(this::handleTribeScreen);
|
||||
Channel.SERVER_SPAWN_PROJECTILE.receiver().addPersistentListener(this::handleSpawnProjectile);
|
||||
Channel.SERVER_BLOCK_DESTRUCTION.receiver().addPersistentListener(this::handleBlockDestruction);
|
||||
Channel.CANCEL_PLAYER_ABILITY.receiver().addPersistentListener(this::handleCancelAbility);
|
||||
Channel.UNLOCK_TRAITS.receiver().addPersistentListener(this::handleUnlockTraits);
|
||||
|
@ -47,30 +41,6 @@ public class ClientNetworkHandlerImpl {
|
|||
client.setScreen(new TribeSelectionScreen(packet.availableRaces(), packet.serverMessage()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleSpawnProjectile(PlayerEntity sender, MsgSpawnProjectile packet) {
|
||||
ClientWorld world = client.world;
|
||||
Entity entity = packet.getEntityType().create(world);
|
||||
|
||||
entity.updateTrackedPosition(packet.getX(), packet.getY(), packet.getZ());
|
||||
entity.refreshPositionAfterTeleport(packet.getX(), packet.getY(), packet.getZ());
|
||||
entity.setVelocity(packet.getVelocityX(), packet.getVelocityY(), packet.getVelocityZ());
|
||||
entity.setPitch(packet.getPitch() * 360 / 256F);
|
||||
entity.setYaw(packet.getYaw() * 360 / 256F);
|
||||
entity.setId(packet.getId());
|
||||
entity.setUuid(packet.getUuid());
|
||||
|
||||
if (entity instanceof Owned.Mutable) {
|
||||
((Owned.Mutable<Entity>) entity).setMaster(world.getEntityById(packet.getEntityData()));
|
||||
}
|
||||
|
||||
if (entity.getType() == UEntities.MAGIC_BEAM) {
|
||||
InteractionManager.instance().playLoopingSound(entity, InteractionManager.SOUND_MAGIC_BEAM, entity.getId());
|
||||
}
|
||||
|
||||
world.addEntity(packet.getId(), entity);
|
||||
}
|
||||
|
||||
private void handleBlockDestruction(PlayerEntity sender, MsgBlockDestruction packet) {
|
||||
ClientBlockDestructionManager destr = ((ClientBlockDestructionManager.Source)client.worldRenderer).getDestructionManager();
|
||||
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
package com.minelittlepony.unicopia.projectile;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.minelittlepony.unicopia.Affinity;
|
||||
import com.minelittlepony.unicopia.InteractionManager;
|
||||
import com.minelittlepony.unicopia.ability.magic.Affine;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.Levelled;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
import com.minelittlepony.unicopia.block.state.StatePredicate;
|
||||
import com.minelittlepony.unicopia.entity.EntityPhysics;
|
||||
import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||
import com.minelittlepony.unicopia.entity.Physics;
|
||||
import com.minelittlepony.unicopia.entity.mob.UEntities;
|
||||
import com.minelittlepony.unicopia.network.datasync.EffectSync;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.data.TrackedData;
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class MagicBeamEntity extends MagicProjectileEntity implements Caster<MagicBeamEntity>, MagicImmune {
|
||||
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
private static final TrackedData<Boolean> HYDROPHOBIC = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(MagicBeamEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
|
||||
|
||||
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
|
||||
|
||||
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, GRAVITY);
|
||||
|
||||
public MagicBeamEntity(EntityType<MagicBeamEntity> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
public MagicBeamEntity(World world, Entity owner, float divergance, Spell spell) {
|
||||
super(UEntities.MAGIC_BEAM, world);
|
||||
setPosition(owner.getX(), owner.getEyeY() - 0.1F, owner.getZ());
|
||||
setOwner(owner);
|
||||
setVelocity(owner, owner.getPitch(), owner.getYaw(), 0, 1.5F, divergance);
|
||||
setNoGravity(true);
|
||||
spell.apply(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataTracker() {
|
||||
super.initDataTracker();
|
||||
getDataTracker().startTracking(GRAVITY, 1F);
|
||||
getDataTracker().startTracking(HYDROPHOBIC, false);
|
||||
getDataTracker().startTracking(EFFECT, new NbtCompound());
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (getOwner() != null) {
|
||||
effectDelegate.tick(Situation.PROJECTILE);
|
||||
}
|
||||
|
||||
|
||||
if (getHydrophobic()) {
|
||||
if (StatePredicate.isFluid(getWorld().getBlockState(getBlockPos()))) {
|
||||
Vec3d vel = getVelocity();
|
||||
|
||||
double velY = vel.y;
|
||||
|
||||
velY *= -1;
|
||||
|
||||
if (!hasNoGravity()) {
|
||||
velY += 0.16;
|
||||
}
|
||||
|
||||
setVelocity(new Vec3d(vel.x, velY, vel.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setHydrophobic() {
|
||||
getDataTracker().set(HYDROPHOBIC, true);
|
||||
}
|
||||
|
||||
public boolean getHydrophobic() {
|
||||
return getDataTracker().get(HYDROPHOBIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MagicBeamEntity asEntity() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelStore getLevel() {
|
||||
return getMasterReference().getTarget().map(target -> target.level()).orElse(Levelled.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelStore getCorruption() {
|
||||
return getMasterReference().getTarget().map(target -> target.corruption()).orElse(Levelled.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Physics getPhysics() {
|
||||
return physics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Affinity getAffinity() {
|
||||
return getSpellSlot().get(true).map(Affine::getAffinity).orElse(Affinity.NEUTRAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellContainer getSpellSlot() {
|
||||
return effectDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtractEnergyCost(double amount) {
|
||||
return Caster.of(getMaster()).filter(c -> c.subtractEnergyCost(amount)).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpawnPacket(EntitySpawnS2CPacket packet) {
|
||||
super.onSpawnPacket(packet);
|
||||
InteractionManager.instance().playLoopingSound(this, InteractionManager.SOUND_MAGIC_BEAM, getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(RemovalReason reason) {
|
||||
super.remove(reason);
|
||||
getSpellSlot().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
|
||||
effectDelegate.tick(spell -> {
|
||||
Optional.ofNullable(predicate.apply(spell)).ifPresent(consumer);
|
||||
return Operation.SKIP;
|
||||
});
|
||||
super.forEachDelegates(consumer, predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readCustomDataFromNbt(NbtCompound compound) {
|
||||
super.readCustomDataFromNbt(compound);
|
||||
getDataTracker().set(HYDROPHOBIC, compound.getBoolean("hydrophobic"));
|
||||
physics.fromNBT(compound);
|
||||
if (compound.contains("effect")) {
|
||||
getSpellSlot().put(Spell.readNbt(compound.getCompound("effect")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCustomDataToNbt(NbtCompound compound) {
|
||||
super.writeCustomDataToNbt(compound);
|
||||
compound.putBoolean("hydrophobic", getHydrophobic());
|
||||
physics.toNBT(compound);
|
||||
getSpellSlot().get(true).ifPresent(effect -> {
|
||||
compound.put("effect", Spell.writeNbt(effect));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,28 +6,12 @@ import java.util.function.Function;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.Affinity;
|
||||
import com.minelittlepony.unicopia.EquinePredicates;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.WeaklyOwned;
|
||||
import com.minelittlepony.unicopia.ability.magic.Affine;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.Levelled;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer;
|
||||
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
import com.minelittlepony.unicopia.block.state.StatePredicate;
|
||||
import com.minelittlepony.unicopia.entity.EntityPhysics;
|
||||
import com.minelittlepony.unicopia.entity.EntityReference;
|
||||
import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||
import com.minelittlepony.unicopia.entity.Physics;
|
||||
import com.minelittlepony.unicopia.entity.mob.UEntities;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
import com.minelittlepony.unicopia.network.Channel;
|
||||
import com.minelittlepony.unicopia.network.MsgSpawnProjectile;
|
||||
import com.minelittlepony.unicopia.network.datasync.EffectSync;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
|
@ -40,8 +24,6 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener;
|
||||
import net.minecraft.particle.ItemStackParticleEffect;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
|
@ -49,32 +31,22 @@ import net.minecraft.predicate.entity.EntityPredicates;
|
|||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.EntityHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* A generalised version of Mojang's projectile entity class with added support for a custom appearance and water phobia.
|
||||
*
|
||||
* Can also carry a spell if needed.
|
||||
*/
|
||||
public class MagicProjectileEntity extends ThrownItemEntity implements Caster<MagicProjectileEntity>, WeaklyOwned.Mutable<LivingEntity>, MagicImmune {
|
||||
public class MagicProjectileEntity extends ThrownItemEntity implements WeaklyOwned.Mutable<LivingEntity> {
|
||||
private static final TrackedData<Float> DAMAGE = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
private static final TrackedData<Float> GRAVITY = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
private static final TrackedData<Boolean> HYDROPHOBIC = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(MagicProjectileEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
|
||||
|
||||
public static final byte PROJECTILE_COLLISSION = 3;
|
||||
|
||||
private final EffectSync effectDelegate = new EffectSync(this, EFFECT);
|
||||
|
||||
private final EntityPhysics<MagicProjectileEntity> physics = new EntityPhysics<>(this, GRAVITY);
|
||||
|
||||
private final EntityReference<Entity> homingTarget = new EntityReference<>();
|
||||
private EntityReference<LivingEntity> owner;
|
||||
|
||||
private int maxAge = 90;
|
||||
|
||||
public MagicProjectileEntity(EntityType<MagicProjectileEntity> type, World world) {
|
||||
public MagicProjectileEntity(EntityType<? extends MagicProjectileEntity> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
|
@ -86,27 +58,24 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
super(UEntities.THROWN_ITEM, thrower, world);
|
||||
}
|
||||
|
||||
protected MagicProjectileEntity(EntityType<? extends MagicProjectileEntity> type, World world, LivingEntity thrower) {
|
||||
super(type, thrower, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataTracker() {
|
||||
super.initDataTracker();
|
||||
getDataTracker().startTracking(GRAVITY, 1F);
|
||||
getDataTracker().startTracking(DAMAGE, 0F);
|
||||
getDataTracker().startTracking(EFFECT, new NbtCompound());
|
||||
getDataTracker().startTracking(HYDROPHOBIC, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public World asWorld() {
|
||||
return getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Item getDefaultItem() {
|
||||
switch (getSpellSlot().get(false).map(Spell::getAffinity).orElse(Affinity.NEUTRAL)) {
|
||||
case GOOD: return Items.SNOWBALL;
|
||||
case BAD: return Items.MAGMA_CREAM;
|
||||
default: return Items.AIR;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MagicProjectileEntity asEntity() {
|
||||
return this;
|
||||
return Items.AIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -140,36 +109,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
homingTarget.set(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelStore getLevel() {
|
||||
return getMasterReference().getTarget().map(target -> target.level()).orElse(Levelled.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelStore getCorruption() {
|
||||
return getMasterReference().getTarget().map(target -> target.corruption()).orElse(Levelled.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Physics getPhysics() {
|
||||
return physics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Affinity getAffinity() {
|
||||
return getSpellSlot().get(true).map(Affine::getAffinity).orElse(Affinity.NEUTRAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellContainer getSpellSlot() {
|
||||
return effectDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean subtractEnergyCost(double amount) {
|
||||
return Caster.of(getMaster()).filter(c -> c.subtractEnergyCost(amount)).isPresent();
|
||||
}
|
||||
|
||||
public void addThrowDamage(float damage) {
|
||||
setThrowDamage(getThrowDamage() + damage);
|
||||
}
|
||||
|
@ -182,14 +121,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
return getDataTracker().get(DAMAGE);
|
||||
}
|
||||
|
||||
public void setHydrophobic() {
|
||||
getDataTracker().set(HYDROPHOBIC, true);
|
||||
}
|
||||
|
||||
public boolean getHydrophobic() {
|
||||
return getDataTracker().get(HYDROPHOBIC);
|
||||
}
|
||||
|
||||
public void setMaxAge(int maxAge) {
|
||||
this.maxAge = maxAge;
|
||||
}
|
||||
|
@ -202,28 +133,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
|
||||
super.tick();
|
||||
|
||||
if (getOwner() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
effectDelegate.tick(Situation.PROJECTILE);
|
||||
|
||||
if (getHydrophobic()) {
|
||||
if (StatePredicate.isFluid(getWorld().getBlockState(getBlockPos()))) {
|
||||
Vec3d vel = getVelocity();
|
||||
|
||||
double velY = vel.y;
|
||||
|
||||
velY *= -1;
|
||||
|
||||
if (!hasNoGravity()) {
|
||||
velY += 0.16;
|
||||
}
|
||||
|
||||
setVelocity(new Vec3d(vel.x, velY, vel.z));
|
||||
}
|
||||
}
|
||||
|
||||
homingTarget.ifPresent(getWorld(), e -> {
|
||||
setNoGravity(true);
|
||||
noClip = true;
|
||||
|
@ -261,12 +170,8 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
@Override
|
||||
public void readCustomDataFromNbt(NbtCompound compound) {
|
||||
super.readCustomDataFromNbt(compound);
|
||||
physics.fromNBT(compound);
|
||||
homingTarget.fromNBT(compound.getCompound("homingTarget"));
|
||||
getMasterReference().fromNBT(compound.getCompound("owner"));
|
||||
if (compound.contains("effect")) {
|
||||
getSpellSlot().put(Spell.readNbt(compound.getCompound("effect")));
|
||||
}
|
||||
if (compound.contains("maxAge", NbtElement.INT_TYPE)) {
|
||||
maxAge = compound.getInt("maxAge");
|
||||
}
|
||||
|
@ -275,13 +180,9 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
@Override
|
||||
public void writeCustomDataToNbt(NbtCompound compound) {
|
||||
super.writeCustomDataToNbt(compound);
|
||||
physics.toNBT(compound);
|
||||
compound.put("homingTarget", homingTarget.toNBT());
|
||||
compound.put("owner", getMasterReference().toNBT());
|
||||
compound.putInt("maxAge", maxAge);
|
||||
getSpellSlot().get(true).ifPresent(effect -> {
|
||||
compound.put("effect", Spell.writeNbt(effect));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -296,12 +197,6 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(RemovalReason reason) {
|
||||
super.remove(reason);
|
||||
getSpellSlot().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBlockHit(BlockHitResult hit) {
|
||||
super.onBlockHit(hit);
|
||||
|
@ -329,19 +224,10 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Ma
|
|||
}
|
||||
|
||||
protected <T extends ProjectileDelegate> void forEachDelegates(Consumer<T> consumer, Function<Object, T> predicate) {
|
||||
effectDelegate.tick(spell -> {
|
||||
Optional.ofNullable(predicate.apply(spell)).ifPresent(consumer);
|
||||
return Operation.SKIP;
|
||||
});
|
||||
try {
|
||||
Optional.ofNullable(predicate.apply(getItem().getItem())).ifPresent(consumer);
|
||||
} catch (Throwable t) {
|
||||
Unicopia.LOGGER.error("Error whilst ticking spell on entity {}", getMasterReference(), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<ClientPlayPacketListener> createSpawnPacket() {
|
||||
return Channel.SERVER_SPAWN_PROJECTILE.toPacket(new MsgSpawnProjectile(this));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue