Fix portals and move them to a spell renderer

This commit is contained in:
Sollace 2024-01-22 17:23:11 +00:00
parent 225c67d558
commit edb1e024d6
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
10 changed files with 197 additions and 103 deletions

View file

@ -42,8 +42,6 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
private boolean publishedPosition;
private final ParticleHandle particleEffect = new ParticleHandle();
private float pitch;
private float yaw;
@ -53,6 +51,10 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
super(type);
}
public boolean isLinked() {
return teleportationTarget.getTarget().isPresent();
}
@Override
public boolean apply(Caster<?> caster) {
setOrientation(caster.asEntity().getPitch(), caster.asEntity().getYaw());
@ -73,17 +75,9 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
source.spawnParticles(origin, particleArea, 5, pos -> {
source.addParticle(effect, pos, Vec3d.ZERO);
});
teleportationTarget.getTarget().ifPresentOrElse(target -> {
particleEffect.update(getUuid(), source, spawner -> {
spawner.addParticle(new SphereParticleEffect(UParticles.DISK, getType().getColor(), 0.8F, 1.8F, new Vec3d(-pitch + 90, -yaw, 0)), source.getOriginVector(), Vec3d.ZERO);
});
}, () -> {
particleEffect.destroy();
});
} else {
teleportationTarget.getTarget().ifPresent(target -> {
if (Ether.get(source.asWorld()).get(getType(), target, targetPortalId) != null) {
if (Ether.get(source.asWorld()).get(getType(), target, targetPortalId) == null) {
Unicopia.LOGGER.debug("Lost sibling, breaking connection to " + target.uuid());
teleportationTarget.set(null);
setDirty();
@ -178,7 +172,6 @@ public class PortalSpell extends AbstractSpell implements PlaceableSpell.Placeme
@Override
protected void onDestroyed(Caster<?> caster) {
particleEffect.destroy();
Ether ether = Ether.get(caster.asWorld());
ether.remove(getType(), caster);
getTarget(caster).ifPresent(e -> e.setTaken(false));

View file

@ -63,6 +63,7 @@ import net.minecraft.world.BlockRenderView;
public interface URenderers {
BlockEntity CHEST_RENDER_ENTITY = new CloudChestBlock.TileData(BlockPos.ORIGIN, UBlocks.CLOUD_CHEST.getDefaultState());
@SuppressWarnings("unchecked")
static void bootstrap() {
ParticleFactoryRegistry.getInstance().register(UParticles.UNICORN_MAGIC, createFactory(MagicParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.CHANGELING_MAGIC, createFactory(ChangelingMagicParticle::new));

View file

@ -13,9 +13,11 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.RotationAxis;
public class BubbleSpellRenderer implements SpellRenderer<BubbleSpell> {
public class BubbleSpellRenderer extends SpellRenderer<BubbleSpell> {
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, BubbleSpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch);
matrices.push();
double height = caster.asEntity().getEyeY() - caster.getOriginVector().y;
matrices.translate(0, height * 0.5F, 0);

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client.render.spell;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.DarkVortexSpell;
import com.minelittlepony.unicopia.client.render.RenderLayers;
import com.minelittlepony.unicopia.client.render.model.PlaneModel;
@ -16,7 +17,7 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
public class DarkVortexSpellRenderer implements SpellRenderer<DarkVortexSpell> {
public class DarkVortexSpellRenderer extends SpellRenderer<DarkVortexSpell> {
private static final Identifier ACCRETION_DISK_TEXTURE = Unicopia.id("textures/spells/dark_vortex/accretion_disk.png");
@ -29,8 +30,13 @@ public class DarkVortexSpellRenderer implements SpellRenderer<DarkVortexSpell> {
}
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, DarkVortexSpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
public boolean shouldRenderEffectPass(int pass) {
return pass < 2;
}
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, DarkVortexSpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch);
Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity();
@ -43,15 +49,12 @@ public class DarkVortexSpellRenderer implements SpellRenderer<DarkVortexSpell> {
SphereModel.SPHERE.render(matrices, vertices.getBuffer(RenderLayers.getSolid()), light, 1, Math.min(radius * 0.6F, absDistance * 0.1F), 0, 0, 0, 1);
matrices.push();
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(90));
matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(90 + cameraEntity.getYaw(tickDelta)));
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-cameraEntity.getPitch(tickDelta)));
matrices.scale(0.7F, 1, 1);
float distance = 1F / MathHelper.clamp((absDistance / (radius * 4)), 0.0000001F, 1);
distance *= distance;
if (absDistance < radius * 4) {
@ -97,4 +100,9 @@ public class DarkVortexSpellRenderer implements SpellRenderer<DarkVortexSpell> {
matrices.pop();
matrices.pop();
}
@Override
protected void renderCountdown(MatrixStack matrices, TimedSpell spell, float tickDelta) {
}
}

View file

@ -15,7 +15,7 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.RotationAxis;
public class PlacedSpellRenderer implements SpellRenderer<PlaceableSpell> {
public class PlacedSpellRenderer extends SpellRenderer<PlaceableSpell> {
private static final Identifier[] TEXTURES = new Identifier[] {
Unicopia.id("textures/particles/runes_0.png"),
Unicopia.id("textures/particles/runes_1.png"),
@ -27,46 +27,65 @@ public class PlacedSpellRenderer implements SpellRenderer<PlaceableSpell> {
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, PlaceableSpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
if (!(caster.asEntity() instanceof CastSpellEntity)) {
if (!(caster.asEntity() instanceof CastSpellEntity castSpell)) {
return;
}
matrices.push();
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-castSpell.getYaw()));
for (Spell delegate : spell.getDelegates()) {
renderAmbientEffects(matrices, vertices, spell, delegate, caster, light, animationProgress, tickDelta);
matrices.push();
matrices.translate(0, 0.001, 0);
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(spell.pitch));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90 - spell.yaw));
float scale = (spell.getAge(tickDelta) / 25F) * 3;
matrices.scale(scale, scale, scale);
float angle = (animationProgress / 9F) % 360;
int color = delegate.getType().getColor();
float red = Color.r(color);
float green = Color.g(color);
float blue = Color.b(color);
for (int i = 0; i < TEXTURES.length; i++) {
VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(TEXTURES[i]));
for (int dim = 0; dim < 3; dim++) {
float ringSpeed = (i % 2 == 0 ? i : -1) * i;
matrices.push();
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim));
PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, red, green, blue, scale / ((float)(dim * 3) + 1));
matrices.pop();
}
}
matrices.pop();
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw));
SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertices, delegate, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch);
matrices.pop();
}
matrices.pop();
}
protected void renderAmbientEffects(MatrixStack matrices, VertexConsumerProvider vertices, PlaceableSpell spell, Spell delegate, Caster<?> caster, int light, float animationProgress, float tickDelta) {
matrices.push();
matrices.translate(0, 0.001, 0);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-spell.pitch));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180 - spell.yaw));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
float scale = (spell.getAge(tickDelta) / 25F) * 3;
matrices.scale(scale, scale, scale);
float angle = (animationProgress / 9F) % 360;
int color = delegate.getType().getColor();
float red = Color.r(color);
float green = Color.g(color);
float blue = Color.b(color);
SpellRenderer<?> renderer = SpellEffectsRenderDispatcher.INSTANCE.getRenderer(delegate);
for (int i = 0; i < TEXTURES.length; i++) {
if (!renderer.shouldRenderEffectPass(i)) {
continue;
}
VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityTranslucent(TEXTURES[i]));
for (int dim = 0; dim < 3; dim++) {
float ringSpeed = (i % 2 == 0 ? i : -1) * i;
matrices.push();
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim));
PlaneModel.INSTANCE.render(matrices, buffer, light, 0, 1, red, green, blue, scale / ((float)(dim * 3) + 1));
matrices.pop();
}
}
matrices.pop();
}
}

View file

@ -0,0 +1,51 @@
package com.minelittlepony.unicopia.client.render.spell;
import com.minelittlepony.common.util.Color;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell;
import com.minelittlepony.unicopia.client.render.RenderLayers;
import com.minelittlepony.unicopia.client.render.model.SphereModel;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.RotationAxis;
public class PortalSpellRenderer extends SpellRenderer<PortalSpell> {
@Override
public boolean shouldRenderEffectPass(int pass) {
return pass == 0;
}
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, PortalSpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch);
if (!spell.isLinked()) {
return;
}
int color = spell.getType().getColor();
float red = Color.r(color);
float green = Color.g(color);
float blue = Color.b(color);
VertexConsumer buffer = vertices.getBuffer(RenderLayers.getEndGateway());
double thickness = 0.1;
matrices.push();
matrices.translate(0, thickness, 0);
SphereModel.DISK.render(matrices, buffer, light, 0, 2.5F, red, green, blue, 1);
matrices.pop();
matrices.push();
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(180));
matrices.translate(0, thickness, 0);
SphereModel.DISK.render(matrices, buffer, light, 0, 2.5F, red, green, blue, 1);
matrices.pop();
}
}

View file

@ -12,9 +12,11 @@ import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
public class ShieldSpellRenderer implements SpellRenderer<ShieldSpell> {
public class ShieldSpellRenderer extends SpellRenderer<ShieldSpell> {
@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertices, ShieldSpell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
super.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch);
matrices.push();
double height = caster.asEntity().getEyeY() - caster.getOriginVector().y;
matrices.translate(0, height, 0);

View file

@ -8,19 +8,12 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.SpellContainer.Operation;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.util.ColorHelper;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer.TextLayerType;
@ -28,7 +21,6 @@ import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.registry.Registries;
import net.minecraft.resource.ResourceManager;
@ -38,7 +30,6 @@ import net.minecraft.util.Colors;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;
@ -56,6 +47,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader
register(SpellType.SHIELD, ShieldSpellRenderer::new);
register(SpellType.DARK_VORTEX, DarkVortexSpellRenderer::new);
register(SpellType.BUBBLE, BubbleSpellRenderer::new);
register(SpellType.PORTAL, PortalSpellRenderer::new);
}
@Nullable
@ -71,20 +63,16 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader
@SuppressWarnings("unchecked")
public <S extends Spell> SpellRenderer<S> getRenderer(S spell) {
return (SpellRenderer<S>)renderers.get(spell.getType());
return (SpellRenderer<S>)renderers.getOrDefault(spell.getType(), SpellRenderer.DEFAULT);
}
public void render(MatrixStack matrices, VertexConsumerProvider vertices, Spell spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
var renderer = getRenderer(spell);
if (renderer != null) {
if (renderer != SpellRenderer.DEFAULT) {
client.getBufferBuilders().getEntityVertexConsumers().draw();
renderer.render(matrices, vertices, spell, caster, light, limbAngle, limbDistance, tickDelta, animationProgress, headYaw, headPitch);
if (EquinePredicates.IS_CASTER.test(client.player)) {
renderGemstone(matrices, vertices, spell, caster, light, tickDelta, animationProgress);
}
}
}
@ -105,38 +93,6 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader
renderers = REGISTRY.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().create()));
}
private void renderGemstone(MatrixStack matrices, VertexConsumerProvider vertices, Spell spell, Caster<?> caster, int light, float tickDelta, float animationProgress) {
matrices.push();
if (!(caster.asEntity() instanceof MagicProjectileEntity)) {
float y = -caster.asEntity().getHeight();
if (caster.asEntity() instanceof CastSpellEntity) {
y = 1F;
}
matrices.translate(0, y + MathHelper.sin(animationProgress / 3F) * 0.2F, 0);
matrices.push();
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(animationProgress));
client.getItemRenderer().renderItem(spell.getType().withTraits(spell.getTraits()).getDefaultStack(), ModelTransformationMode.FIXED, light, 0, matrices, vertices, caster.asWorld(), 0);
matrices.pop();
if (spell instanceof TimedSpell timed && spell.getType() != SpellType.DARK_VORTEX) {
matrices.multiply(client.getEntityRenderDispatcher().getRotation().invert());
float radius = 0.6F;
float timeRemaining = timed.getTimer().getPercentTimeRemaining(tickDelta);
DrawableUtil.drawArc(matrices, radius, radius + 0.3F, 0, DrawableUtil.TAU * timeRemaining,
ColorHelper.lerp(MathHelper.clamp(timeRemaining * 4, 0, 1), 0xFF0000FF, 0xFFFFFFFF),
false
);
}
}
matrices.pop();
}
private void renderSpellDebugInfo(MatrixStack matrices, VertexConsumerProvider vertices, Caster<?> caster, int light) {
matrices.push();
matrices.multiply(client.getEntityRenderDispatcher().getRotation());

View file

@ -1,11 +1,73 @@
package com.minelittlepony.unicopia.client.render.spell;
import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.TimedSpell;
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
import com.minelittlepony.unicopia.util.ColorHelper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
public interface SpellRenderer<T extends Spell> {
void render(MatrixStack matrices, VertexConsumerProvider vertices, T spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch);
public class SpellRenderer<T extends Spell> {
public static final SpellRenderer<?> DEFAULT = new SpellRenderer<>();
protected final MinecraftClient client = MinecraftClient.getInstance();
public boolean shouldRenderEffectPass(int pass) {
return true;
}
public void render(MatrixStack matrices, VertexConsumerProvider vertices, T spell, Caster<?> caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
if (caster.asEntity() == client.cameraEntity || (caster.asEntity() instanceof MagicProjectileEntity)) {
return;
}
if (EquinePredicates.IS_CASTER.test(client.player)) {
renderGemstone(matrices, vertices, spell, caster, light, tickDelta, animationProgress);
}
}
private void renderGemstone(MatrixStack matrices, VertexConsumerProvider vertices, T spell, Caster<?> caster, int light, float tickDelta, float animationProgress) {
matrices.push();
transformGemstone(matrices, vertices, spell, caster, animationProgress);
matrices.push();
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(animationProgress));
client.getItemRenderer().renderItem(spell.getType().withTraits(spell.getTraits()).getDefaultStack(), ModelTransformationMode.FIXED, light, 0, matrices, vertices, caster.asWorld(), 0);
matrices.pop();
if (spell instanceof TimedSpell timed) {
renderCountdown(matrices, timed, tickDelta);
}
matrices.pop();
}
protected void renderCountdown(MatrixStack matrices, TimedSpell spell, float tickDelta) {
matrices.multiply(client.getEntityRenderDispatcher().getRotation().invert());
float radius = 0.6F;
float timeRemaining = spell.getTimer().getPercentTimeRemaining(tickDelta);
DrawableUtil.drawArc(matrices, radius, radius + 0.3F, 0, DrawableUtil.TAU * timeRemaining,
ColorHelper.lerp(MathHelper.clamp(timeRemaining * 4, 0, 1), 0xFF0000FF, 0xFFFFFFFF),
false
);
}
protected void transformGemstone(MatrixStack matrices, VertexConsumerProvider vertices, T spell, Caster<?> caster, float animationProgress) {
float y = -caster.asEntity().getHeight();
if (caster.asEntity() instanceof CastSpellEntity) {
y = 1F;
}
matrices.translate(0, y + MathHelper.sin(animationProgress / 3F) * 0.2F, 0);
}
}

View file

@ -41,7 +41,7 @@ public interface UEntities {
.dimensions(EntityDimensions.fixed(1, 1)));
EntityType<CastSpellEntity> CAST_SPELL = register("cast_spell", FabricEntityTypeBuilder.create(SpawnGroup.MISC, CastSpellEntity::new)
.trackRangeBlocks(200)
.dimensions(EntityDimensions.fixed(1, 0.4F)));
.dimensions(EntityDimensions.fixed(1, 1)));
EntityType<FairyEntity> TWITTERMITE = register("twittermite", FabricEntityTypeBuilder.create(SpawnGroup.MISC, FairyEntity::new)
.trackRangeBlocks(200)
.dimensions(EntityDimensions.fixed(0.1F, 0.1F)));