diff --git a/build.gradle b/build.gradle index 1cf670a..65617c4 100644 --- a/build.gradle +++ b/build.gradle @@ -126,7 +126,7 @@ import com.modrinth.minotaur.dependencies.ModDependency modrinth { projectId = 'QXA901PE' // The ID of your Modrinth project. Slugs will not work. uploadFile = remapJar // Tells Minotaur to use the remapped jar - versionType = "alpha" + versionType = "beta" dependencies = [ new ModDependency('P7dR8mSH', 'required'), //required dependency on Fabric API new ModDependency('AANobbMI', 'optional'), //compatible with Sodium diff --git a/src/main/java/quimufu/colourful_portals/MixinConfig.java b/src/main/java/quimufu/colourful_portals/MixinConfig.java index cc697b2..b9ac9e3 100644 --- a/src/main/java/quimufu/colourful_portals/MixinConfig.java +++ b/src/main/java/quimufu/colourful_portals/MixinConfig.java @@ -14,7 +14,7 @@ public class MixinConfig implements IMixinConfigPlugin { private static final Supplier TRUE = () -> true; private static final Map> CONDITIONS = Map.of( - "quimufu.colourful_portals.mixin.SodiumFluidRendererMixin", () -> FabricLoader.getInstance().isModLoaded("sodium") + "quimufu.colourful_portals.mixin.client.SodiumFluidRendererMixin", () -> FabricLoader.getInstance().isModLoaded("sodium") ); @Override diff --git a/src/main/java/quimufu/colourful_portals/PortalBlock.java b/src/main/java/quimufu/colourful_portals/PortalBlock.java index ba512dc..f93cf2c 100644 --- a/src/main/java/quimufu/colourful_portals/PortalBlock.java +++ b/src/main/java/quimufu/colourful_portals/PortalBlock.java @@ -76,8 +76,8 @@ public class PortalBlock extends Block implements FluidFillable { return VoxelShapes.empty(); } - @Override - protected void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) { + protected void onEntityCollisionOld(BlockState state, World world, BlockPos pos, Entity entity) { + ColourfulPortalsMod.LOGGER.info("detected collision {}", entity.getType()); if (entity.getBoundingBox() .intersects(getShape(state, world, pos).getBoundingBox())) { Vec3d vec3d = new Vec3d(0.5, 0.5f, 0.5); @@ -85,6 +85,11 @@ public class PortalBlock extends Block implements FluidFillable { } Vec3d entityPos = entity.getPos(); Vec3d prevEntityPos = new Vec3d(entity.prevX, entity.prevY, entity.prevZ); + if(entityPos.equals(prevEntityPos) && entity.getVelocity().squaredDistanceTo(Vec3d.ZERO) >= 0.01D){ + //in this case, the collision logic was called prior to the movement logic, + // so we'll have to calculate our own next postion + entityPos = entityPos.add(entity.getVelocity()); + } Vec3d movement = entityPos.subtract(prevEntityPos); if (world instanceof ServerWorld) { Direction.Axis axis = state.get(AXIS); diff --git a/src/main/java/quimufu/colourful_portals/mixin/BlockChangeAndEntityMovementMixin.java b/src/main/java/quimufu/colourful_portals/mixin/BlockChangeAndEntityMovementMixin.java new file mode 100644 index 0000000..df45094 --- /dev/null +++ b/src/main/java/quimufu/colourful_portals/mixin/BlockChangeAndEntityMovementMixin.java @@ -0,0 +1,89 @@ +package quimufu.colourful_portals.mixin; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.registry.Registries; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import quimufu.colourful_portals.util.RaycastHelper; + +import java.util.List; + +import static quimufu.colourful_portals.ColourfulPortalsMod.*; + +@Mixin(ServerWorld.class) +public abstract class BlockChangeAndEntityMovementMixin { + @Unique + private static final List HORIZONTAL = Direction.stream().filter(d -> d.getAxis().isHorizontal()).toList(); + +// @Unique +// private final ThreadLocal, Entity>> entities = +// ThreadLocal.withInitial(() -> HashMap.newHashMap(Registries.ENTITY_TYPE.size())); + + @Shadow + public abstract String toString(); + +// @Inject(at = @At(value = "HEAD"), method = "tickEntity") +// private void cpm_beforeEntityTick(Entity entity, CallbackInfo ci) { +// if(PORTAL_MANAGER.getLinkingSystem().needsMovementCallback()){ +// Entity copy = entities.get().computeIfAbsent(entity.getType(), t -> t.create(null)); +// copy.copyFrom(entity); +// } +// } + + @Shadow + public abstract boolean isChunkLoaded(long chunkPos); + + @Inject(at = @At("RETURN"), method = "tickEntity") + private void cpm_afterEntityTick(Entity entity, CallbackInfo ci) { + if (PORTAL_MANAGER.getLinkingSystem().needsMovementCallback()) { + Vec3d prevEntityPos; + if (entity instanceof ServerPlayerEntity serverPlayerEntity) { + ServerPlayNetworkHandlerAccessor spnha = (ServerPlayNetworkHandlerAccessor) serverPlayerEntity.networkHandler; + prevEntityPos = new Vec3d(spnha.getLastTickX(), spnha.getLastTickY(), spnha.getLastTickZ()); + } else { + prevEntityPos = new Vec3d(entity.prevX, entity.prevY, entity.prevZ); + } + Vec3d entityPos = entity.getPos(); + ServerWorld world = (ServerWorld) (Object) this; + List passedBlocks = RaycastHelper.passedBlocks(prevEntityPos, entityPos); + for (BlockPos passedBlock : passedBlocks) { + if (PORTAL_MANAGER.onMovementThroughBlock(entity, passedBlock, world)) { + return; + } + } + } + } + + @Inject(at = @At("RETURN"), method = "onBlockChanged") + private void cpm_afterOnBlockChanged(BlockPos pos, BlockState oldBlock, BlockState newBlock, CallbackInfo info) { + ServerWorld world = (ServerWorld) (Object) this; + if (world.isDebugWorld()) + return; + + // This code is injected into the end of ServerWorld.onBlockChanged()V + if (oldBlock.getBlock() != newBlock.getBlock()) { + if (PORTAL_BLOCKS.contains(Registries.BLOCK.getId(newBlock.getBlock()))) { + LOGGER.info("onBlockNew {} -> {}", oldBlock, newBlock); + Identifier blockId = Registries.BLOCK.getId(newBlock.getBlock()); + world.getServer().execute(() -> PORTAL_MANAGER.onPortalBlockPlaced(world, pos, blockId)); + } + + if (PORTAL_BLOCKS.contains(Registries.BLOCK.getId(oldBlock.getBlock()))) { + LOGGER.info("onBlockOld {} -> {}", oldBlock, newBlock); + Identifier blockId = Registries.BLOCK.getId(oldBlock.getBlock()); + world.getServer().execute(() -> PORTAL_MANAGER.onPortalBlockBroken(world, pos, blockId)); + } + } +} +} \ No newline at end of file diff --git a/src/main/java/quimufu/colourful_portals/mixin/BlockChangeMixin.java b/src/main/java/quimufu/colourful_portals/mixin/BlockChangeMixin.java deleted file mode 100644 index bdbf80e..0000000 --- a/src/main/java/quimufu/colourful_portals/mixin/BlockChangeMixin.java +++ /dev/null @@ -1,39 +0,0 @@ -package quimufu.colourful_portals.mixin; - -import net.minecraft.block.BlockState; -import net.minecraft.registry.Registries; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import static quimufu.colourful_portals.ColourfulPortalsMod.*; - -@Mixin(ServerWorld.class) -public class BlockChangeMixin { - - @Inject(at = @At("RETURN"), method = "onBlockChanged") - private void cpm_afterOnBlockChanged(BlockPos pos, BlockState oldBlock, BlockState newBlock, CallbackInfo info) { - ServerWorld world = (ServerWorld) (Object) this; - if(world.isDebugWorld()|| !world.isChunkLoaded(pos)) - return; - // This code is injected into the end of ServerWorld.onBlockChanged()V - if (oldBlock.getBlock() != newBlock.getBlock()) { - if (PORTAL_BLOCKS.contains(Registries.BLOCK.getId(newBlock.getBlock()))) { - LOGGER.info("onBlockNew {} -> {}", oldBlock, newBlock); - Identifier blockId = Registries.BLOCK.getId(newBlock.getBlock()); - PORTAL_MANAGER.onPortalBlockPlaced(world, pos, blockId); - - } - if (PORTAL_BLOCKS.contains(Registries.BLOCK.getId(oldBlock.getBlock()))) { - LOGGER.info("onBlockOld {} -> {}", oldBlock, newBlock); - Identifier blockId = Registries.BLOCK.getId(oldBlock.getBlock()); - PORTAL_MANAGER.onPortalBlockBroken(world, pos, blockId); - } - } - - } -} \ No newline at end of file diff --git a/src/main/java/quimufu/colourful_portals/mixin/EntityMixin.java b/src/main/java/quimufu/colourful_portals/mixin/EntityMixin.java deleted file mode 100644 index 9f5dd3a..0000000 --- a/src/main/java/quimufu/colourful_portals/mixin/EntityMixin.java +++ /dev/null @@ -1,65 +0,0 @@ -package quimufu.colourful_portals.mixin; - -import com.llamalad7.mixinextras.sugar.Local; -import net.minecraft.block.BlockState; -import net.minecraft.entity.Entity; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.RaycastContext; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import quimufu.colourful_portals.util.CollisionAwareShapeContext; - -import java.util.HashSet; - -import static quimufu.colourful_portals.ColourfulPortalsMod.PORTAL_BLOCK; - -@Mixin(Entity.class) -public class EntityMixin { - @Shadow - private World world; - - @Shadow - public double prevX; - - @Shadow - public double prevY; - - @Shadow - public double prevZ; - - @Shadow - private Vec3d pos; - - @Unique - private final ThreadLocal> calledAlready = ThreadLocal.withInitial(HashSet::new); - - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;onEntityCollision(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/Entity;)V"), method = "checkBlockCollision") - public void cpm_dontCallTwice(CallbackInfo ci, @Local BlockPos.Mutable mutable) { - calledAlready.get().add(mutable.toImmutable()); - } - - @Inject(at = @At("RETURN"), method = "checkBlockCollision") - public void cpm_afterCheckBlockCollision(CallbackInfo ci) { - if (!world.isClient()) { - BlockHitResult hitResult = world.raycast(new RaycastContext(new Vec3d(prevX, prevY, prevZ), pos, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, new CollisionAwareShapeContext())); - - BlockPos hitResultBlockPos = hitResult.getBlockPos(); - if (!calledAlready.get().contains(hitResultBlockPos)) { - BlockState state = world.getBlockState(hitResultBlockPos); - if (state.getBlock() == PORTAL_BLOCK) { - state.onEntityCollision(world, hitResultBlockPos, (Entity) ((Object) this)); - } - - } - calledAlready.get().clear(); - } - - } -} diff --git a/src/main/java/quimufu/colourful_portals/mixin/ServerPlayNetworkHandlerAccessor.java b/src/main/java/quimufu/colourful_portals/mixin/ServerPlayNetworkHandlerAccessor.java new file mode 100644 index 0000000..2d85288 --- /dev/null +++ b/src/main/java/quimufu/colourful_portals/mixin/ServerPlayNetworkHandlerAccessor.java @@ -0,0 +1,26 @@ +package quimufu.colourful_portals.mixin; + +import net.minecraft.server.network.ServerPlayNetworkHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ServerPlayNetworkHandler.class) +public interface ServerPlayNetworkHandlerAccessor { + @Accessor + double getLastTickX(); + + @Accessor + double getLastTickY(); + + @Accessor + double getLastTickZ(); + + @Accessor + double getLastTickRiddenX(); + + @Accessor + double getLastTickRiddenY(); + + @Accessor + double getLastTickRiddenZ(); +} diff --git a/src/main/java/quimufu/colourful_portals/mixin/ServerPlayerEntityAccessor.java b/src/main/java/quimufu/colourful_portals/mixin/ServerPlayerEntityAccessor.java new file mode 100644 index 0000000..66fa21d --- /dev/null +++ b/src/main/java/quimufu/colourful_portals/mixin/ServerPlayerEntityAccessor.java @@ -0,0 +1,12 @@ +package quimufu.colourful_portals.mixin; + +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ServerPlayerEntity.class) +public interface ServerPlayerEntityAccessor { + + @Accessor + void setInTeleportationState(boolean inTeleportationState); +} diff --git a/src/main/java/quimufu/colourful_portals/mixin/AnimationMixin.java b/src/main/java/quimufu/colourful_portals/mixin/client/AnimationMixin.java similarity index 97% rename from src/main/java/quimufu/colourful_portals/mixin/AnimationMixin.java rename to src/main/java/quimufu/colourful_portals/mixin/client/AnimationMixin.java index 8ea9d54..1e7118c 100644 --- a/src/main/java/quimufu/colourful_portals/mixin/AnimationMixin.java +++ b/src/main/java/quimufu/colourful_portals/mixin/client/AnimationMixin.java @@ -1,4 +1,4 @@ -package quimufu.colourful_portals.mixin; +package quimufu.colourful_portals.mixin.client; import net.minecraft.client.texture.Animator; import net.minecraft.client.texture.SpriteContents; diff --git a/src/main/java/quimufu/colourful_portals/mixin/AnimationResourceMetadataMixin.java b/src/main/java/quimufu/colourful_portals/mixin/client/AnimationResourceMetadataMixin.java similarity index 93% rename from src/main/java/quimufu/colourful_portals/mixin/AnimationResourceMetadataMixin.java rename to src/main/java/quimufu/colourful_portals/mixin/client/AnimationResourceMetadataMixin.java index 9b68d37..0e2b08d 100644 --- a/src/main/java/quimufu/colourful_portals/mixin/AnimationResourceMetadataMixin.java +++ b/src/main/java/quimufu/colourful_portals/mixin/client/AnimationResourceMetadataMixin.java @@ -1,4 +1,4 @@ -package quimufu.colourful_portals.mixin; +package quimufu.colourful_portals.mixin.client; import net.minecraft.client.resource.metadata.AnimationResourceMetadata; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/quimufu/colourful_portals/mixin/AnimationResourceMetadataReaderMixin.java b/src/main/java/quimufu/colourful_portals/mixin/client/AnimationResourceMetadataReaderMixin.java similarity index 96% rename from src/main/java/quimufu/colourful_portals/mixin/AnimationResourceMetadataReaderMixin.java rename to src/main/java/quimufu/colourful_portals/mixin/client/AnimationResourceMetadataReaderMixin.java index feabc1e..93207a3 100644 --- a/src/main/java/quimufu/colourful_portals/mixin/AnimationResourceMetadataReaderMixin.java +++ b/src/main/java/quimufu/colourful_portals/mixin/client/AnimationResourceMetadataReaderMixin.java @@ -1,4 +1,4 @@ -package quimufu.colourful_portals.mixin; +package quimufu.colourful_portals.mixin.client; import com.google.gson.JsonObject; import net.minecraft.client.resource.metadata.AnimationResourceMetadata; diff --git a/src/main/java/quimufu/colourful_portals/mixin/SodiumFluidRendererMixin.java b/src/main/java/quimufu/colourful_portals/mixin/client/SodiumFluidRendererMixin.java similarity index 83% rename from src/main/java/quimufu/colourful_portals/mixin/SodiumFluidRendererMixin.java rename to src/main/java/quimufu/colourful_portals/mixin/client/SodiumFluidRendererMixin.java index 5a8c071..f9fb87f 100644 --- a/src/main/java/quimufu/colourful_portals/mixin/SodiumFluidRendererMixin.java +++ b/src/main/java/quimufu/colourful_portals/mixin/client/SodiumFluidRendererMixin.java @@ -1,17 +1,14 @@ -package quimufu.colourful_portals.mixin; +package quimufu.colourful_portals.mixin.client; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers; -import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer; import me.jellysquid.mods.sodium.client.world.WorldSlice; import net.minecraft.fluid.FluidState; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.BlockRenderView; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import quimufu.colourful_portals.client.SodiumPortalFluidRenderHandler; import static quimufu.colourful_portals.ColourfulPortalsMod.PORTAL_FLUID; diff --git a/src/main/java/quimufu/colourful_portals/mixin/SpriteContentsMixin.java b/src/main/java/quimufu/colourful_portals/mixin/client/SpriteContentsMixin.java similarity index 95% rename from src/main/java/quimufu/colourful_portals/mixin/SpriteContentsMixin.java rename to src/main/java/quimufu/colourful_portals/mixin/client/SpriteContentsMixin.java index c504742..37b1b8e 100644 --- a/src/main/java/quimufu/colourful_portals/mixin/SpriteContentsMixin.java +++ b/src/main/java/quimufu/colourful_portals/mixin/client/SpriteContentsMixin.java @@ -1,9 +1,8 @@ -package quimufu.colourful_portals.mixin; +package quimufu.colourful_portals.mixin.client; import net.minecraft.client.resource.metadata.AnimationResourceMetadata; import net.minecraft.client.texture.SpriteContents; import net.minecraft.client.texture.SpriteDimensions; -import net.minecraft.resource.metadata.ResourceMetadata; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/quimufu/colourful_portals/portal/DefaultLinkingSystem.java b/src/main/java/quimufu/colourful_portals/portal/DefaultLinkingSystem.java index fc77fcd..b4e4cb6 100644 --- a/src/main/java/quimufu/colourful_portals/portal/DefaultLinkingSystem.java +++ b/src/main/java/quimufu/colourful_portals/portal/DefaultLinkingSystem.java @@ -1,7 +1,10 @@ package quimufu.colourful_portals.portal; import net.minecraft.entity.Entity; +import net.minecraft.entity.projectile.ArrowEntity; +import net.minecraft.entity.projectile.PersistentProjectileEntity; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockBox; @@ -11,14 +14,15 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.TeleportTarget; import quimufu.colourful_portals.general_util.LinkedList; import quimufu.colourful_portals.general_util.Node; +import quimufu.colourful_portals.mixin.ServerPlayNetworkHandlerAccessor; +import quimufu.colourful_portals.mixin.ServerPlayerEntityAccessor; +import quimufu.colourful_portals.util.RaycastHelper; import java.util.*; import static quimufu.colourful_portals.ColourfulPortalsMod.LOGGER; import static quimufu.colourful_portals.ColourfulPortalsMod.MOD_ID; -import static quimufu.colourful_portals.portal.PortalHelper.getAxisW; -import static quimufu.colourful_portals.portal.PortalHelper.insideOf; -import static quimufu.colourful_portals.portal.PortalHelper.getDimId; +import static quimufu.colourful_portals.portal.PortalHelper.*; public class DefaultLinkingSystem implements PortalLinkingSystem { @@ -58,9 +62,32 @@ public class DefaultLinkingSystem implements PortalLinkingSystem { } @Override - public void onPortalPassed(Entity entity, BlockPos pos, ServerWorld world, Direction.Axis a) { - Set> portalRepresentationCandidated = positionalLookup.get(pos); - Optional> portalOpt = portalRepresentationCandidated.stream() + public boolean movementCallback(Entity entity, BlockPos pos, ServerWorld world) { + for (Direction.Axis axis : Direction.Axis.values()) { + Vec3d prevEntityPos; + if (entity instanceof ServerPlayerEntity serverPlayerEntity) { + ServerPlayNetworkHandlerAccessor spnha = (ServerPlayNetworkHandlerAccessor) serverPlayerEntity.networkHandler; + prevEntityPos = new Vec3d(spnha.getLastTickX(), spnha.getLastTickY(), spnha.getLastTickZ()); + } else { + prevEntityPos = new Vec3d(entity.prevX, entity.prevY, entity.prevZ); + } + if (RaycastHelper.passedOnAxis(prevEntityPos, entity.getPos(), pos, axis)) { + //LOGGER.info("passed on Axis!"); + if (onPortalPassed(entity, pos, world, axis)) { + return true; + } + } + } + return false; + } + + @Override + public boolean onPortalPassed(Entity entity, BlockPos pos, ServerWorld world, Direction.Axis a) { + Set> portalRepresentationCandidates = positionalLookup.get(pos); + if (portalRepresentationCandidates == null) { + return false; + } + Optional> portalOpt = portalRepresentationCandidates.stream() .filter(n -> !n.orphaned()) .filter(n -> n.getValue() != null) .filter(n -> getAxisW(n.getValue()).rotateYClockwise().getAxis() == a) @@ -70,31 +97,66 @@ public class DefaultLinkingSystem implements PortalLinkingSystem { Node fromNode = portalOpt.get(); Node toNode = fromNode.getNext() != null ? fromNode.getNext() : fromNode.getPartOf().getNode(0); if (toNode == null || toNode.getValue() == null) { - return; + return false; } PortalRepresentation fromPortal = fromNode.getValue(); PortalRepresentation toPortal = toNode.getValue(); BlockBox fromBox = fromPortal.location(); - Vec3d fromCenter = new Vec3d((fromBox.getMaxX()+1 + fromBox.getMinX())/2D,(fromBox.getMaxY()+1 + fromBox.getMinY())/2D,(fromBox.getMaxZ()+1 + fromBox.getMinZ())/2D); + Vec3d fromCenter = new Vec3d((fromBox.getMaxX() + 1 + fromBox.getMinX()) / 2D, (fromBox.getMaxY() + 1 + fromBox.getMinY()) / 2D, (fromBox.getMaxZ() + 1 + fromBox.getMinZ()) / 2D); BlockBox toBox = toPortal.location(); - Vec3d toCenter = new Vec3d((toBox.getMaxX()+1 + toBox.getMinX())/2D,(toBox.getMaxY()+1 + toBox.getMinY())/2D,(toBox.getMaxZ()+1 + toBox.getMinZ())/2D); + Vec3d toCenter = new Vec3d((toBox.getMaxX() + 1 + toBox.getMinX()) / 2D, (toBox.getMaxY() + 1 + toBox.getMinY()) / 2D, (toBox.getMaxZ() + 1 + toBox.getMinZ()) / 2D); + Vec3d relPos = entity.getPos().subtract(fromCenter); + Vec3d targetPos; + float targetYaw; + Vec3d targetVelocity; + ServerWorld toWorld = getPortalWorld(server, toPortal); if (getAxisW(fromPortal) == getAxisW(toPortal)) { - Vec3d relPos = entity.getPos().subtract(fromCenter); - Vec3d targetPos = toCenter.add(relPos); - //todo: maybe fancy continoous movement math! - ServerWorld toWorld = getPortalWorld(server, toPortal); - TeleportTarget teleportTarget = new TeleportTarget(toWorld, targetPos, entity.getVelocity(), entity.getYaw(), entity.getPitch(), TeleportTarget.ADD_PORTAL_CHUNK_TICKET); - entity.teleportTo(teleportTarget); + targetPos = toCenter.add(relPos); + targetYaw = entity.getYaw(); + targetVelocity = entity.getVelocity(); } else { - Vec3d relPos = entity.getPos().subtract(fromCenter); - Vec3d targetPos = toCenter.add(new Vec3d(-relPos.z, relPos.y, relPos.x)); - //todo: maybe fancy continoous movement math! - ServerWorld toWorld = getPortalWorld(server, toPortal); - TeleportTarget teleportTarget = new TeleportTarget(toWorld, targetPos, entity.getVelocity(), (entity.getYaw() + 90.F) % 360.F, entity.getPitch(), TeleportTarget.ADD_PORTAL_CHUNK_TICKET); - entity.teleportTo(teleportTarget); + targetPos = toCenter.add(new Vec3d(-relPos.z, relPos.y, relPos.x)); + if (entity instanceof PersistentProjectileEntity) { +// //un-fuck up arrow Yaw +// //rotate by 90° +// targetYaw = (entity.getYaw() + 90.F) % 360.F; +// //mirror +// targetYaw = (-targetYaw) % 360.F; +// //rotate by 90° +// targetYaw = (targetYaw - 90.F) % 360.F; +// +// //now it's normal! +// //Let's rotate it! +// targetYaw = (targetYaw + 90.F) % 360.F; +// +// //fuck it up again +// //rotate by 90° +// targetYaw = (targetYaw + 90.F) % 360.F; +// //mirror +// targetYaw = (-targetYaw) % 360.F; +// //rotate by 90° +// targetYaw = (targetYaw - 90.F) % 360.F; + //short: + targetYaw = (entity.getYaw() - 90.F) % 360.F; + } else { + targetYaw = (entity.getYaw() + 90.F) % 360.F; + } + Vec3d currVelocity = entity.getVelocity(); + targetVelocity = new Vec3d(-currVelocity.z, currVelocity.y, currVelocity.x); + } + //todo: maybe fancy continoous movement math! + TeleportTarget teleportTarget = new TeleportTarget(toWorld, targetPos, targetVelocity, targetYaw, entity.getPitch(), TeleportTarget.ADD_PORTAL_CHUNK_TICKET); + if (entity instanceof ServerPlayerEntity) { + ((ServerPlayerEntityAccessor) entity).setInTeleportationState(true); + } + Entity target; + if ((target = entity.teleportTo(teleportTarget)) != null) { + target.velocityDirty = true; + return true; } } + return false; } @Override @@ -102,6 +164,11 @@ public class DefaultLinkingSystem implements PortalLinkingSystem { return true; } + @Override + public boolean needsMovementCallback() { + return true; + } + private static ServerWorld getPortalWorld(MinecraftServer server, PortalRepresentation fromPortalRepresentation) { ServerWorld serverWorld = PortalHelper.getPortalWorld(server, fromPortalRepresentation); if (serverWorld == null) { diff --git a/src/main/java/quimufu/colourful_portals/portal/ImmersivePortalsLinkingSystem.java b/src/main/java/quimufu/colourful_portals/portal/ImmersivePortalsLinkingSystem.java index 717d017..d8b3a8b 100644 --- a/src/main/java/quimufu/colourful_portals/portal/ImmersivePortalsLinkingSystem.java +++ b/src/main/java/quimufu/colourful_portals/portal/ImmersivePortalsLinkingSystem.java @@ -111,8 +111,9 @@ public class ImmersivePortalsLinkingSystem implements PortalLinkingSystem { } @Override - public void onPortalPassed(Entity entity, BlockPos pos, ServerWorld world, Direction.Axis a) { + public boolean onPortalPassed(Entity entity, BlockPos pos, ServerWorld world, Direction.Axis a) { //no-op, handled by immptl + return false; } @Override @@ -120,6 +121,16 @@ public class ImmersivePortalsLinkingSystem implements PortalLinkingSystem { return false; } + @Override + public boolean needsMovementCallback() { + return false; + } + + @Override + public boolean movementCallback(Entity entity, BlockPos p, ServerWorld world) { + return false; + } + private List getPortalList(PortalRepresentation portalRepresentation) { Box portalBox = Box.from(portalRepresentation.location()); return getPortalWorld(portalRepresentation) diff --git a/src/main/java/quimufu/colourful_portals/portal/PortalLinkingSystem.java b/src/main/java/quimufu/colourful_portals/portal/PortalLinkingSystem.java index a55643e..a727a55 100644 --- a/src/main/java/quimufu/colourful_portals/portal/PortalLinkingSystem.java +++ b/src/main/java/quimufu/colourful_portals/portal/PortalLinkingSystem.java @@ -7,8 +7,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import quimufu.colourful_portals.general_util.LinkedList; -import java.util.List; - public interface PortalLinkingSystem { Identifier getLinkingSystemId(); @@ -16,7 +14,11 @@ public interface PortalLinkingSystem { void unLinkPortal(PortalRepresentation portalRepresentation); - void onPortalPassed(Entity entity, BlockPos pos, ServerWorld world, Direction.Axis a); + boolean onPortalPassed(Entity entity, BlockPos pos, ServerWorld world, Direction.Axis a); boolean needsReInit(); + + boolean needsMovementCallback(); + + boolean movementCallback(Entity entity, BlockPos p, ServerWorld world); } diff --git a/src/main/java/quimufu/colourful_portals/portal/PortalManager.java b/src/main/java/quimufu/colourful_portals/portal/PortalManager.java index 68986b2..221d7ac 100644 --- a/src/main/java/quimufu/colourful_portals/portal/PortalManager.java +++ b/src/main/java/quimufu/colourful_portals/portal/PortalManager.java @@ -251,6 +251,10 @@ public class PortalManager { linkingSystem.onPortalPassed(entity, pos, world, a); } + public boolean onMovementThroughBlock(Entity entity, BlockPos pos, ServerWorld world) { + return linkingSystem.movementCallback(entity, pos, world); + } + public void onLoad(MinecraftServer minecraftServer) { HashSet blockIdsToDelete = new HashSet<>(portalCandidateList.getBlockIds()); blockIdsToDelete.addAll(portalList.getBlockIds()); diff --git a/src/main/java/quimufu/colourful_portals/portal_fluid/PortalFluid.java b/src/main/java/quimufu/colourful_portals/portal_fluid/PortalFluid.java index 179dad2..18122a0 100644 --- a/src/main/java/quimufu/colourful_portals/portal_fluid/PortalFluid.java +++ b/src/main/java/quimufu/colourful_portals/portal_fluid/PortalFluid.java @@ -198,6 +198,8 @@ public class PortalFluid extends Fluid { } } Direction candidate = null; + BlockState candidateBlockState = null; + for (Direction dir : Direction.values()) { if (dir == targetDir.getOpposite() || dir == targetDir) { continue; @@ -212,12 +214,16 @@ public class PortalFluid extends Fluid { //if adjacent to any solid Block, it's a candidate if (neighbourOfInspected.isSideSolidFullSquare(world, neighborOfInspectedLocation, dir.getOpposite())) { candidate = dir; + candidateBlockState = world.getBlockState(pos.offset(dir)); + } - if (candidate == null && !neighbourOfInspected.isReplaceable()) { + if ((candidate == null || candidateBlockState.isReplaceable()) && !neighbourOfInspected.isReplaceable()) { candidate = dir; + candidateBlockState = world.getBlockState(pos.offset(dir)); } - if (candidate == null && !neighbourOfInspected.isReplaceable()) { + if (candidate == null) { candidate = dir; + candidateBlockState = world.getBlockState(pos.offset(dir)); } } diff --git a/src/main/java/quimufu/colourful_portals/util/RaycastHelper.java b/src/main/java/quimufu/colourful_portals/util/RaycastHelper.java new file mode 100644 index 0000000..7060551 --- /dev/null +++ b/src/main/java/quimufu/colourful_portals/util/RaycastHelper.java @@ -0,0 +1,80 @@ +package quimufu.colourful_portals.util; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import quimufu.colourful_portals.ColourfulPortalsMod; + +import java.util.LinkedList; +import java.util.List; + +public class RaycastHelper { + + + public static List passedBlocks(Vec3d from, Vec3d to) { + LinkedList psitions = new LinkedList<>(); + Vec3d difference = to.subtract(from); + if(to.equals(from)){ + return List.of(); + } + + double[] diff = new double[]{difference.getX(), difference.getY(), difference.getZ()}; + double[] start = new double[]{from.getX(), from.getY(), from.getZ()}; + double[] pos = new double[]{from.getX(), from.getY(), from.getZ()}; + BlockPos currentBlockPos = BlockPos.ofFloored(pos[0], pos[1], pos[2]); + + double currDelta = 0; + + while (currDelta < 1) { + psitions.add(currentBlockPos); + double minMissing = 1; + for (int i = 0; i < 3; i++) { + if (diff[i] == 0) { + continue; + } + double curr; + if ((curr = ((round(pos[i], Math.signum(diff[i])) - pos[i]) / diff[i])) < minMissing) { + minMissing = curr; + } + } + currDelta += minMissing; + + for (int i = 0; i < 3; i++) { + pos[i] = start[i] + currDelta * diff[i]; + } + currentBlockPos = BlockPos.ofFloored(pos[0], pos[1], pos[2]); + } + BlockPos last = BlockPos.ofFloored(to); + if(!psitions.getLast().equals(last)){ + psitions.add(last); + } + + return psitions; + + } + + private static double round(double val, double signum) { + if (signum > 0) { + return Math.floor(val + signum); + } + return Math.ceil(val + signum); + } + + public static boolean passedOnAxis(Vec3d from, Vec3d to, BlockPos blockPos, Direction.Axis axis) { + double startAA = from.getComponentAlongAxis(axis); + double centerAA = blockPos.toCenterPos().getComponentAlongAxis(axis); + Vec3d diff = to.subtract(from); + double differenceAA = diff.getComponentAlongAxis(axis); + + double hitAfter = (centerAA - startAA) / differenceAA; + + if (differenceAA == 0 || hitAfter > 1 || hitAfter < 0) { + return false; + } + + //ColourfulPortalsMod.LOGGER.info("{}, {}: {} -> {}", hitAfter,axis, from, to); + + return BlockPos.ofFloored(from.add(diff.multiply(hitAfter))) + .equals(blockPos); + } +} diff --git a/src/main/resources/colourful_portals.mixins.json b/src/main/resources/colourful_portals.mixins.json index 45c228d..11721df 100644 --- a/src/main/resources/colourful_portals.mixins.json +++ b/src/main/resources/colourful_portals.mixins.json @@ -3,18 +3,19 @@ "package": "quimufu.colourful_portals.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "BlockChangeMixin", - "EntityMixin" + "BlockChangeAndEntityMovementMixin", + "ServerPlayerEntityAccessor", + "ServerPlayNetworkHandlerAccessor" ], "injectors": { "defaultRequire": 1 }, "plugin": "quimufu.colourful_portals.MixinConfig", "client": [ - "AnimationMixin", - "AnimationResourceMetadataMixin", - "AnimationResourceMetadataReaderMixin", - "SodiumFluidRendererMixin", - "SpriteContentsMixin" + "client.AnimationMixin", + "client.AnimationResourceMetadataMixin", + "client.AnimationResourceMetadataReaderMixin", + "client.SodiumFluidRendererMixin", + "client.SpriteContentsMixin" ] } \ No newline at end of file