mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-30 16:28:00 +01:00
Clean up deprecated particle handling
This commit is contained in:
parent
edb1e024d6
commit
eb1b767319
18 changed files with 292 additions and 423 deletions
|
@ -1,11 +1,13 @@
|
||||||
package com.minelittlepony.unicopia;
|
package com.minelittlepony.unicopia;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.entity.player.dummy.DummyPlayerEntity;
|
import com.minelittlepony.unicopia.entity.player.dummy.DummyPlayerEntity;
|
||||||
|
import com.minelittlepony.unicopia.particle.ParticleSpawner;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
@ -32,6 +34,10 @@ public class InteractionManager {
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ParticleSpawner createBoundParticle(UUID id) {
|
||||||
|
return ParticleSpawner.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Identifier, ?> readChapters(PacketByteBuf buf) {
|
public Map<Identifier, ?> readChapters(PacketByteBuf buf) {
|
||||||
throw new RuntimeException("Method not supported");
|
throw new RuntimeException("Method not supported");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
|
|
||||||
import com.minelittlepony.unicopia.particle.UParticles;
|
|
||||||
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pegasus ability to perform rainbooms
|
* Pegasus ability to perform rainbooms
|
||||||
|
@ -72,7 +68,6 @@ public class PegasusRainboomAbility implements Ability<Hit> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.consumeSuperMove()) {
|
if (player.consumeSuperMove()) {
|
||||||
player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO);
|
|
||||||
SpellType.RAINBOOM.withTraits().apply(player, CastingMethod.INNATE);
|
SpellType.RAINBOOM.withTraits().apply(player, CastingMethod.INNATE);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
package com.minelittlepony.unicopia.ability.magic.spell;
|
package com.minelittlepony.unicopia.ability.magic.spell;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.InteractionManager;
|
||||||
import com.minelittlepony.unicopia.UTags;
|
import com.minelittlepony.unicopia.UTags;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
|
||||||
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
|
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle;
|
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
import com.minelittlepony.unicopia.particle.ParticleSpawner;
|
||||||
|
import com.minelittlepony.unicopia.particle.TargetBoundParticleEffect;
|
||||||
import com.minelittlepony.unicopia.server.world.ModificationType;
|
import com.minelittlepony.unicopia.server.world.ModificationType;
|
||||||
import com.minelittlepony.unicopia.particle.UParticles;
|
import com.minelittlepony.unicopia.particle.UParticles;
|
||||||
import com.minelittlepony.unicopia.util.shape.Shape;
|
import com.minelittlepony.unicopia.util.shape.Shape;
|
||||||
|
@ -26,7 +30,8 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
||||||
private static final int RADIUS = 5;
|
private static final int RADIUS = 5;
|
||||||
private static final Shape EFFECT_RANGE = new Sphere(false, RADIUS);
|
private static final Shape EFFECT_RANGE = new Sphere(false, RADIUS);
|
||||||
|
|
||||||
private final ParticleHandle particlEffect = new ParticleHandle();
|
@Nullable
|
||||||
|
private ParticleSpawner boundParticle;
|
||||||
|
|
||||||
private int age;
|
private int age;
|
||||||
|
|
||||||
|
@ -35,11 +40,6 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
||||||
setHidden(true);
|
setHidden(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDestroyed(Caster<?> source) {
|
|
||||||
particlEffect.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tick(Caster<?> source, Situation situation) {
|
public boolean tick(Caster<?> source, Situation situation) {
|
||||||
|
|
||||||
|
@ -47,14 +47,15 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
particlEffect.update(getUuid(), source, spawner -> {
|
|
||||||
spawner.addParticle(UParticles.RAINBOOM_TRAIL, source.getOriginVector(), Vec3d.ZERO);
|
|
||||||
}).ifPresent(attachment -> {
|
|
||||||
attachment.setAttribute(Attachment.ATTR_BOUND, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (source.isClient()) {
|
if (source.isClient()) {
|
||||||
//source.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO);
|
if (boundParticle == null) {
|
||||||
|
boundParticle = InteractionManager.INSTANCE.createBoundParticle(getUuid());
|
||||||
|
}
|
||||||
|
boundParticle.addParticle(new TargetBoundParticleEffect(UParticles.RAINBOOM_TRAIL, source.asEntity()), source.getOriginVector(), Vec3d.ZERO);
|
||||||
|
|
||||||
|
if (age == 0) {
|
||||||
|
source.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
source.findAllEntitiesInRange(RADIUS).forEach(e -> {
|
source.findAllEntitiesInRange(RADIUS).forEach(e -> {
|
||||||
|
@ -92,5 +93,6 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
||||||
public void fromNBT(NbtCompound compound) {
|
public void fromNBT(NbtCompound compound) {
|
||||||
super.fromNBT(compound);
|
super.fromNBT(compound);
|
||||||
age = compound.getInt("age");
|
age = compound.getInt("age");
|
||||||
|
boundParticle = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@ -14,10 +15,12 @@ import com.minelittlepony.unicopia.InteractionManager;
|
||||||
import com.minelittlepony.unicopia.USounds;
|
import com.minelittlepony.unicopia.USounds;
|
||||||
import com.minelittlepony.unicopia.client.gui.DismissSpellScreen;
|
import com.minelittlepony.unicopia.client.gui.DismissSpellScreen;
|
||||||
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
|
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
|
||||||
|
import com.minelittlepony.unicopia.client.particle.ClientBoundParticleSpawner;
|
||||||
import com.minelittlepony.unicopia.client.sound.*;
|
import com.minelittlepony.unicopia.client.sound.*;
|
||||||
import com.minelittlepony.unicopia.entity.player.PlayerPhysics;
|
import com.minelittlepony.unicopia.entity.player.PlayerPhysics;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity;
|
import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity;
|
||||||
|
import com.minelittlepony.unicopia.particle.ParticleSpawner;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
@ -47,7 +50,7 @@ public class ClientInteractionManager extends InteractionManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Identifier, ?> readChapters(PacketByteBuf buffer) {
|
public Map<Identifier, ?> readChapters(PacketByteBuf buffer) {
|
||||||
return buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter);
|
return buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -144,4 +147,9 @@ public class ClientInteractionManager extends InteractionManager {
|
||||||
public int getViewMode() {
|
public int getViewMode() {
|
||||||
return client.options.getPerspective().ordinal();
|
return client.options.getPerspective().ordinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParticleSpawner createBoundParticle(UUID id) {
|
||||||
|
return new ClientBoundParticleSpawner(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.minelittlepony.unicopia.client.particle;
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.client.render.RenderUtil;
|
||||||
|
|
||||||
import net.minecraft.client.particle.Particle;
|
import net.minecraft.client.particle.Particle;
|
||||||
import net.minecraft.client.particle.ParticleTextureSheet;
|
import net.minecraft.client.particle.ParticleTextureSheet;
|
||||||
import net.minecraft.client.render.BufferBuilder;
|
import net.minecraft.client.render.BufferBuilder;
|
||||||
|
@ -36,6 +38,16 @@ public abstract class AbstractGeometryBasedParticle extends Particle {
|
||||||
te.draw();
|
te.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final void renderQuad(Tessellator te, BufferBuilder buffer, RenderUtil.Vertex[] corners, float alpha, float tickDelta) {
|
||||||
|
int light = getBrightness(tickDelta);
|
||||||
|
buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT);
|
||||||
|
for (RenderUtil.Vertex corner : corners) {
|
||||||
|
buffer.vertex(corner.position().x, corner.position().y, corner.position().z).texture(corner.u(), corner.v()).color(red, green, blue, alpha).light(light).next();
|
||||||
|
}
|
||||||
|
te.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected final void renderQuad(VertexConsumer buffer, Vector3f[] corners, float alpha, float tickDelta) {
|
protected final void renderQuad(VertexConsumer buffer, Vector3f[] corners, float alpha, float tickDelta) {
|
||||||
int light = getBrightness(tickDelta);
|
int light = getBrightness(tickDelta);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.minelittlepony.unicopia.client.particle;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.particle.ParticleSpawner;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.particle.Particle;
|
||||||
|
import net.minecraft.particle.ParticleEffect;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A connection class for updating and persisting an attached particle effect.
|
||||||
|
*/
|
||||||
|
public class ClientBoundParticleSpawner implements ParticleSpawner {
|
||||||
|
private static final Map<UUID, Entry> SPAWNED_PARTICLES = new HashMap<>();
|
||||||
|
|
||||||
|
private final UUID id;
|
||||||
|
private WeakReference<BooleanSupplier> attachment = new WeakReference<>(null);
|
||||||
|
|
||||||
|
private final MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
|
||||||
|
public ClientBoundParticleSpawner(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addParticle(ParticleEffect effect, Vec3d pos, Vec3d vel) {
|
||||||
|
BooleanSupplier a = attachment.get();
|
||||||
|
if ((a == null || !a.getAsBoolean())) {
|
||||||
|
SPAWNED_PARTICLES.values().removeIf(set -> !set.getAsBoolean());
|
||||||
|
attachment = new WeakReference<>(SPAWNED_PARTICLES.computeIfAbsent(id, i -> {
|
||||||
|
return new Entry(
|
||||||
|
new WeakReference<>(client.world),
|
||||||
|
new WeakReference<>(client.particleManager.addParticle(effect, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z))
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Entry (WeakReference<World> world, WeakReference<Particle> particle) implements BooleanSupplier {
|
||||||
|
@Override
|
||||||
|
public boolean getAsBoolean() {
|
||||||
|
if (world.get() == null || world.get() != MinecraftClient.getInstance().world) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Particle particle = this.particle.get();
|
||||||
|
return particle != null && particle.isAlive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +1,46 @@
|
||||||
package com.minelittlepony.unicopia.client.particle;
|
package com.minelittlepony.unicopia.client.particle;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EntityConvertable;
|
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.client.render.bezier.BezierSegment;
|
import com.minelittlepony.unicopia.client.render.bezier.BezierSegment;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.client.render.bezier.Trail;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
import com.minelittlepony.unicopia.particle.TargetBoundParticleEffect;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Link;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.render.BufferBuilder;
|
import net.minecraft.client.render.BufferBuilder;
|
||||||
import net.minecraft.client.render.Tessellator;
|
import net.minecraft.client.render.Tessellator;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.particle.DefaultParticleType;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
public class RainbowTrailParticle extends AbstractBillboardParticle implements Attachment {
|
public class RainbowTrailParticle extends AbstractBillboardParticle {
|
||||||
private static final Identifier TEXTURE = Unicopia.id("textures/particles/rainboom_trail.png");
|
private static final Identifier TEXTURE = Unicopia.id("textures/particles/rainboom_trail.png");
|
||||||
|
|
||||||
private final List<Segment> segments = new ArrayList<>();
|
private final Trail trail;
|
||||||
|
|
||||||
private Optional<Link> link = Optional.empty();
|
@Nullable
|
||||||
|
private Entity target;
|
||||||
|
private boolean isAbility;
|
||||||
|
|
||||||
private boolean bound;
|
public RainbowTrailParticle(TargetBoundParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
|
||||||
|
|
||||||
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);
|
super(world, x, y, z, velocityX, velocityY, velocityZ);
|
||||||
segments.add(new Segment(new Vec3d(x, y, z)));
|
trail = new Trail(new Vec3d(x, y, z));
|
||||||
setMaxAge(300);
|
setMaxAge(300);
|
||||||
|
this.velocityX = velocityX;
|
||||||
|
this.velocityY = velocityY;
|
||||||
|
this.velocityZ = velocityZ;
|
||||||
|
|
||||||
|
if (effect.getTargetId() <= 0) {
|
||||||
|
this.target = world.getOtherEntities(null, Box.from(trail.pos)).get(0);
|
||||||
|
} else {
|
||||||
|
this.target = world.getEntityById(effect.getTargetId());
|
||||||
|
}
|
||||||
|
isAbility = Caster.of(target).filter(caster -> SpellType.RAINBOOM.isOn(caster)).isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,98 +49,45 @@ public class RainbowTrailParticle extends AbstractBillboardParticle implements A
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isStillAlive() {
|
public boolean isAlive() {
|
||||||
return age < getMaxAge() && (!dead || !segments.isEmpty());
|
return age < getMaxAge() && (!dead || !trail.getSegments().isEmpty());
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void attach(Link link) {
|
|
||||||
this.link = Optional.of(link);
|
|
||||||
bound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void detach() {
|
|
||||||
link = Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAttribute(int key, Number value) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) {
|
protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) {
|
||||||
float alpha = 1 - (float)age / maxAge;
|
float alpha = this.alpha * (1 - (float)age / maxAge);
|
||||||
|
|
||||||
|
List<Trail.Segment> segments = trail.getSegments();
|
||||||
|
|
||||||
for (int i = 0; i < segments.size() - 1; i++) {
|
for (int i = 0; i < segments.size() - 1; i++) {
|
||||||
BezierSegment corners = segments.get(i).getPlane(segments.get(i + 1));
|
BezierSegment corners = segments.get(i).getPlane(segments.get(i + 1));
|
||||||
float scale = getScale(tickDelta);
|
float scale = getScale(tickDelta);
|
||||||
|
|
||||||
corners.forEachCorner(corner -> {
|
corners.forEachCorner(corner -> {
|
||||||
corner.mul(scale);
|
corner.position().mul(scale).add(x, y, z);
|
||||||
corner.add(x, y, z);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
renderQuad(te, buffer, corners.corners(), segments.get(i).getAlpha() * alpha, tickDelta);
|
renderQuad(te, buffer, corners.corners(), segments.get(i).getAlpha() * alpha, tickDelta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void follow(EntityConvertable<?> caster) {
|
|
||||||
Vec3d next = caster.asEntity().getPos();
|
|
||||||
|
|
||||||
if (segments.isEmpty()) {
|
|
||||||
segments.add(new Segment(next));
|
|
||||||
} else {
|
|
||||||
Vec3d last = segments.get(segments.size() - 1).position;
|
|
||||||
if (next.distanceTo(last) > 0.2) {
|
|
||||||
segments.add(new Segment(next));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
if (link.isPresent()) {
|
if (target != null && target.isAlive()) {
|
||||||
age = 0;
|
if (isAbility) {
|
||||||
link.flatMap(Link::get).ifPresent(this::follow);
|
age = 0;
|
||||||
} else if (!dead && !bound) {
|
}
|
||||||
follow(Pony.of(MinecraftClient.getInstance().player));
|
trail.update(target.getEyePos());
|
||||||
|
|
||||||
|
if (isAbility && Caster.of(target).filter(caster -> SpellType.RAINBOOM.isOn(caster)).isEmpty()) {
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segments.size() > 1) {
|
if (trail.tick()) {
|
||||||
segments.removeIf(Segment::tick);
|
|
||||||
}
|
|
||||||
if (segments.isEmpty()) {
|
|
||||||
markDead();
|
markDead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class Segment {
|
|
||||||
Vec3d position;
|
|
||||||
Vector3f offset;
|
|
||||||
|
|
||||||
int age;
|
|
||||||
int maxAge;
|
|
||||||
|
|
||||||
Segment(Vec3d position) {
|
|
||||||
this.position = position;
|
|
||||||
this.offset = new Vector3f((float)(position.getX() - x), (float)(position.getY() - y), (float)(position.getZ() - z));
|
|
||||||
this.maxAge = 90;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getAlpha() {
|
|
||||||
return alpha * (1 - ((float)age / maxAge));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean tick() {
|
|
||||||
return segments.indexOf(this) < segments.size() - 1 && age++ >= maxAge;
|
|
||||||
}
|
|
||||||
|
|
||||||
BezierSegment getPlane(Segment to) {
|
|
||||||
return new BezierSegment(offset, to.offset, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,20 @@
|
||||||
package com.minelittlepony.unicopia.client.particle;
|
package com.minelittlepony.unicopia.client.particle;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.joml.Quaternionf;
|
import org.joml.Quaternionf;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
import com.minelittlepony.common.util.Color;
|
|
||||||
import com.minelittlepony.unicopia.EntityConvertable;
|
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
|
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Link;
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
import net.minecraft.client.render.BufferBuilder;
|
import net.minecraft.client.render.BufferBuilder;
|
||||||
import net.minecraft.client.render.Tessellator;
|
import net.minecraft.client.render.Tessellator;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.*;
|
import net.minecraft.util.math.*;
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class RunesParticle extends OrientedBillboardParticle implements Attachment {
|
public class RunesParticle extends OrientedBillboardParticle {
|
||||||
|
|
||||||
private static final Identifier[] TEXTURES = new Identifier[] {
|
private static final Identifier[] TEXTURES = new Identifier[] {
|
||||||
Unicopia.id("textures/particles/runes_0.png"),
|
Unicopia.id("textures/particles/runes_0.png"),
|
||||||
|
@ -40,10 +33,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
||||||
private float prevRotationAngle;
|
private float prevRotationAngle;
|
||||||
private float rotationAngle;
|
private float rotationAngle;
|
||||||
|
|
||||||
private Optional<Link> link = Optional.empty();
|
|
||||||
|
|
||||||
private int stasisAge = -1;
|
|
||||||
|
|
||||||
public RunesParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
|
public RunesParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
|
||||||
super(effect, world, x, y, z, velocityX, velocityY, velocityZ);
|
super(effect, world, x, y, z, velocityX, velocityY, velocityZ);
|
||||||
setMaxAge(70);
|
setMaxAge(70);
|
||||||
|
@ -53,52 +42,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
||||||
blue = world.random.nextFloat();
|
blue = world.random.nextFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStillAlive() {
|
|
||||||
return age < (maxAge - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void attach(Link link) {
|
|
||||||
this.link = Optional.of(link);
|
|
||||||
velocityX = 0;
|
|
||||||
velocityY = 0;
|
|
||||||
velocityZ = 0;
|
|
||||||
Vec3d pos = link.get().map(EntityConvertable::asEntity).map(Entity::getPos).orElse(Vec3d.ZERO);
|
|
||||||
setPos(pos.x, pos.y + 0.25, pos.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void detach() {
|
|
||||||
link = Optional.empty();
|
|
||||||
if (targetSize > 1) {
|
|
||||||
this.targetSize = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAttribute(int key, Number value) {
|
|
||||||
if (key == ATTR_COLOR) {
|
|
||||||
int tint = value.intValue();
|
|
||||||
red = Color.r(tint);
|
|
||||||
green = Color.g(tint);
|
|
||||||
blue = Color.b(tint);
|
|
||||||
}
|
|
||||||
if (key == ATTR_OPACITY) {
|
|
||||||
alpha = value.floatValue();
|
|
||||||
}
|
|
||||||
if (key == ATTR_RADIUS) {
|
|
||||||
targetSize = value.floatValue();
|
|
||||||
}
|
|
||||||
if (key == ATTR_PITCH) {
|
|
||||||
rotation = new Quaternionf(0, 0, 0, 1);
|
|
||||||
rotation.mul(RotationAxis.POSITIVE_Y.rotationDegrees(value.floatValue()));
|
|
||||||
}
|
|
||||||
if (key == ATTR_YAW) {
|
|
||||||
rotation.mul(RotationAxis.POSITIVE_X.rotationDegrees(180 - value.floatValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getScale(float tickDelta) {
|
public float getScale(float tickDelta) {
|
||||||
return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta);
|
return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta);
|
||||||
|
@ -166,15 +109,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
link.flatMap(Link::get).map(EntityConvertable::asEntity).ifPresentOrElse(e -> {
|
|
||||||
if (getAlphaScale() >= 0.9F) {
|
|
||||||
if (stasisAge < 0) {
|
|
||||||
stasisAge = age;
|
|
||||||
}
|
|
||||||
age = stasisAge;
|
|
||||||
}
|
|
||||||
}, this::detach);
|
|
||||||
|
|
||||||
prevBaseSize = baseSize;
|
prevBaseSize = baseSize;
|
||||||
if (baseSize < targetSize) {
|
if (baseSize < targetSize) {
|
||||||
baseSize += 0.1F;
|
baseSize += 0.1F;
|
||||||
|
|
|
@ -10,22 +10,13 @@ import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EntityConvertable;
|
|
||||||
import com.minelittlepony.unicopia.client.render.RenderLayers;
|
import com.minelittlepony.unicopia.client.render.RenderLayers;
|
||||||
import com.minelittlepony.unicopia.client.render.model.SphereModel;
|
import com.minelittlepony.unicopia.client.render.model.SphereModel;
|
||||||
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
|
||||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Link;
|
|
||||||
import com.minelittlepony.unicopia.util.ColorHelper;
|
import com.minelittlepony.unicopia.util.ColorHelper;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
import java.util.Optional;
|
public class SphereParticle extends Particle {
|
||||||
|
|
||||||
import com.minelittlepony.common.util.Color;
|
|
||||||
|
|
||||||
public class SphereParticle extends Particle implements Attachment {
|
|
||||||
|
|
||||||
protected float prevRadius;
|
protected float prevRadius;
|
||||||
protected float radius;
|
protected float radius;
|
||||||
|
@ -34,12 +25,6 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
protected float lerpIncrement;
|
protected float lerpIncrement;
|
||||||
protected float toRadius;
|
protected float toRadius;
|
||||||
|
|
||||||
private Optional<Link> link = Optional.empty();
|
|
||||||
|
|
||||||
private final SphereParticleEffect parameters;
|
|
||||||
|
|
||||||
private boolean bound;
|
|
||||||
|
|
||||||
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ) {
|
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ) {
|
||||||
this(parameters, w, x, y, z);
|
this(parameters, w, x, y, z);
|
||||||
|
|
||||||
|
@ -50,7 +35,6 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
|
|
||||||
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z) {
|
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z) {
|
||||||
super(w, x, y, z);
|
super(w, x, y, z);
|
||||||
this.parameters = parameters;
|
|
||||||
this.radius = parameters.radius();
|
this.radius = parameters.radius();
|
||||||
this.red = parameters.color().x / 255F;
|
this.red = parameters.color().x / 255F;
|
||||||
this.green = parameters.color().y / 255F;
|
this.green = parameters.color().y / 255F;
|
||||||
|
@ -60,43 +44,6 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
setMaxAge(10);
|
setMaxAge(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStillAlive() {
|
|
||||||
return age < (maxAge - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void attach(Link link) {
|
|
||||||
setMaxAge(50000);
|
|
||||||
this.link = Optional.of(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void detach() {
|
|
||||||
markDead();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAttribute(int key, Number value) {
|
|
||||||
if (key == ATTR_RADIUS) {
|
|
||||||
toRadius = value.floatValue();
|
|
||||||
steps = 20;
|
|
||||||
lerpIncrement = (toRadius - radius) / steps;
|
|
||||||
}
|
|
||||||
if (key == ATTR_COLOR) {
|
|
||||||
int tint = value.intValue();
|
|
||||||
red = Color.r(tint);
|
|
||||||
green = Color.g(tint);
|
|
||||||
blue = Color.b(tint);
|
|
||||||
}
|
|
||||||
if (key == ATTR_OPACITY) {
|
|
||||||
alpha = value.floatValue();
|
|
||||||
}
|
|
||||||
if (key == ATTR_BOUND) {
|
|
||||||
bound = value.intValue() == 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParticleTextureSheet getType() {
|
public ParticleTextureSheet getType() {
|
||||||
return ParticleTextureSheet.CUSTOM;
|
return ParticleTextureSheet.CUSTOM;
|
||||||
|
@ -106,24 +53,7 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
public void tick() {
|
public void tick() {
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
if (link.isPresent()) {
|
radius *= 0.9998281;
|
||||||
link.flatMap(Link::get).map(EntityConvertable::asEntity).ifPresentOrElse(e -> {
|
|
||||||
if (!bound) {
|
|
||||||
Vec3d offset = parameters.offset();
|
|
||||||
setPos(e.getX() + offset.getX(), e.getY() + offset.getY(), e.getZ() + offset.getZ());
|
|
||||||
|
|
||||||
prevPosX = e.lastRenderX + offset.getX();
|
|
||||||
prevPosY = e.lastRenderY + offset.getY();
|
|
||||||
prevPosZ = e.lastRenderZ + offset.getZ();
|
|
||||||
}
|
|
||||||
}, this::detach);
|
|
||||||
|
|
||||||
if (steps-- > 0) {
|
|
||||||
radius += lerpIncrement;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
radius *= 0.9998281;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,20 +4,22 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.client.render.RenderUtil;
|
||||||
|
|
||||||
public record BezierSegment(
|
public record BezierSegment(
|
||||||
Vector3f[] corners
|
RenderUtil.Vertex[] corners
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public BezierSegment(Vector3f from, Vector3f to, float height) {
|
public BezierSegment(Vector3f from, Vector3f to, float height) {
|
||||||
this(new Vector3f[] {
|
this(new RenderUtil.Vertex[] {
|
||||||
new Vector3f(from.x, from.y - height/2F, from.z), // bottom left
|
new RenderUtil.Vertex(new Vector3f(from.x, from.y - height/2F, from.z), 0, 0), // bottom left
|
||||||
new Vector3f(from.x, from.y + height/2F, from.z), // top left
|
new RenderUtil.Vertex(new Vector3f(from.x, from.y + height/2F, from.z), 1, 0), // top left
|
||||||
new Vector3f(to.x, to.y + height/2F, to.z), // top right
|
new RenderUtil.Vertex(new Vector3f(to.x, to.y + height/2F, to.z), 1, 1), // top right
|
||||||
new Vector3f(to.x, to.y - height/2F, to.z) // bottom right
|
new RenderUtil.Vertex(new Vector3f(to.x, to.y - height/2F, to.z), 0, 1) // bottom right
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forEachCorner(Consumer<Vector3f> transformer) {
|
public void forEachCorner(Consumer<RenderUtil.Vertex> transformer) {
|
||||||
for (var corner : corners) {
|
for (var corner : corners) {
|
||||||
transformer.accept(corner);
|
transformer.accept(corner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.client.render.bezier;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import org.joml.Vector3f;
|
|
||||||
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
|
|
||||||
public class Ribbon implements Iterable<BezierSegment> {
|
|
||||||
public float width;
|
|
||||||
public float angle;
|
|
||||||
|
|
||||||
private final List<Node> nodes = new ArrayList<>();
|
|
||||||
private final List<BezierSegment> segments = new ArrayList<>();
|
|
||||||
private Node lastNode;
|
|
||||||
|
|
||||||
public Ribbon(Vec3d position, Vector3f bottom, Vector3f top, float angle) {
|
|
||||||
this.angle = angle;
|
|
||||||
lastNode = new Node(position, position.toVector3f().add(bottom), position.toVector3f().add(top));
|
|
||||||
nodes.add(lastNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addNode(Vec3d position, float angle) {
|
|
||||||
Vector3f directionVector = position.subtract(lastNode.position()).toVector3f();
|
|
||||||
|
|
||||||
Vector3f bottom = lastNode.bottom().add(directionVector).rotateAxis(angle, directionVector.x, directionVector.y, directionVector.z);
|
|
||||||
Vector3f top = lastNode.top().add(directionVector).rotateAxis(angle, directionVector.x, directionVector.y, directionVector.z);
|
|
||||||
|
|
||||||
Node oldNode = lastNode;
|
|
||||||
lastNode = new Node(position, bottom, top);
|
|
||||||
nodes.add(lastNode);
|
|
||||||
segments.add(new BezierSegment(new Vector3f[] {
|
|
||||||
oldNode.bottom(),
|
|
||||||
oldNode.top(),
|
|
||||||
lastNode.bottom(),
|
|
||||||
lastNode.top()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<BezierSegment> iterator() {
|
|
||||||
return segments.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
record Node(Vec3d position, Vector3f bottom, Vector3f top) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package com.minelittlepony.unicopia.client.render.bezier;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
public class Trail {
|
||||||
|
|
||||||
|
private final List<Segment> segments = new ArrayList<>();
|
||||||
|
|
||||||
|
public final Vec3d pos;
|
||||||
|
|
||||||
|
public Trail(Vec3d pos) {
|
||||||
|
this.pos = pos;
|
||||||
|
segments.add(new Segment(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Segment> getSegments() {
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(Vec3d newPosition) {
|
||||||
|
if (segments.isEmpty()) {
|
||||||
|
segments.add(new Segment(newPosition));
|
||||||
|
} else {
|
||||||
|
Vec3d last = segments.get(segments.size() - 1).position;
|
||||||
|
if (newPosition.distanceTo(last) > 0.2) {
|
||||||
|
segments.add(new Segment(newPosition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tick() {
|
||||||
|
if (segments.size() > 1) {
|
||||||
|
segments.removeIf(Segment::tick);
|
||||||
|
}
|
||||||
|
return segments.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Segment {
|
||||||
|
Vec3d position;
|
||||||
|
Vector3f offset;
|
||||||
|
|
||||||
|
int age;
|
||||||
|
int maxAge;
|
||||||
|
|
||||||
|
Segment(Vec3d position) {
|
||||||
|
this.position = position;
|
||||||
|
this.offset = position.subtract(pos).toVector3f();
|
||||||
|
this.maxAge = 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAlpha() {
|
||||||
|
return (1 - ((float)age / maxAge));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean tick() {
|
||||||
|
return segments.indexOf(this) < segments.size() - 1 && age++ >= maxAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BezierSegment getPlane(Segment to) {
|
||||||
|
return new BezierSegment(offset, to.offset, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.minelittlepony.unicopia.client.render.spell;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
|
||||||
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
|
||||||
|
public class RainboomSpellRenderer extends SpellRenderer<RainboomAbilitySpell> {
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack matrices, VertexConsumerProvider vertices, RainboomAbilitySpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader
|
||||||
register(SpellType.DARK_VORTEX, DarkVortexSpellRenderer::new);
|
register(SpellType.DARK_VORTEX, DarkVortexSpellRenderer::new);
|
||||||
register(SpellType.BUBBLE, BubbleSpellRenderer::new);
|
register(SpellType.BUBBLE, BubbleSpellRenderer::new);
|
||||||
register(SpellType.PORTAL, PortalSpellRenderer::new);
|
register(SpellType.PORTAL, PortalSpellRenderer::new);
|
||||||
|
register(SpellType.RAINBOOM, RainboomSpellRenderer::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.particle;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.HashMap;
|
|
||||||
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.EntityConvertable;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
|
||||||
|
|
||||||
import net.fabricmc.api.EnvType;
|
|
||||||
import net.fabricmc.api.Environment;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.particle.Particle;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A connection class for updating and persisting an attached particle effect.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class ParticleHandle {
|
|
||||||
private final Map<String, Attachment> loadedEffects = new WeakHashMap<>();
|
|
||||||
|
|
||||||
public Optional<Attachment> update(UUID id, ParticleSource<?> source, Consumer<ParticleSpawner> constructor) {
|
|
||||||
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.asEntity().getWorld().isClient) {
|
|
||||||
new ClientHandle().addParticle(id, partName, source, constructor);
|
|
||||||
}
|
|
||||||
return get(partName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
loadedEffects.values().forEach(Attachment::detach);
|
|
||||||
loadedEffects.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Attachment> get(String partName) {
|
|
||||||
return Optional.ofNullable(loadedEffects.get(partName)).filter(Attachment::isStillAlive);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class ClientHandle {
|
|
||||||
private static final Map<UUID, Map<String, Entry>> SPAWNED_PARTICLES = new HashMap<>();
|
|
||||||
|
|
||||||
private Particle pp;
|
|
||||||
|
|
||||||
@Environment(EnvType.CLIENT)
|
|
||||||
private void addParticle(UUID id, String partName, ParticleSource<?> source, Consumer<ParticleSpawner> constructor) {
|
|
||||||
SPAWNED_PARTICLES.values().removeIf(set -> {
|
|
||||||
set.values().removeIf(particle -> particle.get() == null);
|
|
||||||
return set.isEmpty();
|
|
||||||
});
|
|
||||||
|
|
||||||
Entry p = SPAWNED_PARTICLES.computeIfAbsent(id, i -> new WeakHashMap<>()).computeIfAbsent(partName, i -> {
|
|
||||||
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) {
|
|
||||||
((Attachment) pp).attach(new Link(id, 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() {
|
|
||||||
if (world.get() == null || world.get() != MinecraftClient.getInstance().world) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Particle particle = this.particle.get();
|
|
||||||
|
|
||||||
return particle == null || !particle.isAlive() ? null : particle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Attachment {
|
|
||||||
int ATTR_RADIUS = 0;
|
|
||||||
int ATTR_COLOR = 1;
|
|
||||||
int ATTR_OPACITY = 2;
|
|
||||||
int ATTR_PITCH = 3;
|
|
||||||
int ATTR_YAW = 4;
|
|
||||||
int ATTR_BOUND = 5;
|
|
||||||
|
|
||||||
boolean isStillAlive();
|
|
||||||
|
|
||||||
void attach(Link link);
|
|
||||||
|
|
||||||
void detach();
|
|
||||||
|
|
||||||
void setAttribute(int key, Number value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class Link {
|
|
||||||
private Optional<WeakReference<EntityConvertable<?>>> caster = Optional.empty();
|
|
||||||
private UUID effect;
|
|
||||||
|
|
||||||
private Link(UUID effect, EntityConvertable<?> caster) {
|
|
||||||
this.caster = Optional.of(new WeakReference<>(caster));
|
|
||||||
this.effect = effect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<EntityConvertable<?>> get() {
|
|
||||||
caster = caster.filter(r -> r.get() != null && (!(r.get() instanceof Caster<?> c) || c.getSpellSlot().contains(effect)) && r.get().asEntity().isAlive());
|
|
||||||
return caster.map(WeakReference::get);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,5 +4,7 @@ import net.minecraft.particle.ParticleEffect;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
public interface ParticleSpawner {
|
public interface ParticleSpawner {
|
||||||
|
ParticleSpawner EMPTY = (effect, pos, vel) -> {};
|
||||||
|
|
||||||
void addParticle(ParticleEffect effect, Vec3d position, Vec3d velocity);
|
void addParticle(ParticleEffect effect, Vec3d position, Vec3d velocity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.minelittlepony.unicopia.particle;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.StringReader;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
import net.minecraft.particle.ParticleEffect;
|
||||||
|
import net.minecraft.particle.ParticleType;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
|
||||||
|
public class TargetBoundParticleEffect implements ParticleEffect {
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static final Factory<TargetBoundParticleEffect> FACTORY = ParticleFactoryHelper.of(TargetBoundParticleEffect::new, TargetBoundParticleEffect::new);
|
||||||
|
|
||||||
|
private final ParticleType<TargetBoundParticleEffect> type;
|
||||||
|
private final int targetId;
|
||||||
|
|
||||||
|
protected TargetBoundParticleEffect(ParticleType<TargetBoundParticleEffect> type, StringReader reader) throws CommandSyntaxException {
|
||||||
|
this.type = type;
|
||||||
|
this.targetId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TargetBoundParticleEffect(ParticleType<TargetBoundParticleEffect> type, PacketByteBuf buf) {
|
||||||
|
this.type = type;
|
||||||
|
this.targetId = buf.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TargetBoundParticleEffect(ParticleType<TargetBoundParticleEffect> type, Entity target) {
|
||||||
|
this.type = type;
|
||||||
|
this.targetId = target.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTargetId() {
|
||||||
|
return targetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParticleType<?> getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(PacketByteBuf buf) {
|
||||||
|
buf.writeInt(targetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String asString() {
|
||||||
|
return String.format(Locale.ROOT, "%s", Registries.PARTICLE_TYPE.getId(getType()), targetId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ public interface UParticles {
|
||||||
DefaultParticleType BUBBLE = register("bubble", FabricParticleTypes.simple());
|
DefaultParticleType BUBBLE = register("bubble", FabricParticleTypes.simple());
|
||||||
|
|
||||||
ParticleType<OrientedBillboardParticleEffect> RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
|
ParticleType<OrientedBillboardParticleEffect> RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
|
||||||
DefaultParticleType RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.simple());
|
ParticleType<TargetBoundParticleEffect> RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.complex(TargetBoundParticleEffect.FACTORY));
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
ParticleType<OrientedBillboardParticleEffect> MAGIC_RUNES = register("magic_runes", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
|
ParticleType<OrientedBillboardParticleEffect> MAGIC_RUNES = register("magic_runes", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
|
||||||
|
|
Loading…
Reference in a new issue