Fix more portal issues

This commit is contained in:
Sollace 2024-11-19 15:54:49 +00:00
parent 6215252b57
commit 7e0272bd7f
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
11 changed files with 157 additions and 59 deletions

View file

@ -4,6 +4,10 @@ import java.util.Optional;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.joml.Vector4f;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Caster;
@ -22,6 +26,7 @@ import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.util.shape.*;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
@ -31,6 +36,7 @@ import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction.Axis;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.WorldEvents;
@ -139,14 +145,16 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
});
}
} else {
targetPortalPitch.set(targetEntry.getPitch());
targetPortalYaw.set(targetEntry.getYaw());
tickActive(source, targetEntry);
}
}
}
var entry = Ether.get(source.asWorld()).getOrCreate(this, source);
entry.setPitch(pitch.get());
entry.setYaw(yaw.get());
ownEntry.setPitch(getPitch());
ownEntry.setYaw(getYaw());
}
}
return !isDead();
@ -154,6 +162,11 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
private void tickActive(Caster<?> source, Ether.Entry<?> destination) {
destination.entity.getTarget().ifPresent(target -> {
Quaternionf rotationChange = getOrientationChange();
var matrix = getPositionMatrix(source, source.asEntity().getPos(), rotationChange, new Matrix4f());
float yawDifference = getYawDifference();
source.findAllEntitiesInRange(1).forEach(entity -> {
if (!entity.hasPortalCooldown()) {
@ -162,13 +175,16 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
return;
}
Vec3d offset = entity.getPos().subtract(source.asEntity().getPos())
.add(new Vec3d(0, 0, -0.7F).rotateY(-getTargetYaw() * MathHelper.RADIANS_PER_DEGREE));
float yawDifference = getYawDifference();
Vec3d dest = target.pos().add(offset.rotateY(yawDifference * MathHelper.RADIANS_PER_DEGREE)).add(0, 0.1, 0);
var dest4f = matrix.transform(new Vector4f(entity.getPos().toVector3f(), 1));
Vec3d dest = new Vec3d(dest4f.x, dest4f.y - 0.5, dest4f.z).add(new Vec3d(0, 0, -0.7F).rotateY(-getTargetYaw() * MathHelper.RADIANS_PER_DEGREE));
if (entity.getWorld().isTopSolid(BlockPos.ofFloored(dest).up(), entity)) {
dest = dest.add(0, 1, 0);
for (int i = 0; i < 2; i++) {
BlockPos destBlock = BlockPos.ofFloored(dest);
BlockState state = entity.getWorld().getBlockState(destBlock);
if (entity.getWorld().isTopSolid(destBlock, entity)) {
double maxY = state.getCollisionShape(entity.getWorld(), destBlock).getMax(Axis.Y);
dest = new Vec3d(dest.x, destBlock.getY() + maxY, dest.z);
}
}
entity.resetPortalCooldown();
@ -193,6 +209,24 @@ public class PortalSpell extends AbstractSpell implements PlacementControlSpell.
});
}
public Matrix4f getPositionMatrix(Caster<?> source, Vec3d pos, Quaternionf orientationChange, Matrix4f matrix) {
getDestinationReference().getTarget().ifPresent(destEntity -> {
Vector3f destPos = destEntity.pos().toVector3f();
Vector3f sourcePos = pos.toVector3f();
matrix.rotateAround(orientationChange.conjugate(), destPos.x, destPos.y, destPos.z);
matrix.translate(destPos.sub(sourcePos));
});
return matrix;
}
public Quaternionf getOrientationChange() {
return new Quaternionf().rotateTo(
Vec3d.fromPolar(getPitch(), getYaw()).toVector3f(),
Vec3d.fromPolar(getTargetPitch(), getTargetYaw()).toVector3f()
);
}
@Override
public void setOrientation(Caster<?> caster, float pitch, float yaw) {
this.pitch.set(90 - pitch);

View file

@ -9,6 +9,8 @@ import com.minelittlepony.unicopia.client.render.spell.SpellEffectsRenderDispatc
import com.minelittlepony.unicopia.client.render.spell.SpellRenderer;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
@ -16,6 +18,7 @@ import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.EntityRendererFactory;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Colors;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.ColorHelper.Argb;
import net.minecraft.util.math.RotationAxis;
@ -41,6 +44,10 @@ public class CastSpellEntityRenderer extends EntityRenderer<CastSpellEntity> {
@Override
public void render(CastSpellEntity entity, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light) {
MinecraftClient client = MinecraftClient.getInstance();
if (client.cameraEntity instanceof CastSpellEntity) {
return;
}
matrices.push();
matrices.translate(0, 0.001, 0);
final float height = entity.getHeight();
@ -52,7 +59,6 @@ public class CastSpellEntityRenderer extends EntityRenderer<CastSpellEntity> {
float animationProgress = getAnimationProgress(entity, tickDelta);
renderAmbientEffects(matrices, vertices, entity, entity.getSpellSlot().get().orElse(null), light, animationProgress, tickDelta);
SpellEffectsRenderDispatcher.INSTANCE.render(matrices, vertices, light, entity, entity.getScale(tickDelta), 0, tickDelta, animationProgress, yaw, pitch);
matrices.pop();
}
@ -69,7 +75,7 @@ public class CastSpellEntityRenderer extends EntityRenderer<CastSpellEntity> {
float angle = (animationProgress / 9F) % 360;
int color = spell == null ? 0 : spell.getTypeAndTraits().type().getColor();
int color = spell == null ? Colors.WHITE : spell.getTypeAndTraits().type().getColor();
@Nullable
SpellRenderer<?> renderer = spell == null ? null : SpellEffectsRenderDispatcher.INSTANCE.getRenderer(spell);
@ -87,7 +93,7 @@ public class CastSpellEntityRenderer extends EntityRenderer<CastSpellEntity> {
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, Argb.withAlpha(color, (int)(255 * (scale / ((float)(dim * 3) + 1)))));
PlaneModel.INSTANCE.render(matrices, buffer, light, OverlayTexture.DEFAULT_UV, 1, Argb.withAlpha(color, (int)(255 * (scale / ((float)(dim * 3) + 1)))));
matrices.pop();
}
}

View file

@ -7,6 +7,7 @@ import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector4f;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@ -42,6 +43,7 @@ import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Colors;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
@ -92,14 +94,10 @@ class PortalFrameBuffer implements AutoCloseable {
if (!(closed || framebuffer == null)) {
Tessellator tessellator = RenderSystem.renderThreadTesselator();
float uScale = (float)framebuffer.viewportWidth / (float)framebuffer.textureWidth;
float vScale = (float)framebuffer.viewportHeight / (float)framebuffer.textureHeight;
RenderSystem.setShader(UShaders.RENDER_TYPE_PORTAL_SURFACE);
RenderSystem._setShaderTexture(0, framebuffer.getColorAttachment());
BufferBuilder buffer = tessellator.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR);
SphereModel.DISK.scaleUV(uScale, vScale);
RenderSystem.setTextureMatrix(SphereModel.DISK.getTextureMatrix());
SphereModel.DISK.render(matrices, buffer, 1, 2F, Colors.WHITE);
BufferRenderer.drawWithGlobalProgram(buffer.end());
@ -115,6 +113,7 @@ class PortalFrameBuffer implements AutoCloseable {
}
public void build(PortalSpell spell, Caster<?> caster, EntityReference.EntityValues<Entity> target) {
closed = false;
long refreshRate = Unicopia.getConfig().fancyPortalRefreshRate.get();
if (refreshRate > 0 && framebuffer != null && System.currentTimeMillis() % refreshRate != 0) {
@ -146,6 +145,8 @@ class PortalFrameBuffer implements AutoCloseable {
}
recursionCount++;
Entity globalCameraEntity = client.cameraEntity;
try {
if (closed || client.interactionManager == null) {
close();
@ -155,17 +156,21 @@ class PortalFrameBuffer implements AutoCloseable {
Camera camera = client.gameRenderer.getCamera();
Entity cameraEntity = UEntities.CAST_SPELL.create(caster.asWorld());
Vec3d offset = new Vec3d(0, 1, -0.1F).rotateY(-spell.getTargetYaw() * MathHelper.RADIANS_PER_DEGREE);
float yaw = spell.getTargetYaw() + camera.getYaw() - spell.getYaw();
float pitch = spell.getTargetPitch();//MathHelper.clamp(spell.getTargetPitch() + (camera.getPitch() - spell.getPitch()) * 0.65F, -90, 90) + 90;
Vec3d pos = target.pos();
cameraEntity.setPosition(target.pos().add(offset));
cameraEntity.setPitch(pitch % 180);
cameraEntity.setYaw((yaw + 180) % 360);
Quaternionf orientationChange = spell.getOrientationChange();
Matrix4f positionMatrix = spell.getPositionMatrix(caster, target.pos(), orientationChange, new Matrix4f());
Vector4f transformedPos = positionMatrix.transform(new Vector4f(pos.toVector3f(), 1));
cameraEntity.setPosition(transformedPos.x, transformedPos.y + 0.5F, transformedPos.z);
cameraEntity.setPitch(MathHelper.clamp(camera.getPitch() - spell.getTargetPitch() + spell.getPitch(), -90, 90));
cameraEntity.setYaw(MathHelper.wrapDegrees(camera.getYaw() + spell.getYawDifference()));
client.cameraEntity = cameraEntity;
drawWorld(cameraEntity, 400, 400);
} finally {
client.cameraEntity = globalCameraEntity;
recursionCount--;
}
}
@ -198,44 +203,38 @@ class PortalFrameBuffer implements AutoCloseable {
BackgroundRenderer.clearFog();
RenderSystem.enableCull();
if (renderer == null) {
renderer = new WorldRenderer(client, client.getEntityRenderDispatcher(), client.getBlockEntityRenderDispatcher(), client.getBufferBuilders());
}
if (cameraEntity.getWorld() != world) {
world = (ClientWorld)cameraEntity.getWorld();
renderer.setWorld(world);
}
//((MixinMinecraftClient)client).setWorldRenderer(renderer);
var tickCounter = client.getRenderTickCounter();
if (renderer == null) {
renderer = new WorldRenderer(client, client.getEntityRenderDispatcher(), client.getBlockEntityRenderDispatcher(), client.getBufferBuilders());
renderer.setWorld(world);
renderer.scheduleBlockRenders(
ChunkSectionPos.getSectionCoord((int)cameraEntity.getX()),
ChunkSectionPos.getSectionCoord((int)cameraEntity.getY()),
ChunkSectionPos.getSectionCoord((int)cameraEntity.getZ())
);
}
camera.update(world, cameraEntity, false, false, 1);
double fov = 110;
double fov = 120;
Matrix4f projectionMatrix = client.gameRenderer.getBasicProjectionMatrix(fov);
Matrix4f cameraTransform = new Matrix4f().rotation(camera.getRotation().conjugate(new Quaternionf()));
client.gameRenderer.loadProjectionMatrix(projectionMatrix);
/*renderer.scheduleBlockRenders(
ChunkSectionPos.getSectionCoord((int)cameraEntity.getX()),
ChunkSectionPos.getSectionCoord((int)cameraEntity.getY()),
ChunkSectionPos.getSectionCoord((int)cameraEntity.getZ())
);*/
renderer.setupFrustum(
camera.getPos(),
cameraTransform,
client.gameRenderer.getBasicProjectionMatrix(Math.max(fov, this.client.options.getFov().getValue().intValue()))
client.gameRenderer.getBasicProjectionMatrix(Math.max(fov, client.options.getFov().getValue().intValue()))
);
try {
renderer.render(tickCounter, false, camera, client.gameRenderer,
renderer.render(client.getRenderTickCounter(), false, camera, client.gameRenderer,
client.gameRenderer.getLightmapTextureManager(),
cameraTransform,
projectionMatrix
);
} catch (Throwable t) {
close();
}
// Strip transparency
RenderSystem.colorMask(false, false, false, true);
RenderSystem.clearColor(1, 1, 1, 1);
@ -246,6 +245,7 @@ class PortalFrameBuffer implements AutoCloseable {
} finally {
client.getFramebuffer().beginWrite(true);
client.gameRenderer.loadProjectionMatrix(proj);
client.getBlockEntityRenderDispatcher().setWorld(client.world);
window.setFramebufferWidth(globalFramebufferWidth);
window.setFramebufferHeight(globalFramebufferHeight);
@ -264,6 +264,7 @@ class PortalFrameBuffer implements AutoCloseable {
if (renderer != null) {
renderer.getChunkBuilder().stop();
renderer.close();
renderer = null;
}
}
}

View file

@ -6,6 +6,8 @@ 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 com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.mob.CastSpellEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
@ -42,11 +44,14 @@ public class PortalSpellRenderer extends SpellRenderer<PortalSpell> {
return;
}
if (caster.asEntity().distanceTo(client.cameraEntity) > 50) {
if (client.cameraEntity instanceof CastSpellEntity) {
double distance = caster.asEntity().distanceTo(client.cameraEntity);
if (distance > 50) {
return; // don't bother rendering if too far away
}
if (client.cameraEntity == caster.asEntity()) {
return;
if (distance < 2) {
return; // don't render ourselves
}
}
matrices.push();

View file

@ -788,8 +788,8 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
Vec3d airflow = WeatherConditions.getAirflow(entity.getBlockPos(), entity.getWorld())
.multiply(0.04F * effectStrength)
.add(Vec3d.fromPolar(
(entity.getPitch() + (float)gust.getY()) * MathHelper.RADIANS_PER_DEGREE,
(entity.getYaw() + (float)gust.getZ()) * MathHelper.RADIANS_PER_DEGREE
(entity.getPitch() + (float)gust.getY()),
(entity.getYaw() + (float)gust.getZ())
).multiply(effectStrength * (float)gust.getX() / weight));
windStrength.update((float)airflow.length(), airflow.length() > windStrength.getValue() ? 1000 : 500);

View file

@ -3,18 +3,12 @@ package com.minelittlepony.unicopia.mixin.client;
import java.util.Queue;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.WorldRenderer;
@Mixin(MinecraftClient.class)
public interface MixinMinecraftClient {
@Accessor("renderTaskQueue")
Queue<Runnable> getRenderTaskQueue();
@Mutable
@Accessor("worldRenderer")
void setWorldRenderer(WorldRenderer worldRenderer);
}

View file

@ -0,0 +1,40 @@
package com.minelittlepony.unicopia.mixin.server;
import java.util.stream.LongStream;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.ability.magic.spell.effect.PortalSpell;
import com.minelittlepony.unicopia.server.world.Ether;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.server.network.ChunkDataSender;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.WorldChunk;
@Mixin(ChunkDataSender.class)
abstract class MixinChunkDataSender {
@Shadow
private @Final LongSet chunks;
@Inject(method = "add", at = @At("RETURN"))
private void onAdd(WorldChunk chunk, CallbackInfo info) {
var etherChunk = Ether.get(chunk.getWorld()).getChunk(chunk.getPos());
if (etherChunk != null) {
etherChunk.getStates().stream().flatMapToLong(state -> {
if (state.getSpell() instanceof PortalSpell portal && portal.getDestinationReference().isSet()) {
return portal.getDestinationReference()
.getTarget()
.stream()
.mapToLong(target -> ChunkPos.toLong(BlockPos.ofFloored(target.pos())));
}
return LongStream.empty();
}).distinct().forEach(chunks::add);
}
}
}

View file

@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.server.world.chunk.Chunk;
import com.minelittlepony.unicopia.server.world.chunk.PositionalDataMap;
import com.minelittlepony.unicopia.util.Tickable;
import com.minelittlepony.unicopia.util.serialization.NbtSerialisable;
@ -20,6 +21,7 @@ import net.minecraft.nbt.*;
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.PersistentState;
import net.minecraft.world.World;
@ -172,6 +174,10 @@ public class Ether extends PersistentState implements Tickable {
return world.isClient() ? Set.of() : positionData.getState(pos);
}
public Chunk<Entry<?>> getChunk(ChunkPos pos) {
return world.isClient() ? null : positionData.getChunk(pos);
}
private void pruneNodes() {
this.endpoints.values().removeIf(entities -> {
entities.values().removeIf(spells -> {

View file

@ -22,6 +22,10 @@ public class Chunk<T extends PositionalDataMap.Hotspot> {
return section == null ? Set.of() : section.getState(pos);
}
public synchronized Set<T> getStates() {
return new HashSet<>(entryToSections.keySet());
}
public synchronized boolean remove(T entry) {
Set<Section<T>> sections = entryToSections.remove(entry);
if (sections != null) {

View file

@ -5,6 +5,8 @@ import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.jetbrains.annotations.Nullable;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.util.math.BlockPos;
@ -22,6 +24,11 @@ public class PositionalDataMap<T extends PositionalDataMap.Hotspot> {
return chunk == null ? Set.of() : chunk.getState(pos);
}
@Nullable
public Chunk<T> getChunk(ChunkPos pos) {
return chunks.get(pos.toLong());
}
public void remove(T entry) {
Set<Chunk<T>> chunks = entryToChunks.remove(entry);
if (chunks != null) {

View file

@ -60,6 +60,7 @@
"datafix.MixinSchemas",
"datafix.MixinItemStackComponentizationFix",
"datafix.DataFixerBuilderAccessor",
"server.MixinChunkDataSender",
"server.MixinEntityTrackerEntry",
"server.MixinPathNodeMaker",
"server.MixinPlayerManager",