mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +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;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.player.dummy.DummyPlayerEntity;
|
||||
import com.minelittlepony.unicopia.particle.ParticleSpawner;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
@ -32,6 +34,10 @@ public class InteractionManager {
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
public ParticleSpawner createBoundParticle(UUID id) {
|
||||
return ParticleSpawner.EMPTY;
|
||||
}
|
||||
|
||||
public Map<Identifier, ?> readChapters(PacketByteBuf buf) {
|
||||
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.entity.player.Pony;
|
||||
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
|
||||
|
@ -72,7 +68,6 @@ public class PegasusRainboomAbility implements Ability<Hit> {
|
|||
}
|
||||
|
||||
if (player.consumeSuperMove()) {
|
||||
player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO);
|
||||
SpellType.RAINBOOM.withTraits().apply(player, CastingMethod.INNATE);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
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.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.*;
|
||||
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.particle.ParticleHandle;
|
||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
||||
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleSpawner;
|
||||
import com.minelittlepony.unicopia.particle.TargetBoundParticleEffect;
|
||||
import com.minelittlepony.unicopia.server.world.ModificationType;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
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 Shape EFFECT_RANGE = new Sphere(false, RADIUS);
|
||||
|
||||
private final ParticleHandle particlEffect = new ParticleHandle();
|
||||
@Nullable
|
||||
private ParticleSpawner boundParticle;
|
||||
|
||||
private int age;
|
||||
|
||||
|
@ -35,11 +40,6 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
|||
setHidden(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyed(Caster<?> source) {
|
||||
particlEffect.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tick(Caster<?> source, Situation situation) {
|
||||
|
||||
|
@ -47,14 +47,15 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
|||
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()) {
|
||||
//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 -> {
|
||||
|
@ -92,5 +93,6 @@ public class RainboomAbilitySpell extends AbstractSpell {
|
|||
public void fromNBT(NbtCompound compound) {
|
||||
super.fromNBT(compound);
|
||||
age = compound.getInt("age");
|
||||
boundParticle = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client;
|
|||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
@ -14,10 +15,12 @@ import com.minelittlepony.unicopia.InteractionManager;
|
|||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.client.gui.DismissSpellScreen;
|
||||
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.entity.player.PlayerPhysics;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity;
|
||||
import com.minelittlepony.unicopia.particle.ParticleSpawner;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
@ -47,7 +50,7 @@ public class ClientInteractionManager extends InteractionManager {
|
|||
|
||||
@Override
|
||||
public Map<Identifier, ?> readChapters(PacketByteBuf buffer) {
|
||||
return buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter);
|
||||
return buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -144,4 +147,9 @@ public class ClientInteractionManager extends InteractionManager {
|
|||
public int getViewMode() {
|
||||
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 com.minelittlepony.unicopia.client.render.RenderUtil;
|
||||
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.client.particle.ParticleTextureSheet;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
|
@ -36,6 +38,16 @@ public abstract class AbstractGeometryBasedParticle extends Particle {
|
|||
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) {
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.ability.magic.Caster;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||
import com.minelittlepony.unicopia.client.render.bezier.BezierSegment;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment;
|
||||
import com.minelittlepony.unicopia.particle.ParticleHandle.Link;
|
||||
import com.minelittlepony.unicopia.client.render.bezier.Trail;
|
||||
import com.minelittlepony.unicopia.particle.TargetBoundParticleEffect;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.Tessellator;
|
||||
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.math.Box;
|
||||
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 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(DefaultParticleType effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
|
||||
public RainbowTrailParticle(TargetBoundParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double 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);
|
||||
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
|
||||
|
@ -42,98 +49,45 @@ public class RainbowTrailParticle extends AbstractBillboardParticle implements A
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isStillAlive() {
|
||||
return age < getMaxAge() && (!dead || !segments.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) {
|
||||
|
||||
public boolean isAlive() {
|
||||
return age < getMaxAge() && (!dead || !trail.getSegments().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
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++) {
|
||||
BezierSegment corners = segments.get(i).getPlane(segments.get(i + 1));
|
||||
float scale = getScale(tickDelta);
|
||||
|
||||
corners.forEachCorner(corner -> {
|
||||
corner.mul(scale);
|
||||
corner.add(x, y, z);
|
||||
corner.position().mul(scale).add(x, y, z);
|
||||
});
|
||||
|
||||
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
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (link.isPresent()) {
|
||||
age = 0;
|
||||
link.flatMap(Link::get).ifPresent(this::follow);
|
||||
} else if (!dead && !bound) {
|
||||
follow(Pony.of(MinecraftClient.getInstance().player));
|
||||
if (target != null && target.isAlive()) {
|
||||
if (isAbility) {
|
||||
age = 0;
|
||||
}
|
||||
trail.update(target.getEyePos());
|
||||
|
||||
if (isAbility && Caster.of(target).filter(caster -> SpellType.RAINBOOM.isOn(caster)).isEmpty()) {
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (segments.size() > 1) {
|
||||
segments.removeIf(Segment::tick);
|
||||
}
|
||||
if (segments.isEmpty()) {
|
||||
if (trail.tick()) {
|
||||
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;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.minelittlepony.common.util.Color;
|
||||
import com.minelittlepony.unicopia.EntityConvertable;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
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 net.minecraft.client.render.BufferBuilder;
|
||||
import net.minecraft.client.render.Tessellator;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.*;
|
||||
|
||||
@Deprecated
|
||||
public class RunesParticle extends OrientedBillboardParticle implements Attachment {
|
||||
public class RunesParticle extends OrientedBillboardParticle {
|
||||
|
||||
private static final Identifier[] TEXTURES = new Identifier[] {
|
||||
Unicopia.id("textures/particles/runes_0.png"),
|
||||
|
@ -40,10 +33,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
private float prevRotationAngle;
|
||||
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) {
|
||||
super(effect, world, x, y, z, velocityX, velocityY, velocityZ);
|
||||
setMaxAge(70);
|
||||
|
@ -53,52 +42,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
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
|
||||
public float getScale(float tickDelta) {
|
||||
return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta);
|
||||
|
@ -166,15 +109,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme
|
|||
public void 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;
|
||||
if (baseSize < targetSize) {
|
||||
baseSize += 0.1F;
|
||||
|
|
|
@ -10,22 +10,13 @@ import net.minecraft.client.render.VertexConsumerProvider;
|
|||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
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.model.SphereModel;
|
||||
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.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.common.util.Color;
|
||||
|
||||
public class SphereParticle extends Particle implements Attachment {
|
||||
public class SphereParticle extends Particle {
|
||||
|
||||
protected float prevRadius;
|
||||
protected float radius;
|
||||
|
@ -34,12 +25,6 @@ public class SphereParticle extends Particle implements Attachment {
|
|||
protected float lerpIncrement;
|
||||
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) {
|
||||
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) {
|
||||
super(w, x, y, z);
|
||||
this.parameters = parameters;
|
||||
this.radius = parameters.radius();
|
||||
this.red = parameters.color().x / 255F;
|
||||
this.green = parameters.color().y / 255F;
|
||||
|
@ -60,43 +44,6 @@ public class SphereParticle extends Particle implements Attachment {
|
|||
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
|
||||
public ParticleTextureSheet getType() {
|
||||
return ParticleTextureSheet.CUSTOM;
|
||||
|
@ -106,24 +53,7 @@ public class SphereParticle extends Particle implements Attachment {
|
|||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (link.isPresent()) {
|
||||
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;
|
||||
}
|
||||
radius *= 0.9998281;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,20 +4,22 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.minelittlepony.unicopia.client.render.RenderUtil;
|
||||
|
||||
public record BezierSegment(
|
||||
Vector3f[] corners
|
||||
RenderUtil.Vertex[] corners
|
||||
) {
|
||||
|
||||
public BezierSegment(Vector3f from, Vector3f to, float height) {
|
||||
this(new Vector3f[] {
|
||||
new Vector3f(from.x, from.y - height/2F, from.z), // bottom left
|
||||
new Vector3f(from.x, from.y + height/2F, from.z), // top left
|
||||
new Vector3f(to.x, to.y + height/2F, to.z), // top right
|
||||
new Vector3f(to.x, to.y - height/2F, to.z) // bottom right
|
||||
this(new RenderUtil.Vertex[] {
|
||||
new RenderUtil.Vertex(new Vector3f(from.x, from.y - height/2F, from.z), 0, 0), // bottom left
|
||||
new RenderUtil.Vertex(new Vector3f(from.x, from.y + height/2F, from.z), 1, 0), // top left
|
||||
new RenderUtil.Vertex(new Vector3f(to.x, to.y + height/2F, to.z), 1, 1), // top 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) {
|
||||
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.BUBBLE, BubbleSpellRenderer::new);
|
||||
register(SpellType.PORTAL, PortalSpellRenderer::new);
|
||||
register(SpellType.RAINBOOM, RainboomSpellRenderer::new);
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
public interface ParticleSpawner {
|
||||
ParticleSpawner EMPTY = (effect, pos, vel) -> {};
|
||||
|
||||
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());
|
||||
|
||||
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
|
||||
ParticleType<OrientedBillboardParticleEffect> MAGIC_RUNES = register("magic_runes", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));
|
||||
|
|
Loading…
Reference in a new issue