diff --git a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java index be559b38..9f055212 100644 --- a/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java +++ b/src/main/java/com/minelittlepony/unicopia/EquinePredicates.java @@ -33,7 +33,7 @@ public interface EquinePredicates { Predicate IS_CASTER = e -> !e.isRemoved() && (e instanceof Caster || IS_PLAYER.test(e)); Predicate IS_PLACED_SPELL = e -> e instanceof Caster && !e.isRemoved(); - Predicate IS_MAGIC_IMMUNE = e -> (e instanceof MagicImmune || !(e instanceof LivingEntity)) && !(e instanceof ItemEntity); + Predicate IS_MAGIC_IMMUNE = e -> (e instanceof MagicImmune || !(e instanceof LivingEntity)) && !(e instanceof ItemEntity) && !(e instanceof ExperienceOrbEntity); Predicate EXCEPT_MAGIC_IMMUNE = IS_MAGIC_IMMUNE.negate(); Predicate VALID_LIVING_AND_NOT_MAGIC_IMMUNE = EntityPredicates.VALID_LIVING_ENTITY.and(EXCEPT_MAGIC_IMMUNE); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java index e3736e59..bba345b4 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/PlaceableSpell.java @@ -13,10 +13,6 @@ 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.particle.OrientedBillboardParticleEffect; -import com.minelittlepony.unicopia.particle.ParticleHandle; -import com.minelittlepony.unicopia.particle.UParticles; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.NbtSerialisable; @@ -24,6 +20,7 @@ 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; @@ -40,11 +37,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Nullable private RegistryKey dimension; - /** - * The visual effect - */ - private final ParticleHandle particlEffect = new ParticleHandle(); - /** * ID of the placed counterpart of this spell. */ @@ -64,6 +56,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS public float pitch; public float yaw; + private int prevAge; + private int age; + private Optional position = Optional.empty(); public PlaceableSpell(CustomisedSpellType type) { @@ -75,15 +70,13 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS return this; } - @Override - public Collection getDelegates() { - return List.of(spell); + public float getAge(float tickDelta) { + return MathHelper.lerp(tickDelta, prevAge, age); } @Override - public void setDead() { - super.setDead(); - particlEffect.destroy(); + public Collection getDelegates() { + return List.of(spell); } @Override @@ -115,14 +108,11 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS } } - if (spell instanceof PlacementDelegate delegate) { - delegate.updatePlacement(source, this); + prevAge = age; + if (age < 25) { + age++; } - getParticleEffectAttachment(source).ifPresent(p -> { - p.setAttribute(Attachment.ATTR_COLOR, spell.getType().getColor()); - }); - return super.tick(source, Situation.GROUND); } @@ -200,12 +190,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS return castEntity.getTarget().map(EntityValues::pos); } - public Optional getParticleEffectAttachment(Caster source) { - return particlEffect.update(getUuid(), source, spawner -> { - spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, pitch + 90, yaw), Vec3d.ZERO, Vec3d.ZERO); - }); - } - protected Optional getWorld(Caster source) { return Optional.ofNullable(dimension) .map(dim -> source.asWorld().getServer().getWorld(dim)); @@ -214,11 +198,15 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); + 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 (dimension != null) { compound.putString("dimension", dimension.getValue().toString()); } @@ -229,9 +217,11 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); + age = compound.getInt("age"); 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) { @@ -260,9 +250,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS } public interface PlacementDelegate { - void onPlaced(Caster source, PlaceableSpell parent, CastSpellEntity entity); - - void updatePlacement(Caster source, PlaceableSpell parent); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java index 4bf0d726..d7b7b562 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java @@ -54,7 +54,7 @@ public class RainboomAbilitySpell extends AbstractSpell { }); if (source.isClient()) { - // source.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO); + //source.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO); } source.findAllEntitiesInRange(RADIUS).forEach(e -> { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java index 9e19b8ae..d81e4f39 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/TimedSpell.java @@ -29,7 +29,7 @@ public interface TimedSpell extends Spell { } public float getPercentTimeRemaining(float tickDelta) { - return MathHelper.lerp(tickDelta, prevDuration, duration) / maxDuration; + return MathHelper.lerp(tickDelta, prevDuration, duration) / (float)maxDuration; } public int getTicksRemaining() { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index 669411a1..9af5cddb 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -7,7 +7,6 @@ import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; -import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; @@ -16,6 +15,7 @@ import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; import net.minecraft.entity.ItemEntity; import net.minecraft.nbt.NbtCompound; +import net.minecraft.particle.ParticleTypes; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -44,9 +44,10 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp if (timer.getTicksRemaining() <= 0) { return false; } + + setDirty(); } - setDirty(); target.getOrEmpty(caster.asWorld()) .filter(entity -> entity.distanceTo(caster.asEntity()) > getDrawDropOffRange(caster)) .ifPresent(entity -> { @@ -59,12 +60,13 @@ public class AttractiveSpell extends ShieldSpell implements HomingSpell, TimedSp @Override public void generateParticles(Caster source) { - double range = getDrawDropOffRange(source) + 10; + double range = getDrawDropOffRange(source); + Vec3d origin = getOrigin(source); - source.spawnParticles(getOrigin(source), new Sphere(false, range), 7, p -> { + source.spawnParticles(origin, new Sphere(false, range), 7, p -> { source.addParticle( - new FollowingParticleEffect(UParticles.HEALTH_DRAIN, source.asEntity(), 0.4F) - .withChild(new MagicParticleEffect(getType().getColor())), + new FollowingParticleEffect(UParticles.HEALTH_DRAIN, origin, 0.4F) + .withChild(ParticleTypes.AMBIENT_ENTITY_EFFECT), p, Vec3d.ZERO ); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java index 4a9dc915..db9f7d5e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/BubbleSpell.java @@ -11,12 +11,10 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.particle.ParticleHandle; -import com.minelittlepony.unicopia.particle.SphereParticleEffect; import com.minelittlepony.unicopia.particle.UParticles; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; +import com.minelittlepony.unicopia.util.shape.Sphere; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -48,11 +46,11 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, .with(Trait.POWER, 1) .build(); - protected final ParticleHandle particlEffect = new ParticleHandle(); - private final Timer timer; private int struggles; + + private float prevRadius; private float radius; protected BubbleSpell(CustomisedSpellType type) { @@ -66,6 +64,10 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, return timer; } + public float getRadius(float tickDelta) { + return MathHelper.lerp(tickDelta, prevRadius, radius); + } + @Override public boolean apply(Caster source) { @@ -95,14 +97,19 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, public boolean tick(Caster source, Situation situation) { if (situation == Situation.PROJECTILE) { - - source.spawnParticles(ParticleTypes.BUBBLE, 2); + source.spawnParticles(UParticles.BUBBLE, 2); return true; } timer.tick(); - if (timer.getTicksRemaining() <= 0) { + boolean done = timer.getTicksRemaining() <= 0; + + source.spawnParticles(source.getOriginVector().add(0, 1, 0), new Sphere(true, radius * (done ? 0.25F : 0.5F)), done ? 13 : 1, pos -> { + source.addParticle(done ? ParticleTypes.BUBBLE_POP : UParticles.BUBBLE, pos, Vec3d.ZERO); + }); + + if (done) { return false; } @@ -116,7 +123,7 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, source.asEntity().fallDistance = 0; - Vec3d origin = source.getOriginVector(); + prevRadius = radius; if (source instanceof Pony pony && pony.sneakingChanged() && pony.asEntity().isSneaking()) { setDirty(); @@ -128,18 +135,11 @@ public class BubbleSpell extends AbstractSpell implements TimedSpell, } } - particlEffect.update(getUuid(), source, spawner -> { - spawner.addParticle(new SphereParticleEffect(UParticles.SPHERE, 0xFFFFFF, 0.3F, 0, new Vec3d(0, radius / 2F, 0)), origin, Vec3d.ZERO); - }).ifPresent(p -> { - p.setAttribute(Attachment.ATTR_RADIUS, radius); - }); - return !isDead(); } @Override protected void onDestroyed(Caster source) { - particlEffect.destroy(); if (source.asEntity() instanceof LivingEntity l) { MODIFIERS.forEach((attribute, modifier) -> { if (l.getAttributes().hasAttribute(attribute)) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java index 9402d692..7c05d439 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java @@ -10,11 +10,11 @@ import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; +import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; +import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; -import com.minelittlepony.unicopia.particle.SphereParticleEffect; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; @@ -48,7 +48,6 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega private static final Vec3d SPHERE_OFFSET = new Vec3d(0, 2, 0); - private int age = 0; private float accumulatedMass = 0; protected DarkVortexSpell(CustomisedSpellType type) { @@ -80,10 +79,7 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega return true; } - age++; - setDirty(); - - if (age % 20 == 0) { + if (source.asEntity().age % 20 == 0) { source.asWorld().playSound(null, source.getOrigin(), USounds.AMBIENT_DARK_VORTEX_ADDITIONS, SoundCategory.AMBIENT, 1, 1); } @@ -116,21 +112,20 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega public void generateParticles(Caster source) { super.generateParticles(source); - float radius = (float)getEventHorizonRadius(); - - particlEffect.update(getUuid(), source, spawner -> { - spawner.addParticle(new SphereParticleEffect(UParticles.SPHERE, 0x000000, 0.99F, radius, SPHERE_OFFSET), source.getOriginVector(), Vec3d.ZERO); - }).ifPresent(p -> { - p.setAttribute(Attachment.ATTR_RADIUS, radius); - p.setAttribute(Attachment.ATTR_OPACITY, 2F); - }); - particlEffect.update(getUuid(), "_ring", source, spawner -> { - spawner.addParticle(new SphereParticleEffect(UParticles.DISK, 0xAAAAAA, 0.4F, radius + 1, SPHERE_OFFSET), getOrigin(source), Vec3d.ZERO); - }).ifPresent(p -> { - p.setAttribute(Attachment.ATTR_RADIUS, radius * 0F); - }); - - source.spawnParticles(ParticleTypes.SMOKE, 3); + if (getEventHorizonRadius() > 0.3) { + double range = getDrawDropOffRange(source); + Vec3d origin = getOrigin(source); + source.spawnParticles(origin, new Sphere(false, range), 1, p -> { + if (!source.asWorld().isAir(BlockPos.ofFloored(p))) { + source.addParticle( + new FollowingParticleEffect(UParticles.HEALTH_DRAIN, origin, 0.4F) + .withChild(ParticleTypes.CAMPFIRE_SIGNAL_SMOKE), + p, + Vec3d.ZERO + ); + } + }); + } } @Override @@ -162,7 +157,6 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega applyRadialEffect(source, e, e.getPos().distanceTo(origin), radius); }); } - setDirty(); }); } } @@ -180,8 +174,8 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega // 2. max force (at dist 0) is taken from accumulated mass // 3. force reaches 0 at distance of drawDropOffRange - private double getEventHorizonRadius() { - return Math.sqrt(Math.max(0.001, getMass() - 12)); + public double getEventHorizonRadius() { + return Math.sqrt(Math.max(0.001, getMass() / 3F)); } private double getAttractiveForce(Caster source, Entity target) { @@ -189,8 +183,7 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega } private double getMass() { - float pulse = (float)Math.sin(age * 8) / 1F; - return 10 + Math.min(15, Math.min(0.5F + pulse, (float)Math.exp(age) / 8F - 90) + accumulatedMass / 10F) + pulse; + return Math.min(15, 0.1F + accumulatedMass / 10F); } @Override @@ -202,6 +195,11 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega if (distance <= getEventHorizonRadius() + 0.5) { target.setVelocity(target.getVelocity().multiply(distance / (2 * radius))); + if (distance < 1) { + target.setVelocity(target.getVelocity().multiply(distance)); + + } + Living.updateVelocity(target); @Nullable Entity master = source.getMaster(); @@ -221,13 +219,19 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega double massOfTarget = AttractionUtils.getMass(target); - accumulatedMass += massOfTarget; - setDirty(); + if (!source.isClient() && massOfTarget != 0) { + accumulatedMass += massOfTarget; + setDirty(); + } + target.damage(source.damageOf(UDamageTypes.GAVITY_WELL_RECOIL, source), Integer.MAX_VALUE); if (!(target instanceof PlayerEntity)) { target.discard(); source.asWorld().playSound(null, source.getOrigin(), USounds.ENCHANTMENT_CONSUMPTION_CONSUME, SoundCategory.AMBIENT, 2, 0.02F); } + if (target.isAlive()) { + target.damage(source.asEntity().getDamageSources().outOfWorld(), Integer.MAX_VALUE); + } source.subtractEnergyCost(-massOfTarget * 10); source.asWorld().playSound(null, source.getOrigin(), USounds.AMBIENT_DARK_VORTEX_MOOD, SoundCategory.AMBIENT, 2, 0.02F); @@ -243,14 +247,12 @@ public class DarkVortexSpell extends AttractiveSpell implements ProjectileDelega @Override public void toNBT(NbtCompound compound) { super.toNBT(compound); - compound.putInt("age", age); compound.putFloat("accumulatedMass", accumulatedMass); } @Override public void fromNBT(NbtCompound compound) { super.fromNBT(compound); - age = compound.getInt("age"); accumulatedMass = compound.getFloat("accumulatedMass"); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java index 14d3abf8..a58b77de 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DisplacementSpell.java @@ -6,8 +6,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.*; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; -import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; import com.minelittlepony.unicopia.projectile.ProjectileDelegate; @@ -16,7 +14,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.Vec3d; -public class DisplacementSpell extends AbstractSpell implements HomingSpell, PlaceableSpell.PlacementDelegate, ProjectileDelegate.EntityHitListener { +public class DisplacementSpell extends AbstractSpell implements HomingSpell, ProjectileDelegate.EntityHitListener { private final EntityReference target = new EntityReference<>(); @@ -67,19 +65,6 @@ public class DisplacementSpell extends AbstractSpell implements HomingSpell, Pla originator.subtractEnergyCost(destinationPos.distanceTo(sourcePos) / 20F); } - @Override - public void onPlaced(Caster source, PlaceableSpell parent, CastSpellEntity entity) { - - } - - @Override - public void updatePlacement(Caster caster, PlaceableSpell parent) { - parent.getParticleEffectAttachment(caster).ifPresent(attachment -> { - float r = 3 - (1 - ((ticks + 10) / 20F)) * 3; - attachment.setAttribute(Attachment.ATTR_RADIUS, r); - }); - } - private void teleport(Caster source, Entity entity, Vec3d pos, Vec3d vel) { entity.teleport(pos.x, pos.y, pos.z); entity.setVelocity(vel); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java index 8b25fbe9..e55f388c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/PortalSpell.java @@ -14,7 +14,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.EntityReference; import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; import com.minelittlepony.unicopia.particle.*; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; import com.minelittlepony.unicopia.server.world.Ether; import com.minelittlepony.unicopia.util.shape.*; @@ -177,14 +176,6 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme entity.setPos(targetPos.x, caster.getY() + 1.5, targetPos.z); } - @Override - public void updatePlacement(Caster source, PlaceableSpell parent) { - parent.getParticleEffectAttachment(source).ifPresent(attachment -> { - attachment.setAttribute(Attachment.ATTR_RADIUS, 2); - attachment.setAttribute(Attachment.ATTR_OPACITY, 0.92F); - }); - } - @Override protected void onDestroyed(Caster caster) { particleEffect.destroy(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index 71f5cede..023da1c7 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; +import java.util.Optional; + import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.Unicopia; @@ -10,11 +12,9 @@ import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect; -import com.minelittlepony.unicopia.particle.ParticleHandle; -import com.minelittlepony.unicopia.particle.SphereParticleEffect; -import com.minelittlepony.unicopia.particle.UParticles; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; +import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.util.shape.Sphere; @@ -30,6 +30,7 @@ import net.minecraft.entity.passive.PassiveEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity; import net.minecraft.entity.vehicle.BoatEntity; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class ShieldSpell extends AbstractSpell { @@ -40,10 +41,14 @@ public class ShieldSpell extends AbstractSpell { .with(Trait.AIR, 9) .build(); - protected final ParticleHandle particlEffect = new ParticleHandle(); - private final TargetSelecter targetSelecter = new TargetSelecter(this); + private float prevRadius; + private float radius; + + private float rangeMultiplier; + private float targetRangeMultiplier; + protected ShieldSpell(CustomisedSpellType type) { super(type); } @@ -53,33 +58,27 @@ public class ShieldSpell extends AbstractSpell { return method == CastingMethod.STAFF || getTraits().get(Trait.GENEROSITY) > 0 ? toPlaceable() : this; } - @Override - protected void onDestroyed(Caster caster) { - particlEffect.destroy(); - } - @Override public Affinity getAffinity() { return getTraits().get(Trait.DARKNESS) > 0 ? Affinity.BAD : Affinity.GOOD; } protected void generateParticles(Caster source) { - float radius = (float)getDrawDropOffRange(source); Vec3d origin = getOrigin(source); source.spawnParticles(origin, new Sphere(true, radius), (int)(radius * 6), pos -> { source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO); - }); - particlEffect.update(getUuid(), source, spawner -> { - spawner.addParticle(new SphereParticleEffect(UParticles.SPHERE, getType().getColor(), 0.3F, radius), origin, Vec3d.ZERO); - }).ifPresent(p -> { - p.setAttribute(Attachment.ATTR_RADIUS, radius); + if (source.asWorld().random.nextInt(10) == 0 && source.asWorld().random.nextFloat() < source.getCorruption().getScaled(1)) { + ParticleUtils.spawnParticle(source.asWorld(), new LightningBoltParticleEffect(true, 3, 2, 0.1F, Optional.empty()), pos, Vec3d.ZERO); + } }); } @Override public boolean tick(Caster source, Situation situation) { + prevRadius = radius; + radius = (float)getDrawDropOffRange(source); if (source.isClient()) { generateParticles(source); @@ -108,20 +107,32 @@ public class ShieldSpell extends AbstractSpell { cost *= costMultiplier / ((1 + source.getLevel().get()) * 3F); cost /= knowledge; - cost += getDrawDropOffRange(source) / 10F; + cost += radius / 10F; if (!source.subtractEnergyCost(cost)) { setDead(); } } + public float getRadius(float tickDelta) { + return MathHelper.lerp(tickDelta, prevRadius, radius); + } + /** * Calculates the maximum radius of the shield. aka The area of effect. */ public double getDrawDropOffRange(Caster source) { - float multiplier = source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2; + targetRangeMultiplier = source instanceof Pony pony && pony.asEntity().isSneaking() ? 1 : 2; + if (rangeMultiplier < targetRangeMultiplier - 0.1F) { + rangeMultiplier += 0.1F; + } else if (rangeMultiplier > targetRangeMultiplier + 0.1) { + rangeMultiplier -= 0.1F; + } else { + rangeMultiplier = targetRangeMultiplier; + } + float min = (source instanceof Pony ? 4 : 6) + getTraits().get(Trait.POWER); - double range = (min + (source.getLevel().getScaled(source instanceof Pony ? 4 : 40) * (source instanceof Pony ? 2 : 10))) / multiplier; + double range = (min + (source.getLevel().getScaled(source instanceof Pony ? 4 : 40) * (source instanceof Pony ? 2 : 10))) / rangeMultiplier; return range; } @@ -150,7 +161,7 @@ public class ShieldSpell extends AbstractSpell { } protected long applyEntities(Caster source) { - double radius = getDrawDropOffRange(source); + double radius = this.radius; Vec3d origin = getOrigin(source); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java index b2482157..d1730e78 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java @@ -10,7 +10,6 @@ import java.util.stream.Stream; import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.ability.magic.Affine; import com.minelittlepony.unicopia.ability.magic.Caster; -import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.item.FriendshipBraceletItem; @@ -29,7 +28,7 @@ public class TargetSelecter { public Stream getEntities(Caster source, double radius, BiPredicate, Entity> filter) { targets.values().removeIf(Target::tick); return source.findAllEntitiesInRange(radius) - .filter(entity -> entity.isAlive() && !entity.isRemoved() && notOwnerOrFriend(spell, source, entity) && !SpellPredicate.IS_SHIELD_LIKE.isOn(entity)) + .filter(entity -> entity.isAlive() && !entity.isRemoved() && notOwnerOrFriend(spell, source, entity)) .filter(EquinePredicates.EXCEPT_MAGIC_IMMUNE) .filter(e -> filter.test(source, e)) .map(i -> { @@ -57,6 +56,11 @@ public class TargetSelecter { public static boolean isOwnerOrFriend(Affine affine, Caster source, Entity target) { Entity owner = source.getMaster(); + var equine = Pony.of(target); + if (equine.isPresent() && !affine.isFriendlyTogether(equine.get())) { + return false; + } + if (affine.isEnemy(source)) { return FriendshipBraceletItem.isComrade(source, target); } diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index 98046073..1d91a1d5 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.block.cloud.CloudChestBlock; import com.minelittlepony.unicopia.client.particle.ChangelingMagicParticle; import com.minelittlepony.unicopia.client.particle.CloudsEscapingParticle; import com.minelittlepony.unicopia.client.particle.DiskParticle; +import com.minelittlepony.unicopia.client.particle.FloatingBubbleParticle; import com.minelittlepony.unicopia.client.particle.GroundPoundParticle; import com.minelittlepony.unicopia.client.particle.HealthDrainParticle; import com.minelittlepony.unicopia.client.particle.LightningBoltParticle; @@ -65,6 +66,7 @@ public interface URenderers { static void bootstrap() { ParticleFactoryRegistry.getInstance().register(UParticles.UNICORN_MAGIC, createFactory(MagicParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.CHANGELING_MAGIC, createFactory(ChangelingMagicParticle::new)); + ParticleFactoryRegistry.getInstance().register(UParticles.BUBBLE, createFactory(FloatingBubbleParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create)); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java index 8cde15c2..c731c559 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java +++ b/src/main/java/com/minelittlepony/unicopia/client/gui/UHud.java @@ -7,6 +7,8 @@ import com.minelittlepony.unicopia.*; import com.minelittlepony.unicopia.ability.*; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.client.render.RenderLayers; +import com.minelittlepony.unicopia.client.render.spell.DarkVortexSpellRenderer; import com.minelittlepony.unicopia.client.sound.*; import com.minelittlepony.unicopia.entity.ItemTracker; import com.minelittlepony.unicopia.entity.effect.EffectUtils; @@ -193,6 +195,19 @@ public class UHud { protected void renderViewEffects(Pony pony, DrawContext context, int scaledWidth, int scaledHeight, float tickDelta) { + float vortexDistortion = DarkVortexSpellRenderer.getCameraDistortion(); + + if (vortexDistortion > 20) { + context.fill(RenderLayers.getEndPortal(), 0, 0, scaledWidth, scaledHeight, 0); + context.getMatrices().push(); + context.getMatrices().translate(scaledWidth / 2, scaledHeight / 2, 0); + DrawableUtil.drawArc(context.getMatrices(), 0, 20, 0, MathHelper.TAU, 0x000000FF, false); + context.getMatrices().pop(); + return; + } else if (vortexDistortion > 0) { + context.fill(0, 0, scaledWidth, scaledHeight, (int)((vortexDistortion / 20F) * 255) << 24); + } + boolean hasEffect = client.player.hasStatusEffect(UEffects.SUN_BLINDNESS); ItemStack glasses = GlassesItem.getForEntity(client.player); diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/CloudsEscapingParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/CloudsEscapingParticle.java index 50792cfe..32ff15f7 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/CloudsEscapingParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/CloudsEscapingParticle.java @@ -30,7 +30,7 @@ public class CloudsEscapingParticle extends GroundPoundParticle { ); double columnHeight = 1 + age / 30; - new Sphere(true, columnHeight, 1, 1, 1) + new Sphere(true, columnHeight) .translate(center) .randomPoints(random) .forEach(point -> { diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/FloatingBubbleParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/FloatingBubbleParticle.java new file mode 100644 index 00000000..68d51be7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/FloatingBubbleParticle.java @@ -0,0 +1,31 @@ +package com.minelittlepony.unicopia.client.particle; + +import net.minecraft.client.particle.ParticleTextureSheet; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.particle.SpriteProvider; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; + +public class FloatingBubbleParticle extends SpriteBillboardParticle { + public FloatingBubbleParticle(ParticleEffect effect, SpriteProvider provider, ClientWorld clientWorld, double x, double y, double z, double dX, double dY, double dZ) { + super(clientWorld, x, y, z, dX, dY, dZ); + setSprite(provider); + scale((float)clientWorld.random.nextTriangular(1F, 0.5F)); + this.velocityX *= -0.1F; + this.velocityY *= -0.1F; + this.velocityZ *= -0.1F; + this.maxAge *= 3; + } + + @Override + public ParticleTextureSheet getType() { + return ParticleTextureSheet.PARTICLE_SHEET_OPAQUE; + } + + @Override + public void markDead() { + super.markDead(); + world.addParticle(ParticleTypes.BUBBLE_POP, x, y, z, 0, 0, 0); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/OrientedBillboardParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/OrientedBillboardParticle.java index f3f04b23..4c25b465 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/OrientedBillboardParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/OrientedBillboardParticle.java @@ -22,7 +22,6 @@ public abstract class OrientedBillboardParticle extends AbstractBillboardParticl fixed = effect.fixed(); if (fixed) { - // Was hamiltonianProduct (CHECK THIS!!) rotation.mul(RotationAxis.POSITIVE_Y.rotationDegrees(effect.pitch())); rotation.mul(RotationAxis.POSITIVE_X.rotationDegrees(180 - effect.yaw())); } diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java index 58a8d453..87ee30c2 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java @@ -20,6 +20,7 @@ import net.minecraft.entity.Entity; import net.minecraft.util.Identifier; import net.minecraft.util.math.*; +@Deprecated public class RunesParticle extends OrientedBillboardParticle implements Attachment { private static final Identifier[] TEXTURES = new Identifier[] { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java index 5ef86cf0..857e4c96 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.client.FirstPersonRendererOverrides.ArmRenderer; +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; import com.minelittlepony.unicopia.client.render.spell.SpellEffectsRenderDispatcher; import net.minecraft.client.MinecraftClient; @@ -13,14 +14,14 @@ import net.minecraft.client.model.ModelPart; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.feature.FeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRendererContext; -import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.LivingEntity; import net.minecraft.util.Arm; public class AccessoryFeatureRenderer< T extends LivingEntity, - M extends BipedEntityModel> extends FeatureRenderer { + M extends EntityModel> extends FeatureRenderer { private static final List> REGISTRY = new ArrayList<>(); @@ -40,6 +41,10 @@ public class AccessoryFeatureRenderer< @Override public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + if (MineLPDelegate.getInstance().getRace(entity).isEquine()) { + return; + } + features.forEach(feature -> feature.render(matrices, vertexConsumers, light, entity, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch)); Caster.of(entity).ifPresent(caster -> { @@ -60,7 +65,7 @@ public class AccessoryFeatureRenderer< } public interface FeatureFactory { - Feature create(FeatureRendererContext> context); + Feature create(FeatureRendererContext> context); } public interface Feature { @@ -75,11 +80,11 @@ public class AccessoryFeatureRenderer< public interface FeatureRoot< T extends LivingEntity, - M extends BipedEntityModel> { + M extends EntityModel> { AccessoryFeatureRenderer getAccessories(); @SuppressWarnings("unchecked") @Nullable - static > FeatureRoot of(T entity) { + static > FeatureRoot of(T entity) { var renderer = MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity); if (renderer instanceof FeatureRoot) { return (FeatureRoot)renderer; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/RenderLayers.java b/src/main/java/com/minelittlepony/unicopia/client/render/RenderLayers.java index 80eeefd4..45a3ae35 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/RenderLayers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/RenderLayers.java @@ -39,6 +39,15 @@ public final class RenderLayers extends RenderLayer { .target(TRANSLUCENT_TARGET) .build(false)); + private static final RenderLayer MAGIC_SHIELD = of("magic_shield", VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, + VertexFormat.DrawMode.QUADS, 256, true, true, MultiPhaseParameters.builder() + .program(COLOR_PROGRAM) + .transparency(TRANSLUCENT_TRANSPARENCY) + .target(TRANSLUCENT_TARGET) + .cull(DISABLE_CULLING) + .writeMaskState(COLOR_MASK) + .build(false)); + private static final Function MAGIC_COLORIN_FUNC = Util.memoize(color -> { return of("magic_colored_" + color, VertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, @@ -75,6 +84,10 @@ public final class RenderLayers extends RenderLayer { return MAGIC_NO_COLOR; } + public static RenderLayer getMagicShield() { + return MAGIC_SHIELD; + } + public static RenderLayer getMagicColored() { return MAGIC_COLORED; } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java b/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java index a126ee28..fc981555 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/RenderUtil.java @@ -1,6 +1,5 @@ package com.minelittlepony.unicopia.client.render; -import org.joml.Matrix4f; import org.joml.Vector3f; import org.joml.Vector4f; @@ -11,7 +10,7 @@ import net.minecraft.client.render.VertexFormats; import net.minecraft.client.util.math.MatrixStack; public class RenderUtil { - private static final Vector4f TEMP_VECTOR = new Vector4f(); + public static final Vector4f TEMP_VECTOR = new Vector4f(); public static final Vertex[] UNIT_FACE = new Vertex[] { new Vertex(new Vector3f(0, 0, 0), 1, 1), new Vertex(new Vector3f(0, 1, 0), 1, 0), @@ -21,21 +20,18 @@ public class RenderUtil { public static void renderFace(MatrixStack matrices, Tessellator te, BufferBuilder buffer, float r, float g, float b, float a, int light) { buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); - - Vertex[] UNIT_FACE = new Vertex[] { - new Vertex(new Vector3f(0, 0, 0), 1, 1), - new Vertex(new Vector3f(0, 1, 0), 1, 0), - new Vertex(new Vector3f(1, 1, 0), 0, 0), - new Vertex(new Vector3f(1, 0, 0), 0, 1) - }; - - Matrix4f transformation = matrices.peek().getPositionMatrix(); for (Vertex vertex : UNIT_FACE) { - transformation.transform(TEMP_VECTOR.set(vertex.position(), 1)); - buffer.vertex(TEMP_VECTOR.x, TEMP_VECTOR.y, TEMP_VECTOR.z).texture(vertex.u(), vertex.v()).color(r, g, b, a).light(light).next(); + Vector4f position = vertex.position(matrices); + buffer.vertex(position.x, position.y, position.z).texture(vertex.u(), vertex.v()).color(r, g, b, a).light(light).next(); } te.draw(); } - record Vertex(Vector3f position, float u, float v) {} + public record Vertex(Vector3f position, float u, float v) { + + public Vector4f position(MatrixStack matrices) { + matrices.peek().getPositionMatrix().transform(TEMP_VECTOR.set(position, 1)); + return TEMP_VECTOR; + } + } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java index 7b4fae4e..ece6638b 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/CastSpellEntityRenderer.java @@ -11,8 +11,6 @@ import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.util.Identifier; public class CastSpellEntityRenderer extends EntityRenderer { - private final SpellEffectsRenderDispatcher spellRenderDispatcher = new SpellEffectsRenderDispatcher(); - public CastSpellEntityRenderer(EntityRendererFactory.Context ctx) { super(ctx); } @@ -24,7 +22,7 @@ public class CastSpellEntityRenderer extends EntityRenderer { @Override public void render(CastSpellEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) { - spellRenderDispatcher.render(matrices, vertexConsumers, light, entity, 0, 0, tickDelta, getAnimationProgress(entity, tickDelta), yaw, 0); + SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertexConsumers, light, entity, 0, 0, tickDelta, getAnimationProgress(entity, tickDelta), yaw, 0); } protected float getAnimationProgress(CastSpellEntity entity, float tickDelta) { diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java index f868ff04..694571c3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/model/BakedModel.java @@ -3,38 +3,37 @@ package com.minelittlepony.unicopia.client.render.model; import java.util.ArrayList; import java.util.List; -import org.joml.Matrix4f; +import org.joml.Vector3f; import org.joml.Vector4f; +import com.minelittlepony.unicopia.client.render.RenderUtil; + import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.util.math.MatrixStack; public class BakedModel { - private static final Vector4f drawVert = new Vector4f(); - - protected final List vertices = new ArrayList<>(); + protected final List vertices = new ArrayList<>(); protected void addVertex(Vector4f vertex) { addVertex(vertex.x, vertex.y, vertex.z, 0, 0); } protected void addVertex(float x, float y, float z, float u, float v) { - vertices.add(new Vertex(x, y, z, u, v)); + vertices.add(new RenderUtil.Vertex(new Vector3f(x, y, z), u, v)); } - public final void render(MatrixStack matrices, VertexConsumer vertexWriter, int light, int overlay, float scale, float r, float g, float b, float a) { + public final void render(MatrixStack matrices, VertexConsumer buffer, int light, int overlay, float scale, float r, float g, float b, float a) { scale = Math.abs(scale); if (scale < 0.001F) { return; } - Matrix4f model = matrices.peek().getPositionMatrix(); - for (Vertex vertex : vertices) { - drawVert.set(vertex.x() * scale, vertex.y() * scale, vertex.z() * scale, 1); - drawVert.mul(model); - vertexWriter.vertex(drawVert.x, drawVert.y, drawVert.z, r, g, b, a, vertex.u(), vertex.v(), overlay, light, 0, 0, 0); + matrices.push(); + matrices.scale(scale, scale, scale); + for (RenderUtil.Vertex vertex : vertices) { + Vector4f pos = vertex.position(matrices); + buffer.vertex(pos.x, pos.y, pos.z, r, g, b, a, vertex.u(), vertex.v(), overlay, light, 0, 0, 0); } + matrices.pop(); } - - record Vertex(float x, float y, float z, float u, float v) {} } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/model/PlaneModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/model/PlaneModel.java new file mode 100644 index 00000000..bfbcfc24 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/model/PlaneModel.java @@ -0,0 +1,12 @@ +package com.minelittlepony.unicopia.client.render.model; + +public class PlaneModel extends BakedModel { + public static final PlaneModel INSTANCE = new PlaneModel(); + + private PlaneModel() { + addVertex(-1, -1, 0, 0, 0); + addVertex(-1, 1, 0, 1, 0); + addVertex( 1, 1, 0, 1, 1); + addVertex( 1, -1, 0, 0, 1); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java new file mode 100644 index 00000000..d15863b7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/BubbleSpellRenderer.java @@ -0,0 +1,41 @@ +package com.minelittlepony.unicopia.client.render.spell; + +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.BubbleSpell; +import com.minelittlepony.unicopia.client.gui.DrawableUtil; +import com.minelittlepony.unicopia.client.render.RenderLayers; +import com.minelittlepony.unicopia.client.render.model.SphereModel; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.RotationAxis; + +public class BubbleSpellRenderer implements SpellRenderer { + @Override + public void render(MatrixStack matrices, VertexConsumerProvider vertices, BubbleSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + matrices.push(); + double height = caster.asEntity().getEyeY() - caster.getOriginVector().y; + matrices.translate(0, height * 0.5F, 0); + + float radius = spell.getRadius(tickDelta) * 0.7F; + + VertexConsumer buffer = vertices.getBuffer(RenderLayers.getMagicNoColor()); + + Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity(); + + matrices.push(); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-45)); + matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(45 + cameraEntity.getYaw(tickDelta))); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-cameraEntity.getPitch(tickDelta))); + + new SphereModel(40, 40, DrawableUtil.PI * 0.25F).render(matrices, buffer, light, 0, radius - 0.1F, 0.9F, 0.9F, 1, 0.3F); + matrices.pop(); + + SphereModel.SPHERE.render(matrices, buffer, light, 0, radius, 0.9F, 0.9F, 1, 0.25F); + + matrices.pop(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/DarkVortexSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/DarkVortexSpellRenderer.java new file mode 100644 index 00000000..548854ae --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/DarkVortexSpellRenderer.java @@ -0,0 +1,100 @@ +package com.minelittlepony.unicopia.client.render.spell; + +import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.DarkVortexSpell; +import com.minelittlepony.unicopia.client.render.RenderLayers; +import com.minelittlepony.unicopia.client.render.model.PlaneModel; +import com.minelittlepony.unicopia.client.render.model.SphereModel; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RotationAxis; + +public class DarkVortexSpellRenderer implements SpellRenderer { + + private static final Identifier ACCRETION_DISK_TEXTURE = Unicopia.id("textures/spells/dark_vortex/accretion_disk.png"); + + private static float cameraDistortion; + + public static float getCameraDistortion() { + cameraDistortion *= 0.9F; + cameraDistortion = MathHelper.clamp(cameraDistortion, 0, 80); + return cameraDistortion; + } + + @Override + public void render(MatrixStack matrices, VertexConsumerProvider vertices, DarkVortexSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + + + Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity(); + + float radius = (float)spell.getEventHorizonRadius(); + float absDistance = (float)cameraEntity.getEyePos().distanceTo(caster.getOriginVector().add(0, 2, 0)); + + matrices.push(); + matrices.translate(0, 2 + radius, 0); + + SphereModel.SPHERE.render(matrices, vertices.getBuffer(RenderLayers.getSolid()), light, 1, Math.min(radius * 0.6F, absDistance * 0.1F), 0, 0, 0, 1); + + matrices.push(); + + + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(90)); + matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(90 + cameraEntity.getYaw(tickDelta))); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-cameraEntity.getPitch(tickDelta))); + + matrices.scale(0.7F, 1, 1); + + + float distance = 1F / MathHelper.clamp((absDistance / (radius * 4)), 0.0000001F, 1); + distance *= distance; + if (absDistance < radius * 4) { + cameraDistortion += distance; + } + + matrices.scale(distance, distance, distance); + + if (absDistance > radius) { + matrices.push(); + matrices.translate(0, -0.1F, 0); + for (int i = 0; i < 10; i++) { + matrices.scale(1, 1, 0.796F); + float brightness = i / 10F; + SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getMagicNoColor()), light, 1, radius * (1 + (0.25F * i)) * 0.7F, brightness, brightness, brightness, 0.2F); + } + matrices.pop(); + } + + SphereModel.DISK.render(matrices, vertices.getBuffer(RenderLayers.getEndPortal()), light, 1, radius * 0.5F, 1, 0.5F, 0, 1); + + if (radius > 0.3F && absDistance > radius) { + radius *= 3 + radius; + + matrices.scale(radius, radius, radius); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90)); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(animationProgress * 168)); + + VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(ACCRETION_DISK_TEXTURE)); + + PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); + + matrices.push(); + matrices.scale(0.5F, 0.5F, 0.5F); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(33)); + + PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); + matrices.pop(); + + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(45)); + PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, 1, 1, 1, 1); + } + matrices.pop(); + matrices.pop(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java new file mode 100644 index 00000000..4630912b --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/PlacedSpellRenderer.java @@ -0,0 +1,72 @@ +package com.minelittlepony.unicopia.client.render.spell; + +import com.minelittlepony.common.util.Color; +import com.minelittlepony.unicopia.Unicopia; +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; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.RotationAxis; + +public class PlacedSpellRenderer implements SpellRenderer { + private static final Identifier[] TEXTURES = new Identifier[] { + Unicopia.id("textures/particles/runes_0.png"), + Unicopia.id("textures/particles/runes_1.png"), + Unicopia.id("textures/particles/runes_2.png"), + Unicopia.id("textures/particles/runes_3.png"), + Unicopia.id("textures/particles/runes_4.png"), + Unicopia.id("textures/particles/runes_5.png") + }; + + @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)) { + return; + } + + for (Spell delegate : spell.getDelegates()) { + + matrices.push(); + matrices.translate(0, 0.001, 0); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.pitch)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90 - spell.yaw)); + float scale = (spell.getAge(tickDelta) / 25F) * 3; + matrices.scale(scale, scale, scale); + + float angle = (animationProgress / 9F) % 360; + + int color = delegate.getType().getColor(); + + float red = Color.r(color); + float green = Color.g(color); + float blue = Color.b(color); + + for (int i = 0; i < TEXTURES.length; i++) { + VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(TEXTURES[i])); + + for (int dim = 0; dim < 3; dim++) { + float ringSpeed = (i % 2 == 0 ? i : -1) * i; + + matrices.push(); + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim)); + PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, red, green, blue, scale / ((float)(dim * 3) + 1)); + matrices.pop(); + } + } + + matrices.pop(); + + SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertices, delegate, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java new file mode 100644 index 00000000..55844dd9 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/ShieldSpellRenderer.java @@ -0,0 +1,36 @@ +package com.minelittlepony.unicopia.client.render.spell; + +import com.minelittlepony.common.util.Color; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.ShieldSpell; +import com.minelittlepony.unicopia.client.render.RenderLayers; +import com.minelittlepony.unicopia.client.render.model.SphereModel; +import com.minelittlepony.unicopia.util.ColorHelper; + +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.MathHelper; + +public class ShieldSpellRenderer implements SpellRenderer { + @Override + public void render(MatrixStack matrices, VertexConsumerProvider vertices, ShieldSpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + matrices.push(); + double height = caster.asEntity().getEyeY() - caster.getOriginVector().y; + matrices.translate(0, height, 0); + + int color = ColorHelper.lerp(caster.getCorruption().getScaled(1) * (tickDelta / (1 + caster.asWorld().random.nextFloat())), spell.getType().getColor(), 0xFF000); + float[] colors = ColorHelper.changeSaturation(Color.r(color), Color.g(color), Color.b(color), 4); + float radius = 0.35F + spell.getRadius(tickDelta) + MathHelper.sin(animationProgress / 30F) * 0.01F; + + VertexConsumer buffer = vertices.getBuffer(RenderLayers.getMagicShield()); + + float thickness = 0.02F * MathHelper.sin(animationProgress / 30F); + float alpha = 1 - Math.abs(MathHelper.sin(animationProgress / 20F)) * 0.2F; + SphereModel.SPHERE.render(matrices, buffer, light, 1, radius + thickness, colors[0], colors[1], colors[2], alpha * 0.08F); + SphereModel.SPHERE.render(matrices, buffer, light, 1, radius - thickness, colors[0], colors[1], colors[2], alpha * 0.05F); + SphereModel.SPHERE.render(matrices, buffer, light, 1, radius + thickness * 2, colors[0], colors[1], colors[2], alpha * 0.05F); + + matrices.pop(); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index 7f5d26a8..341abe8a 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -8,12 +8,18 @@ import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; +import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; +import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; +import com.minelittlepony.unicopia.client.gui.DrawableUtil; import com.minelittlepony.unicopia.entity.Living; +import com.minelittlepony.unicopia.entity.mob.CastSpellEntity; +import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; +import com.minelittlepony.unicopia.util.ColorHelper; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.minecraft.client.MinecraftClient; @@ -22,6 +28,7 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.registry.Registries; import net.minecraft.resource.ResourceManager; @@ -31,6 +38,7 @@ import net.minecraft.util.Colors; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; import net.minecraft.util.math.Box; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.RotationAxis; import net.minecraft.util.math.Vec3d; @@ -43,10 +51,19 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader REGISTRY.put(type, rendererFactory); } + static { + register(SpellType.PLACED_SPELL, PlacedSpellRenderer::new); + register(SpellType.SHIELD, ShieldSpellRenderer::new); + register(SpellType.DARK_VORTEX, DarkVortexSpellRenderer::new); + register(SpellType.BUBBLE, BubbleSpellRenderer::new); + } + @Nullable private Map, SpellRenderer> renderers = Map.of(); private final MinecraftClient client = MinecraftClient.getInstance(); + private SpellEffectsRenderDispatcher() {} + @Override public Identifier getFabricId() { return ID; @@ -57,12 +74,23 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader return (SpellRenderer)renderers.get(spell.getType()); } + public void render(MatrixStack matrices, VertexConsumerProvider vertices, Spell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + var renderer = getRenderer(spell); + + if (renderer != null) { + client.getBufferBuilders().getEntityVertexConsumers().draw(); + + renderer.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); + + if (EquinePredicates.IS_CASTER.test(client.player)) { + renderGemstone(matrices, vertices, spell, caster, light, tickDelta, animationProgress); + } + } + } + public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, Caster caster, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { caster.getSpellSlot().forEach(spell -> { - var renderer = getRenderer(spell); - if (renderer != null) { - renderer.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); - } + render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch); return Operation.SKIP; }, false); @@ -77,6 +105,38 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader renderers = REGISTRY.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().create())); } + private void renderGemstone(MatrixStack matrices, VertexConsumerProvider vertices, Spell spell, Caster caster, int light, float tickDelta, float animationProgress) { + matrices.push(); + + if (!(caster.asEntity() instanceof MagicProjectileEntity)) { + + float y = -caster.asEntity().getHeight(); + if (caster.asEntity() instanceof CastSpellEntity) { + y = 1F; + } + + matrices.translate(0, y + MathHelper.sin(animationProgress / 3F) * 0.2F, 0); + matrices.push(); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(animationProgress)); + + client.getItemRenderer().renderItem(spell.getType().withTraits(spell.getTraits()).getDefaultStack(), ModelTransformationMode.FIXED, light, 0, matrices, vertices, caster.asWorld(), 0); + matrices.pop(); + + if (spell instanceof TimedSpell timed && spell.getType() != SpellType.DARK_VORTEX) { + matrices.multiply(client.getEntityRenderDispatcher().getRotation().invert()); + float radius = 0.6F; + float timeRemaining = timed.getTimer().getPercentTimeRemaining(tickDelta); + + DrawableUtil.drawArc(matrices, radius, radius + 0.3F, 0, DrawableUtil.TAU * timeRemaining, + ColorHelper.lerp(MathHelper.clamp(timeRemaining * 4, 0, 1), 0xFF0000FF, 0xFFFFFFFF), + false + ); + } + } + + matrices.pop(); + } + private void renderSpellDebugInfo(MatrixStack matrices, VertexConsumerProvider vertices, Caster caster, int light) { matrices.push(); matrices.multiply(client.getEntityRenderDispatcher().getRotation()); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java index df9c7e37..16a4100b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/CastSpellEntity.java @@ -37,6 +37,7 @@ public class CastSpellEntity extends LightEmittingEntity implements Caster type, World world) { super(type, world); + ignoreCameraFrustum = true; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java index 11b71c2e..26c6d4c7 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerCamera.java @@ -5,6 +5,7 @@ import java.util.Optional; import com.minelittlepony.common.util.animation.MotionCompositor; import com.minelittlepony.unicopia.ability.magic.SpellPredicate; import com.minelittlepony.unicopia.ability.magic.spell.AbstractDisguiseSpell; +import com.minelittlepony.unicopia.client.render.spell.DarkVortexSpellRenderer; import net.minecraft.util.math.Vec3d; @@ -62,6 +63,7 @@ public class PlayerCamera extends MotionCompositor { public double calculateFieldOfView(double fov) { fov += player.getMagicalReserves().getExertion().get() / 5F; fov += getEnergyAddition(); + fov += DarkVortexSpellRenderer.getCameraDistortion() * 2.5F; return fov; } diff --git a/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java index 326ddd43..da2018d0 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/FriendshipBraceletItem.java @@ -78,7 +78,7 @@ public class FriendshipBraceletItem extends WearableItem implements DyeableItem, @Override public EquipmentSlot getSlotType(ItemStack stack) { - return isSigned(stack) ? EquipmentSlot.CHEST : super.getSlotType(); + return isSigned(stack) ? EquipmentSlot.CHEST : super.getSlotType(stack); } private boolean checkSignature(ItemStack stack, PlayerEntity player) { diff --git a/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java b/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java index b745b9bb..1b7067da 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/WearableItem.java @@ -49,6 +49,7 @@ public abstract class WearableItem extends Item implements Equipment { return ArmorMaterials.LEATHER.getEquipSound(); } + @Deprecated @Override public final EquipmentSlot getSlotType() { return getSlotType(getDefaultStack()); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java index be01f778..2e6cc68b 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinArmorFeatureRenderer.java @@ -1,19 +1,9 @@ package com.minelittlepony.unicopia.mixin.client; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer; - -import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRenderer; -import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.model.BipedEntityModel; -import net.minecraft.client.render.model.BakedModelManager; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.LivingEntity; @Mixin(ArmorFeatureRenderer.class) @@ -21,13 +11,13 @@ abstract class MixinArmorFeatureRenderer< T extends LivingEntity, M extends BipedEntityModel, A extends BipedEntityModel> - extends FeatureRenderer implements AccessoryFeatureRenderer.FeatureRoot { + extends FeatureRenderer/* implements AccessoryFeatureRenderer.FeatureRoot*/ { - private AccessoryFeatureRenderer accessories; + //private AccessoryFeatureRenderer accessories; MixinArmorFeatureRenderer() { super(null); } - @Override + /*@Override public AccessoryFeatureRenderer getAccessories() { return accessories; } @@ -40,5 +30,5 @@ abstract class MixinArmorFeatureRenderer< @Inject(method = "render", at = @At("RETURN")) private void onRender(MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, T entity, float limbDistance, float limbAngle, float tickDelta, float age, float headYaw, float headPitch, CallbackInfo info) { getAccessories().render(stack, renderContext, lightUv, entity, limbDistance, limbAngle, tickDelta, age, headYaw, headPitch); - } + }*/ } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinLivingEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinLivingEntityRenderer.java index 3e153574..6f915b70 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinLivingEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinLivingEntityRenderer.java @@ -1,17 +1,25 @@ package com.minelittlepony.unicopia.mixin.client; +import java.util.List; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer; import com.minelittlepony.unicopia.client.render.AnimalPoser; import com.minelittlepony.unicopia.client.render.PlayerPoser; +import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer.FeatureRoot; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.render.entity.feature.FeatureRenderer; import net.minecraft.client.render.entity.feature.FeatureRendererContext; import net.minecraft.client.render.entity.model.BipedEntityModel; import net.minecraft.client.render.entity.model.EntityModel; @@ -21,8 +29,31 @@ import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.player.PlayerEntity; @Mixin(LivingEntityRenderer.class) -abstract class MixinLivingEntityRenderer> extends EntityRenderer implements FeatureRendererContext { +abstract class MixinLivingEntityRenderer> extends EntityRenderer + implements FeatureRendererContext, FeatureRoot { + @Shadow + private @Final List> features; + MixinLivingEntityRenderer() { super(null); } + @Nullable + private AccessoryFeatureRenderer accessories; + + @Override + @SuppressWarnings("unchecked") + public AccessoryFeatureRenderer getAccessories() { + if (accessories == null) { + accessories = features.stream() + .filter(a -> a instanceof FeatureRoot) + .map(a -> ((FeatureRoot)a).getAccessories()) + .findFirst() + .orElseGet(() -> { + var feature = new AccessoryFeatureRenderer<>(this); + features.add(feature); + return feature; + }); + } + return accessories; + } @Inject(method = "render", at = @At( @@ -36,6 +67,7 @@ abstract class MixinLivingEntityRenderer)getModel(), PlayerPoser.Context.THIRD_PERSON); } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinPlayerEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinPlayerEntityRenderer.java index 35503ffd..cd1eac71 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinPlayerEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinPlayerEntityRenderer.java @@ -1,13 +1,11 @@ package com.minelittlepony.unicopia.mixin.client; -import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer; import com.minelittlepony.unicopia.client.render.PlayerPoser; import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer.FeatureRoot; @@ -21,31 +19,14 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Arm; @Mixin(PlayerEntityRenderer.class) -abstract class MixinPlayerEntityRenderer - extends LivingEntityRenderer> - implements FeatureRoot> { - @Nullable - private AccessoryFeatureRenderer> accessories; - +abstract class MixinPlayerEntityRenderer extends LivingEntityRenderer> { MixinPlayerEntityRenderer() { super(null, null, 0); } - @Override @SuppressWarnings("unchecked") - public AccessoryFeatureRenderer> getAccessories() { - if (accessories == null) { - accessories = features.stream() - .filter(a -> a instanceof FeatureRoot) - .map(a -> ((FeatureRoot>)a).getAccessories()) - .findFirst() - .orElseGet(() -> new AccessoryFeatureRenderer<>(this)); - } - return accessories; - } - @Inject(method = "renderArm", at = @At("RETURN")) private void onRenderArm(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, AbstractClientPlayerEntity player, ModelPart arm, ModelPart sleeve, CallbackInfo info) { Arm a = this.getModel().leftArm == arm ? Arm.LEFT : Arm.RIGHT; - getAccessories().renderArm(matrices, vertexConsumers, light, player, arm, a); + ((FeatureRoot>)this).getAccessories().renderArm(matrices, vertexConsumers, light, player, arm, a); } @Inject(method = "renderArm", diff --git a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java index f54aebaa..2a4568e9 100644 --- a/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java +++ b/src/main/java/com/minelittlepony/unicopia/network/datasync/EffectSync.java @@ -136,7 +136,7 @@ public class EffectSync implements SpellContainer, NbtSerialisable { @SuppressWarnings("unchecked") private Stream read(@Nullable SpellPredicate type, boolean synchronize, boolean sendUpdate) { if (synchronize && spells.fromNbt(owner.asEntity().getDataTracker().get(param)) && sendUpdate) { - owner.asEntity().getDataTracker().set(param, spells.toNbt()); + write(); } if (type == null) { diff --git a/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java b/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java index 1fc12c06..b099f347 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java @@ -20,6 +20,7 @@ import net.minecraft.world.World; /** * A connection class for updating and persisting an attached particle effect. */ +@Deprecated public class ParticleHandle { private final Map loadedEffects = new WeakHashMap<>(); diff --git a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java index 8d5208f0..f1e88314 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java @@ -12,10 +12,12 @@ public interface UParticles { ParticleType UNICORN_MAGIC = register("unicorn_magic", FabricParticleTypes.complex(MagicParticleEffect.FACTORY)); DefaultParticleType CHANGELING_MAGIC = register("changeling_magic", FabricParticleTypes.simple()); + DefaultParticleType BUBBLE = register("bubble", FabricParticleTypes.simple()); ParticleType RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY)); DefaultParticleType RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.simple()); + @Deprecated ParticleType MAGIC_RUNES = register("magic_runes", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY)); DefaultParticleType RAIN_DROPS = register("rain_drops", FabricParticleTypes.simple()); diff --git a/src/main/java/com/minelittlepony/unicopia/util/shape/Sphere.java b/src/main/java/com/minelittlepony/unicopia/util/shape/Sphere.java index 7ebf61af..c151b47c 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/shape/Sphere.java +++ b/src/main/java/com/minelittlepony/unicopia/util/shape/Sphere.java @@ -1,5 +1,7 @@ package com.minelittlepony.unicopia.util.shape; +import org.spongepowered.include.com.google.common.base.Objects; + import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.Random; @@ -102,6 +104,19 @@ public class Sphere implements Shape { return stretch.multiply(rad); } + @Override + public boolean equals(Object other) { + return other instanceof Sphere o + && Objects.equal(stretch, o.stretch) + && hollow == o.hollow + && Double.compare(rad, o.rad) == 0; + } + + @Override + public int hashCode() { + return Objects.hashCode(stretch, hollow, rad); + } + public static double computeEllipsoidArea(double rad, Vec3d stretch) { double p = 1.6075; double result = Math.pow(rad * stretch.x, p) * Math.pow(rad * stretch.y, p); diff --git a/src/main/resources/assets/unicopia/particles/bubble.json b/src/main/resources/assets/unicopia/particles/bubble.json new file mode 100644 index 00000000..21bb4eeb --- /dev/null +++ b/src/main/resources/assets/unicopia/particles/bubble.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "minecraft:bubble" + ] +} diff --git a/src/main/resources/assets/unicopia/textures/spells/dark_vortex/accretion_disk.png b/src/main/resources/assets/unicopia/textures/spells/dark_vortex/accretion_disk.png new file mode 100644 index 00000000..d1ffe0c5 Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/spells/dark_vortex/accretion_disk.png differ diff --git a/src/main/resources/data/unicopia/advancements/unicopia/earth/dead_ringer.json b/src/main/resources/data/unicopia/advancements/unicopia/earth/dead_ringer.json index 881e8c8d..dc70d6e7 100644 --- a/src/main/resources/data/unicopia/advancements/unicopia/earth/dead_ringer.json +++ b/src/main/resources/data/unicopia/advancements/unicopia/earth/dead_ringer.json @@ -2,13 +2,13 @@ "parent": "unicopia:unicopia/earth/born_on_a_rock_farm", "display": { "icon": { - "item": "unicopia:rock" + "item": "unicopia:iron_horse_shoe" }, "title": { - "translate": "advancements.unicopia.sticks_and_stones.title" + "translate": "advancements.unicopia.dead_ringer.title" }, "description": { - "translate": "advancements.unicopia.sticks_and_stones.description" + "translate": "advancements.unicopia.dead_ringer.description" }, "frame": "task", "show_toast": true, @@ -16,13 +16,13 @@ "hidden": true }, "criteria": { - "killed_entity_with_rock": { + "killed_entity_with_horseshoe": { "trigger": "minecraft:player_killed_entity", "conditions": { "killing_blow": { "tags": [ { - "id": "unicopia:from_rocks", + "id": "unicopia:from_horseshoes", "expected": true } ] @@ -31,6 +31,6 @@ } }, "requirements": [ - [ "killed_entity_with_rock" ] + [ "killed_entity_with_horseshoe" ] ] } diff --git a/src/main/resources/data/unicopia/advancements/unicopia/earth/sticks_and_stones.json b/src/main/resources/data/unicopia/advancements/unicopia/earth/sticks_and_stones.json index 591e4616..083c3c04 100644 --- a/src/main/resources/data/unicopia/advancements/unicopia/earth/sticks_and_stones.json +++ b/src/main/resources/data/unicopia/advancements/unicopia/earth/sticks_and_stones.json @@ -2,13 +2,13 @@ "parent": "unicopia:unicopia/earth/born_on_a_rock_farm", "display": { "icon": { - "item": "unicopia:horseshoe" + "item": "unicopia:rock" }, "title": { - "translate": "advancements.unicopia.dead_ringer.title" + "translate": "advancements.unicopia.sticks_and_stones.title" }, "description": { - "translate": "advancements.unicopia.dead_ringer.description" + "translate": "advancements.unicopia.sticks_and_stones.description" }, "frame": "task", "show_toast": true, @@ -16,13 +16,13 @@ "hidden": true }, "criteria": { - "killed_entity_with_horseshoe": { + "killed_entity_with_rock": { "trigger": "minecraft:player_killed_entity", "conditions": { "killing_blow": { "tags": [ { - "id": "unicopia:from_horseshoes", + "id": "unicopia:from_rocks", "expected": true } ] @@ -31,6 +31,6 @@ } }, "requirements": [ - [ "killed_entity_with_horseshoe" ] + [ "killed_entity_with_rock" ] ] -} +} \ No newline at end of file