mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 23:27:59 +01:00
Change particle handles and linking to be a little more robust. Should help with some cases where duplicate particles happen
This commit is contained in:
parent
3806799cf2
commit
063d4e6dd2
11 changed files with 97 additions and 82 deletions
|
@ -1,6 +1,7 @@
|
|||
package com.minelittlepony.unicopia.ability.magic;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
|
@ -30,8 +31,18 @@ public interface SpellContainer {
|
|||
public boolean forEach(Function<Spell, Operation> action, boolean update) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(UUID id) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a spell with the given uuid is present.
|
||||
*/
|
||||
boolean contains(UUID id);
|
||||
|
||||
/**
|
||||
* Gets the active effect for this caster updating it if needed.
|
||||
*/
|
||||
|
@ -79,6 +90,11 @@ public interface SpellContainer {
|
|||
|
||||
SpellContainer delegate();
|
||||
|
||||
@Override
|
||||
default boolean contains(UUID id) {
|
||||
return delegate().contains(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
default <T extends Spell> Optional<T> get(@Nullable SpellPredicate<T> type, boolean update) {
|
||||
return delegate().get(type, update);
|
||||
|
|
|
@ -54,10 +54,10 @@ public class JoustingSpell extends AbstractSpell {
|
|||
}
|
||||
|
||||
if (source.isClient()) {
|
||||
particlEffect.ifAbsent(source, spawner -> {
|
||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(UParticles.RAINBOOM_TRAIL, source.getOriginVector(), Vec3d.ZERO);
|
||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO);
|
||||
}).ifPresent(p -> p.attach(source));
|
||||
});
|
||||
}
|
||||
|
||||
LivingEntity owner = source.getMaster();
|
||||
|
|
|
@ -82,10 +82,9 @@ public class PlaceableSpell extends AbstractDelegatingSpell {
|
|||
|
||||
return super.tick(source, Situation.GROUND);
|
||||
} else if (situation == Situation.GROUND_ENTITY) {
|
||||
particlEffect.ifAbsent(source, spawner -> {
|
||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(new OrientedBillboardParticleEffect(UParticles.MAGIC_RUNES, 90, 0), source.getOriginVector(), Vec3d.ZERO);
|
||||
}).ifPresent(p -> {
|
||||
p.attach(source);
|
||||
p.setAttribute(1, spell.getType().getColor());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -55,10 +55,9 @@ public class DarkVortexSpell extends AttractiveSpell {
|
|||
|
||||
float radius = (float)getDrawDropOffRange(source) / 2;
|
||||
|
||||
particlEffect.ifAbsent(source, spawner -> {
|
||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.99F, radius), source.getOriginVector(), Vec3d.ZERO);
|
||||
}).ifPresent(p -> {
|
||||
p.attach(source);
|
||||
p.setAttribute(0, radius);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -70,10 +70,9 @@ public class ShieldSpell extends AbstractSpell {
|
|||
source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO);
|
||||
});
|
||||
|
||||
particlEffect.ifAbsent(source, spawner -> {
|
||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
||||
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.3F, radius), source.getOriginVector(), Vec3d.ZERO);
|
||||
}).ifPresent(p -> {
|
||||
p.attach(source);
|
||||
p.setAttribute(0, radius);
|
||||
p.setAttribute(1, getType().getColor());
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client.particle;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
|
@ -22,7 +23,7 @@ public class RainbowTrailParticle extends AbstractBillboardParticle implements A
|
|||
|
||||
private final List<Segment> segments = new ArrayList<>();
|
||||
|
||||
private final Link link = new Link();
|
||||
private Optional<Link> link = Optional.empty();
|
||||
|
||||
public RainbowTrailParticle(DefaultParticleType effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
|
||||
super(world, x, y, z, velocityX, velocityY, velocityZ);
|
||||
|
@ -41,13 +42,13 @@ public class RainbowTrailParticle extends AbstractBillboardParticle implements A
|
|||
}
|
||||
|
||||
@Override
|
||||
public void attach(Caster<?> caster) {
|
||||
link.attach(caster);
|
||||
public void attach(Link link) {
|
||||
this.link = Optional.of(link);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
link.detach();
|
||||
link = Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,9 +91,9 @@ public class RainbowTrailParticle extends AbstractBillboardParticle implements A
|
|||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (link.linked()) {
|
||||
if (link.isPresent()) {
|
||||
age = 0;
|
||||
link.ifAbsent(() -> {}).ifPresent(this::follow);
|
||||
link.flatMap(Link::get).ifPresent(this::follow);
|
||||
} else if (!dead) {
|
||||
follow(Pony.of(MinecraftClient.getInstance().player));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.minelittlepony.unicopia.client.particle;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.common.util.Color;
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
|
||||
|
@ -33,7 +35,7 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
private float prevRotationAngle;
|
||||
private float rotationAngle;
|
||||
|
||||
private final Link link = new Link();
|
||||
private Optional<Link> link = Optional.empty();
|
||||
|
||||
private int stasisAge = -1;
|
||||
|
||||
|
@ -52,18 +54,18 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
}
|
||||
|
||||
@Override
|
||||
public void attach(Caster<?> caster) {
|
||||
link.attach(caster);
|
||||
public void attach(Link link) {
|
||||
this.link = Optional.of(link);
|
||||
velocityX = 0;
|
||||
velocityY = 0;
|
||||
velocityZ = 0;
|
||||
Vec3d pos = caster.getOriginVector();
|
||||
Vec3d pos = link.get().map(Caster::getOriginVector).orElse(Vec3d.ZERO);
|
||||
setPos(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
link.detach();
|
||||
link = Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,16 +137,14 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (link.linked()) {
|
||||
link.ifAbsent(this::detach).map(Caster::getEntity).ifPresent(e -> {
|
||||
if (getAlphaScale() >= 0.9F) {
|
||||
if (stasisAge < 0) {
|
||||
stasisAge = age;
|
||||
}
|
||||
age = stasisAge;
|
||||
link.flatMap(Link::get).map(Caster::getEntity).ifPresentOrElse(e -> {
|
||||
if (getAlphaScale() >= 0.9F) {
|
||||
if (stasisAge < 0) {
|
||||
stasisAge = age;
|
||||
}
|
||||
});
|
||||
}
|
||||
age = stasisAge;
|
||||
}
|
||||
}, this::detach);
|
||||
|
||||
prevBaseSize = baseSize;
|
||||
if (baseSize < 3) {
|
||||
|
|
|
@ -17,6 +17,9 @@ import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
|||
import com.minelittlepony.unicopia.particle.ParticleHandle.Link;
|
||||
import com.minelittlepony.unicopia.util.ColorHelper;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.common.util.Color;
|
||||
|
||||
public class SphereParticle extends Particle implements Attachment {
|
||||
|
@ -28,7 +31,7 @@ public class SphereParticle extends Particle implements Attachment {
|
|||
protected float lerpIncrement;
|
||||
protected float toRadius;
|
||||
|
||||
private final Link link = new Link();
|
||||
private Optional<Link> link = Optional.empty();
|
||||
|
||||
private static final SphereModel MODEL = new SphereModel();
|
||||
|
||||
|
@ -58,9 +61,9 @@ public class SphereParticle extends Particle implements Attachment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void attach(Caster<?> caster) {
|
||||
public void attach(Link link) {
|
||||
setMaxAge(50000);
|
||||
link.attach(caster);
|
||||
this.link = Optional.of(link);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,14 +95,14 @@ public class SphereParticle extends Particle implements Attachment {
|
|||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (link.linked()) {
|
||||
link.ifAbsent(this::markDead).map(Caster::getEntity).ifPresent(e -> {
|
||||
if (link.isPresent()) {
|
||||
link.flatMap(Link::get).map(Caster::getEntity).ifPresentOrElse(e -> {
|
||||
setPos(e.getX(), e.getY() + 0.5, e.getZ());
|
||||
|
||||
prevPosX = e.lastRenderX;
|
||||
prevPosY = e.lastRenderY + 0.5;
|
||||
prevPosZ = e.lastRenderZ;
|
||||
});
|
||||
}, this::detach);
|
||||
|
||||
if (steps-- > 0) {
|
||||
radius += lerpIncrement;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.minelittlepony.unicopia.network.datasync;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -39,6 +40,11 @@ public class EffectSync implements SpellContainer {
|
|||
this.param = param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(UUID id) {
|
||||
return spells.containsReference(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Spell> Optional<T> get(@Nullable SpellPredicate<T> type, boolean update) {
|
||||
|
|
|
@ -34,6 +34,10 @@ public class NetworkedReferenceSet<T> {
|
|||
this.factory = factory;
|
||||
}
|
||||
|
||||
public boolean containsReference(UUID id) {
|
||||
return ids.contains(id);
|
||||
}
|
||||
|
||||
public Stream<T> getReferences() {
|
||||
return ids.stream().map(id -> values.get(id))
|
||||
.map(a -> a.getReference())
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package com.minelittlepony.unicopia.particle;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
|
@ -19,30 +20,41 @@ import net.minecraft.util.math.Vec3d;
|
|||
* A connection class for updating and persisting an attached particle effect.
|
||||
*/
|
||||
public class ParticleHandle {
|
||||
private Optional<WeakReference<Attachment>> particleEffect = Optional.empty();
|
||||
|
||||
private Optional<Attachment> particleEffect = Optional.empty();
|
||||
|
||||
public Optional<Attachment> ifAbsent(ParticleSource source, Consumer<ParticleSpawner> constructor) {
|
||||
particleEffect.filter(Attachment::isStillAlive).orElseGet(() -> {
|
||||
public Optional<Attachment> ifAbsent(UUID id, ParticleSource source, Consumer<ParticleSpawner> constructor) {
|
||||
return get().or(() -> {
|
||||
if (source.getWorld().isClient) {
|
||||
constructor.accept(this::addParticle);
|
||||
constructor.accept((effect, pos, vel) -> new ClientHandle().addParticle(id, source, effect, pos, vel));
|
||||
}
|
||||
return null;
|
||||
return get();
|
||||
});
|
||||
|
||||
return particleEffect;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
particleEffect.ifPresent(Attachment::detach);
|
||||
get().ifPresent(Attachment::detach);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private void addParticle(ParticleEffect effect, Vec3d pos, Vec3d vel) {
|
||||
Particle p = MinecraftClient.getInstance().particleManager.addParticle(effect, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z);
|
||||
private Optional<Attachment> get() {
|
||||
return particleEffect.map(WeakReference::get).filter(Attachment::isStillAlive);
|
||||
}
|
||||
|
||||
if (p instanceof Attachment) {
|
||||
particleEffect = Optional.of((Attachment)p);
|
||||
private final class ClientHandle {
|
||||
private static final Map<UUID, Particle> SPAWNED_PARTICLES = new WeakHashMap<>();
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private void addParticle(UUID id, ParticleSource source, ParticleEffect effect, Vec3d pos, Vec3d vel) {
|
||||
Particle p = SPAWNED_PARTICLES.computeIfAbsent(id, i -> {
|
||||
Particle 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 pp;
|
||||
});
|
||||
|
||||
if (p instanceof Attachment) {
|
||||
particleEffect = Optional.of(new WeakReference<>((Attachment)p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +62,7 @@ public class ParticleHandle {
|
|||
|
||||
boolean isStillAlive();
|
||||
|
||||
void attach(Caster<?> caster);
|
||||
void attach(Link link);
|
||||
|
||||
void detach();
|
||||
|
||||
|
@ -58,41 +70,17 @@ public class ParticleHandle {
|
|||
}
|
||||
|
||||
public static final class Link {
|
||||
|
||||
private Optional<Caster<?>> caster = Optional.empty();
|
||||
private Optional<WeakReference<Caster<?>>> caster = Optional.empty();
|
||||
private UUID effect;
|
||||
private boolean linked;
|
||||
|
||||
public void attach(Caster<?> caster) {
|
||||
this.linked = true;
|
||||
this.caster = Optional.of(caster);
|
||||
this.effect = caster.getSpellSlot().get(false).map(Spell::getUuid).orElse(null);
|
||||
private Link(UUID effect, Caster<?> caster) {
|
||||
this.caster = Optional.of(new WeakReference<>(caster));
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
caster = Optional.empty();
|
||||
}
|
||||
|
||||
public boolean linked() {
|
||||
return linked;
|
||||
}
|
||||
|
||||
public Optional<Caster<?>> ifAbsent(Runnable action) {
|
||||
caster = caster.filter(c -> {
|
||||
Entity e = c.getEntity();
|
||||
|
||||
return Caster.of(e).orElse(null) == c
|
||||
&& c.getSpellSlot().get(false)
|
||||
.filter(s -> s.getUuid().equals(effect))
|
||||
.isPresent()
|
||||
&& e != null
|
||||
&& c.getWorld().getEntityById(e.getId()) != null;
|
||||
});
|
||||
if (!caster.isPresent()) {
|
||||
action.run();
|
||||
}
|
||||
|
||||
return caster;
|
||||
public Optional<Caster<?>> get() {
|
||||
caster = caster.filter(r -> r.get() != null && r.get().getSpellSlot().contains(effect));
|
||||
return caster.map(WeakReference::get);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue