mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-24 13:57:59 +01:00
Fixed jars, fixed particles not respawning correctly when reloading a world, fixed some behaviours with black holes
This commit is contained in:
parent
76506665bc
commit
bb29d97ff3
14 changed files with 151 additions and 93 deletions
|
@ -83,7 +83,7 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (situation == Situation.GROUND_ENTITY) {
|
if (situation == Situation.GROUND_ENTITY) {
|
||||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
particlEffect.update(getUuid(), source, spawner -> {
|
||||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
||||||
}).ifPresent(p -> {
|
}).ifPresent(p -> {
|
||||||
p.setAttribute(1, spell.getType().getColor());
|
p.setAttribute(1, spell.getType().getColor());
|
||||||
|
|
|
@ -54,10 +54,10 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.isClient()) {
|
if (source.isClient()) {
|
||||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
particlEffect.update(getUuid(), source, spawner -> {
|
||||||
spawner.addParticle(UParticles.RAINBOOM_TRAIL, source.getOriginVector(), Vec3d.ZERO);
|
spawner.addParticle(UParticles.RAINBOOM_TRAIL, source.getOriginVector(), Vec3d.ZERO);
|
||||||
spawner.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);
|
||||||
}
|
}
|
||||||
|
|
||||||
LivingEntity owner = source.getMaster();
|
LivingEntity owner = source.getMaster();
|
||||||
|
|
|
@ -5,22 +5,31 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||||
import com.minelittlepony.unicopia.particle.DiskParticleEffect;
|
|
||||||
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
||||||
|
import com.minelittlepony.unicopia.particle.UParticles;
|
||||||
|
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||||
|
import com.minelittlepony.unicopia.projectile.ProjectileDelegate;
|
||||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||||
import com.minelittlepony.unicopia.util.PosHelper;
|
import com.minelittlepony.unicopia.util.PosHelper;
|
||||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.FallingBlockEntity;
|
||||||
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.entity.projectile.PersistentProjectileEntity;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.particle.ParticleTypes;
|
import net.minecraft.particle.ParticleTypes;
|
||||||
import net.minecraft.sound.SoundCategory;
|
import net.minecraft.sound.SoundCategory;
|
||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.math.Vec3f;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* More powerful version of the vortex spell which creates a black hole
|
* More powerful version of the vortex spell which creates a black hole.
|
||||||
|
*
|
||||||
|
* TODO: Possible uses
|
||||||
|
* - Garbage bin
|
||||||
|
* - Link with a teleportation spell to create a wormhole
|
||||||
*/
|
*/
|
||||||
public class DarkVortexSpell extends AttractiveSpell {
|
public class DarkVortexSpell extends AttractiveSpell {
|
||||||
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
||||||
|
@ -55,15 +64,17 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
setDirty();
|
setDirty();
|
||||||
|
|
||||||
if (age % 20 == 0) {
|
if (age % 20 == 0) {
|
||||||
source.getWorld().playSound(null, source.getOrigin(), SoundEvents.AMBIENT_SOUL_SAND_VALLEY_MOOD, SoundCategory.AMBIENT, 1, 1);
|
source.getWorld().playSound(null, source.getOrigin(), SoundEvents.AMBIENT_SOUL_SAND_VALLEY_ADDITIONS, SoundCategory.AMBIENT, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source.subtractEnergyCost(-accumulatedMass);
|
||||||
|
|
||||||
return super.tick(source, situation);
|
return super.tick(source, situation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFriendlyTogether(Affine other) {
|
public boolean isFriendlyTogether(Affine other) {
|
||||||
return accumulatedMass < 150 && super.isFriendlyTogether(other);
|
return accumulatedMass < 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -77,16 +88,27 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
|
|
||||||
float radius = (float)getEventHorizonRadius();
|
float radius = (float)getEventHorizonRadius();
|
||||||
|
|
||||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
particlEffect.update(getUuid(), source, spawner -> {
|
||||||
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.99F, radius, SPHERE_OFFSET), source.getOriginVector(), Vec3d.ZERO);
|
spawner.addParticle(new SphereParticleEffect(UParticles.SPHERE, getType().getColor(), 0.99F, radius, SPHERE_OFFSET), source.getOriginVector(), Vec3d.ZERO);
|
||||||
}).ifPresent(p -> {
|
}).ifPresent(p -> {
|
||||||
p.setAttribute(0, radius);
|
p.setAttribute(0, radius);
|
||||||
});
|
});
|
||||||
|
particlEffect.update(getUuid(), "_ring", source, spawner -> {
|
||||||
|
spawner.addParticle(new SphereParticleEffect(UParticles.DISK, 0xFFFFFFFF, 0.4F, radius + 1, SPHERE_OFFSET), getOrigin(source), Vec3d.ZERO);
|
||||||
|
}).ifPresent(p -> {
|
||||||
|
p.setAttribute(0, radius * 2F);
|
||||||
|
p.setAttribute(1, 0xAAAAAA);
|
||||||
|
});
|
||||||
|
|
||||||
|
double angle = age % 260;
|
||||||
|
|
||||||
source.spawnParticles(ParticleTypes.SMOKE, 3);
|
source.spawnParticles(ParticleTypes.SMOKE, 3);
|
||||||
|
|
||||||
if (age % 11 == 0) {
|
if (radius > 2) {
|
||||||
source.addParticle(new DiskParticleEffect(Vec3f.ZERO, 1, radius + 1), getOrigin(source), Vec3d.ZERO);
|
source.addParticle(new SphereParticleEffect(UParticles.DISK, 0xFF0000, 1, radius),
|
||||||
|
getOrigin(source).add(0, 0.2, 0), new Vec3d(0, angle, 10));
|
||||||
|
source.addParticle(new SphereParticleEffect(UParticles.DISK, 0xFF0000, 1, radius),
|
||||||
|
getOrigin(source).add(0, -0.2, 0), new Vec3d(0, angle, 10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,12 +128,19 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
|
|
||||||
double radius = getEventHorizonRadius();
|
double radius = getEventHorizonRadius();
|
||||||
|
|
||||||
if (radius > 3) {
|
if (radius > 5) {
|
||||||
Vec3d origin = getOrigin(source);
|
Vec3d origin = getOrigin(source);
|
||||||
PosHelper.getAllInRegionMutable(source.getOrigin(), new Sphere(false, radius)).forEach(i -> {
|
PosHelper.getAllInRegionMutable(source.getOrigin(), new Sphere(false, radius)).forEach(i -> {
|
||||||
CatapultSpell.createBlockEntity(source.getWorld(), i, e -> {
|
if (!source.getWorld().getFluidState(i).isEmpty()) {
|
||||||
applyRadialEffect(source, e, e.getPos().distanceTo(origin), radius);
|
return;
|
||||||
});
|
}
|
||||||
|
if (source.getOrigin().isWithinDistance(i, getEventHorizonRadius())) {
|
||||||
|
source.getWorld().breakBlock(i, false);
|
||||||
|
} else {
|
||||||
|
CatapultSpell.createBlockEntity(source.getWorld(), i, e -> {
|
||||||
|
applyRadialEffect(source, e, e.getPos().distanceTo(origin), radius);
|
||||||
|
});
|
||||||
|
}
|
||||||
setDirty();
|
setDirty();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -125,7 +154,7 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
// 3. force reaches 0 at distance of drawDropOffRange
|
// 3. force reaches 0 at distance of drawDropOffRange
|
||||||
|
|
||||||
private double getEventHorizonRadius() {
|
private double getEventHorizonRadius() {
|
||||||
return Math.sqrt(Math.max(0.001, getMass() - 10));
|
return Math.sqrt(Math.max(0.001, getMass() - 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getAttractiveForce(Caster<?> source, Entity target) {
|
private double getAttractiveForce(Caster<?> source, Entity target) {
|
||||||
|
@ -133,8 +162,8 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getMass() {
|
private double getMass() {
|
||||||
float pulse = (float)Math.sin(age * 6) / 8F;
|
float pulse = (float)Math.sin(age * 8) / 1F;
|
||||||
return 10 + Math.min(15, Math.min(0.5F + pulse, (float)Math.exp(age) / 8F - 90) + pulse + accumulatedMass / 10F);
|
return 10 + Math.min(15, Math.min(0.5F + pulse, (float)Math.exp(age) / 8F - 90) + accumulatedMass / 10F) + pulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getMass(Entity entity) {
|
private double getMass(Entity entity) {
|
||||||
|
@ -144,15 +173,38 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
@Override
|
@Override
|
||||||
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
|
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
|
||||||
|
|
||||||
|
if (target instanceof FallingBlockEntity && source.isClient()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (distance <= getEventHorizonRadius()) {
|
if (distance <= getEventHorizonRadius()) {
|
||||||
|
|
||||||
|
if (target instanceof MagicProjectileEntity) {
|
||||||
|
Item item = ((MagicProjectileEntity)target).getStack().getItem();
|
||||||
|
if (item instanceof ProjectileDelegate) {
|
||||||
|
((ProjectileDelegate) item).onImpact(((MagicProjectileEntity)target), source.getMaster());
|
||||||
|
}
|
||||||
|
} else if (target instanceof PersistentProjectileEntity) {
|
||||||
|
source.getMaster().damage(DamageSource.thrownProjectile(target, ((PersistentProjectileEntity)target).getOwner()), 4);
|
||||||
|
target.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
accumulatedMass += getMass(target);
|
accumulatedMass += getMass(target);
|
||||||
|
setDirty();
|
||||||
target.damage(MagicalDamageSource.create("black_hole"), Integer.MAX_VALUE);
|
target.damage(MagicalDamageSource.create("black_hole"), Integer.MAX_VALUE);
|
||||||
target.discard();
|
|
||||||
|
source.subtractEnergyCost(-getMass(target) * 10);
|
||||||
|
|
||||||
|
source.getWorld().playSound(null, source.getOrigin(), SoundEvents.AMBIENT_CRIMSON_FOREST_MOOD, SoundCategory.AMBIENT, 2, 0.02F);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
double force = getAttractiveForce(source, target);
|
double force = getAttractiveForce(source, target);
|
||||||
|
|
||||||
target.setVelocity(target.getVelocity().multiply(Math.min(1, 1 - force)));
|
target.setVelocity(target.getVelocity().multiply(Math.min(1, 1 - force)));
|
||||||
applyForce(getOrigin(source), target, -force, 0);
|
applyForce(getOrigin(source), target, -force, 0);
|
||||||
|
|
||||||
|
source.subtractEnergyCost(-2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,3 +222,9 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
accumulatedMass = compound.getFloat("accumulatedMass");
|
accumulatedMass = compound.getFloat("accumulatedMass");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle;
|
import com.minelittlepony.unicopia.particle.ParticleHandle;
|
||||||
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
||||||
|
import com.minelittlepony.unicopia.particle.UParticles;
|
||||||
import com.minelittlepony.unicopia.projectile.ProjectileUtil;
|
import com.minelittlepony.unicopia.projectile.ProjectileUtil;
|
||||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||||
|
|
||||||
|
@ -63,8 +64,8 @@ public class ShieldSpell extends AbstractSpell {
|
||||||
source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO);
|
source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO);
|
||||||
});
|
});
|
||||||
|
|
||||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
particlEffect.update(getUuid(), source, spawner -> {
|
||||||
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.3F, radius), origin, Vec3d.ZERO);
|
spawner.addParticle(new SphereParticleEffect(UParticles.SPHERE, getType().getColor(), 0.3F, radius), origin, Vec3d.ZERO);
|
||||||
}).ifPresent(p -> {
|
}).ifPresent(p -> {
|
||||||
p.setAttribute(0, radius);
|
p.setAttribute(0, radius);
|
||||||
p.setAttribute(1, getType().getColor());
|
p.setAttribute(1, getType().getColor());
|
||||||
|
|
|
@ -29,14 +29,19 @@ public class TargetSelecter {
|
||||||
|
|
||||||
Entity owner = source.getMaster();
|
Entity owner = source.getMaster();
|
||||||
|
|
||||||
boolean ownerIsValid = spell.isFriendlyTogether(source) && (EquinePredicates.PLAYER_UNICORN.test(owner) && owner.isSneaking());
|
boolean ownerIsValid = spell.isFriendlyTogether(source) && (EquinePredicates.PLAYER_UNICORN.test(owner));
|
||||||
|
|
||||||
return source.findAllEntitiesInRange(radius)
|
return source.findAllEntitiesInRange(radius)
|
||||||
.filter(entity -> !entity.isRemoved())
|
.filter(entity -> !entity.isRemoved())
|
||||||
.filter(entity -> {
|
.filter(entity -> {
|
||||||
return !FriendshipBraceletItem.isComrade(source, entity)
|
boolean hasShield = SpellPredicate.IS_SHIELD_LIKE.isOn(entity);
|
||||||
&& !SpellPredicate.IS_SHIELD_LIKE.isOn(entity)
|
boolean isOwnerOrFriend = Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity) || FriendshipBraceletItem.isComrade(source, entity);
|
||||||
&& !(ownerIsValid && (Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity)));
|
|
||||||
|
if (!ownerIsValid && isOwnerOrFriend) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !hasShield && (!ownerIsValid || !isOwnerOrFriend);
|
||||||
})
|
})
|
||||||
.filter(e -> filter.test(source, e))
|
.filter(e -> filter.test(source, e))
|
||||||
.map(i -> {
|
.map(i -> {
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class DiskParticle extends SphereParticle {
|
||||||
@Override
|
@Override
|
||||||
protected void renderModel(MatrixStack matrices, VertexConsumer buffer, float scale, float tickDelta, int light) {
|
protected void renderModel(MatrixStack matrices, VertexConsumer buffer, float scale, float tickDelta, int light) {
|
||||||
matrices.multiply(rotation);
|
matrices.multiply(rotation);
|
||||||
SphereModel.DISK.render(matrices, buffer, 1, light, scale, 1, 1, 1, 1);
|
SphereModel.DISK.render(matrices, buffer, light, 1, scale, 1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,9 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
colorGreen = Color.g(tint);
|
colorGreen = Color.g(tint);
|
||||||
colorBlue = Color.b(tint);
|
colorBlue = Color.b(tint);
|
||||||
}
|
}
|
||||||
|
if (key == 2) {
|
||||||
|
colorAlpha = (float)value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.particle;
|
|
||||||
|
|
||||||
import com.mojang.brigadier.StringReader;
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
||||||
|
|
||||||
import net.minecraft.network.PacketByteBuf;
|
|
||||||
import net.minecraft.particle.ParticleType;
|
|
||||||
import net.minecraft.util.math.Vec3f;
|
|
||||||
|
|
||||||
public class DiskParticleEffect extends SphereParticleEffect {
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static final Factory<DiskParticleEffect> FACTORY = ParticleFactoryHelper.of(DiskParticleEffect::new, DiskParticleEffect::new);
|
|
||||||
|
|
||||||
protected DiskParticleEffect(ParticleType<DiskParticleEffect> type, StringReader reader) throws CommandSyntaxException {
|
|
||||||
super(type, reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DiskParticleEffect(ParticleType<DiskParticleEffect> type, PacketByteBuf buf) {
|
|
||||||
super(type, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DiskParticleEffect(Vec3f color, float alpha, float rad) {
|
|
||||||
super(color, alpha, rad);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ParticleType<?> getType() {
|
|
||||||
return UParticles.DISK;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.minelittlepony.unicopia.particle;
|
package com.minelittlepony.unicopia.particle;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -13,53 +14,71 @@ import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.particle.Particle;
|
import net.minecraft.client.particle.Particle;
|
||||||
import net.minecraft.particle.ParticleEffect;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A connection class for updating and persisting an attached particle effect.
|
* A connection class for updating and persisting an attached particle effect.
|
||||||
*/
|
*/
|
||||||
public class ParticleHandle {
|
public class ParticleHandle {
|
||||||
private Optional<WeakReference<Attachment>> particleEffect = Optional.empty();
|
private final Map<String, Attachment> loadedEffects = new WeakHashMap<>();
|
||||||
|
|
||||||
public Optional<Attachment> ifAbsent(UUID id, ParticleSource source, Consumer<ParticleSpawner> constructor) {
|
public Optional<Attachment> update(UUID id, ParticleSource source, Consumer<ParticleSpawner> constructor) {
|
||||||
return get().or(() -> {
|
return update(id, "prime", source, constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Attachment> update(UUID id, String partName, ParticleSource source, Consumer<ParticleSpawner> constructor) {
|
||||||
|
return get(partName).or(() -> {
|
||||||
if (source.getWorld().isClient) {
|
if (source.getWorld().isClient) {
|
||||||
constructor.accept((effect, pos, vel) -> new ClientHandle().addParticle(id, source, effect, pos, vel));
|
new ClientHandle().addParticle(id, partName, source, constructor);
|
||||||
}
|
}
|
||||||
return get();
|
return get(partName);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
get().ifPresent(Attachment::detach);
|
loadedEffects.values().forEach(Attachment::detach);
|
||||||
|
loadedEffects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Attachment> get() {
|
private Optional<Attachment> get(String partName) {
|
||||||
return particleEffect.map(WeakReference::get).filter(Attachment::isStillAlive);
|
return Optional.ofNullable(loadedEffects.get(partName)).filter(Attachment::isStillAlive);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ClientHandle {
|
private final class ClientHandle {
|
||||||
private static final Map<UUID, Particle> SPAWNED_PARTICLES = new WeakHashMap<>();
|
private static final Map<UUID, Map<String, Entry>> SPAWNED_PARTICLES = new HashMap<>();
|
||||||
|
|
||||||
|
private Particle pp;
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
@Environment(EnvType.CLIENT)
|
||||||
private void addParticle(UUID id, ParticleSource source, ParticleEffect effect, Vec3d pos, Vec3d vel) {
|
private void addParticle(UUID id, String partName, ParticleSource source, Consumer<ParticleSpawner> constructor) {
|
||||||
Particle p = SPAWNED_PARTICLES.computeIfAbsent(id, i -> {
|
SPAWNED_PARTICLES.values().removeIf(set -> {
|
||||||
Particle pp = MinecraftClient.getInstance().particleManager.addParticle(effect, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z);
|
set.values().removeIf(particle -> particle.get() == null);
|
||||||
if (pp instanceof Attachment && source instanceof Caster<?>) {
|
return set.isEmpty();
|
||||||
((Attachment) pp).attach(new Link(id, (Caster<?>)source));
|
|
||||||
}
|
|
||||||
return pp;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (p instanceof Attachment) {
|
Entry p = SPAWNED_PARTICLES.computeIfAbsent(id, i -> new HashMap<>()).computeIfAbsent(partName, i -> {
|
||||||
particleEffect = Optional.of(new WeakReference<>((Attachment)p));
|
constructor.accept((effect, pos, vel) -> {
|
||||||
|
pp = MinecraftClient.getInstance().particleManager.addParticle(effect, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z);
|
||||||
|
if (pp instanceof Attachment && source instanceof Caster<?>) {
|
||||||
|
((Attachment) pp).attach(new Link(id, (Caster<?>)source));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new Entry(new WeakReference<>(MinecraftClient.getInstance().world), new WeakReference<>(pp));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (p.get() instanceof Attachment) {
|
||||||
|
loadedEffects.put(partName, (Attachment)p.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
record Entry (WeakReference<World> world, WeakReference<Particle> particle) {
|
||||||
|
public Particle get() {
|
||||||
|
return world.get() == null || world.get() != MinecraftClient.getInstance().world ? null : particle.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Attachment {
|
public interface Attachment {
|
||||||
|
|
||||||
boolean isStillAlive();
|
boolean isStillAlive();
|
||||||
|
|
||||||
void attach(Link link);
|
void attach(Link link);
|
||||||
|
|
|
@ -43,5 +43,4 @@ public interface ParticleSource extends ParticleSpawner {
|
||||||
default void addParticle(ParticleEffect effect, Vec3d position, Vec3d velocity) {
|
default void addParticle(ParticleEffect effect, Vec3d position, Vec3d velocity) {
|
||||||
getWorld().addParticle(effect, position.x, position.y, position.z, velocity.x, velocity.y, velocity.z);
|
getWorld().addParticle(effect, position.x, position.y, position.z, velocity.x, velocity.y, velocity.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,27 +26,30 @@ public class SphereParticleEffect implements ParticleEffect {
|
||||||
|
|
||||||
private Vec3d offset = Vec3d.ZERO;
|
private Vec3d offset = Vec3d.ZERO;
|
||||||
|
|
||||||
|
private final ParticleType<? extends SphereParticleEffect> type;
|
||||||
|
|
||||||
protected SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, StringReader reader) throws CommandSyntaxException {
|
protected SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, StringReader reader) throws CommandSyntaxException {
|
||||||
this(AbstractDustParticleEffect.readColor(reader), ParticleFactoryHelper.readFloat(reader), ParticleFactoryHelper.readFloat(reader), ParticleFactoryHelper.readVector(reader));
|
this(type, AbstractDustParticleEffect.readColor(reader), ParticleFactoryHelper.readFloat(reader), ParticleFactoryHelper.readFloat(reader), ParticleFactoryHelper.readVector(reader));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, PacketByteBuf buf) {
|
protected SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, PacketByteBuf buf) {
|
||||||
this(AbstractDustParticleEffect.readColor(buf), buf.readFloat(), buf.readFloat());
|
this(type, AbstractDustParticleEffect.readColor(buf), buf.readFloat(), buf.readFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
public SphereParticleEffect(int tint, float alpha, float rad) {
|
public SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, int tint, float alpha, float rad) {
|
||||||
this(tint, alpha, rad, DEFAULT_OFFSET);
|
this(type, tint, alpha, rad, DEFAULT_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SphereParticleEffect(Vec3f color, float alpha, float rad) {
|
public SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, Vec3f color, float alpha, float rad) {
|
||||||
this(color, alpha, rad, DEFAULT_OFFSET);
|
this(type, color, alpha, rad, DEFAULT_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SphereParticleEffect(int tint, float alpha, float rad, Vec3d offset) {
|
public SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, int tint, float alpha, float rad, Vec3d offset) {
|
||||||
this(new Vec3f(Color.r(tint), Color.g(tint), Color.b(tint)), alpha, rad, offset);
|
this(type, new Vec3f(Color.r(tint), Color.g(tint), Color.b(tint)), alpha, rad, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SphereParticleEffect(Vec3f color, float alpha, float rad, Vec3d offset) {
|
public SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, Vec3f color, float alpha, float rad, Vec3d offset) {
|
||||||
|
this.type = type;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
this.alpha = alpha;
|
this.alpha = alpha;
|
||||||
|
@ -71,7 +74,7 @@ public class SphereParticleEffect implements ParticleEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParticleType<?> getType() {
|
public ParticleType<?> getType() {
|
||||||
return UParticles.SPHERE;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,7 +19,7 @@ public interface UParticles {
|
||||||
DefaultParticleType RAIN_DROPS = register("rain_drops", FabricParticleTypes.simple());
|
DefaultParticleType RAIN_DROPS = register("rain_drops", FabricParticleTypes.simple());
|
||||||
|
|
||||||
ParticleType<SphereParticleEffect> SPHERE = register("sphere", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY));
|
ParticleType<SphereParticleEffect> SPHERE = register("sphere", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY));
|
||||||
ParticleType<DiskParticleEffect> DISK = register("disk", FabricParticleTypes.complex(true, DiskParticleEffect.FACTORY));
|
ParticleType<SphereParticleEffect> DISK = register("disk", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY));
|
||||||
|
|
||||||
ParticleType<FollowingParticleEffect> HEALTH_DRAIN = register("health_drain", FabricParticleTypes.complex(true, FollowingParticleEffect.FACTORY));
|
ParticleType<FollowingParticleEffect> HEALTH_DRAIN = register("health_drain", FabricParticleTypes.complex(true, FollowingParticleEffect.FACTORY));
|
||||||
|
|
||||||
|
|
|
@ -159,9 +159,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Caster<Li
|
||||||
setNoGravity(false);
|
setNoGravity(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getSpellSlot().get(true).filter(spell -> spell.tick(this, Situation.PROJECTILE)).isPresent()) {
|
getSpellSlot().get(true).filter(spell -> spell.tick(this, Situation.PROJECTILE));
|
||||||
discard();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getHydrophobic()) {
|
if (getHydrophobic()) {
|
||||||
if (world.getBlockState(getBlockPos()).getMaterial().isLiquid()) {
|
if (world.getBlockState(getBlockPos()).getMaterial().isLiquid()) {
|
||||||
|
|
|
@ -430,6 +430,8 @@
|
||||||
"death.attack.paradox": "%1$s imploded",
|
"death.attack.paradox": "%1$s imploded",
|
||||||
"death.attack.food_poisoning": "%1$s died of food poisoning",
|
"death.attack.food_poisoning": "%1$s died of food poisoning",
|
||||||
"death.attack.food_poisoning.attacker": "%2$s poisoned %1$s to death",
|
"death.attack.food_poisoning.attacker": "%2$s poisoned %1$s to death",
|
||||||
|
"death.attach.back_hole": "%1$s was sucked into a black hole",
|
||||||
|
"death.attach.back_hole": "%1$s got sucked into %2$s's black hole",
|
||||||
|
|
||||||
"unicopia.subtitle.flap_wings": "Wing Flaps",
|
"unicopia.subtitle.flap_wings": "Wing Flaps",
|
||||||
"unicopia.subtitle.wind_rush": "Wind Gust",
|
"unicopia.subtitle.wind_rush": "Wind Gust",
|
||||||
|
|
Loading…
Reference in a new issue