Question How to detect specific entity movement/collision

D

Deleted member 94

Guest
I did ask this last year on Discord channel, but I have tried more things since then but I still have not found solution so I thought I ask here if anyone has any ideas, if not it is OK.

My goal is to detect specific movement of a falling block entity, when it collides with cobble wall. Currently I detect similar movement by using EntityChangeBlockEvent and check correct velocity, but this is not possible for this type of movement because the velocity returns 0, 0, 0.

Here is the type of movement I speak of:
Screen_Shot_2021-12-31_at_12.27.15_AM.png

Sand (or other gravity block) pushes up by piston, hits slime but does not go 100% into end portal. In vanilla, it is duped. In paper it sits on edge.

Here is code I use to detect other type of similar movement:

Java:
  @EventHandler(priority = EventPriority.HIGHEST)
  public void onEntityChangeBlock(final EntityChangeBlockEvent event) {
    if (!(event.getEntity() instanceof final FallingBlock falling) || event.getTo() == Material.AIR) return;
    final Vector velocity = falling.getVelocity().clone();

    for (BlockFace face : ALLOWED_PORTAL_FACES) {
      final Block relative = event.getBlock().getRelative(face);
      if (relative.getType() != Material.END_PORTAL) continue;

      if ((face == BlockFace.NORTH && velocity.getZ() < 0D)
        || (face == BlockFace.EAST && velocity.getX() > 0D)
        || (face == BlockFace.SOUTH && velocity.getZ() > 0D)
        || (face == BlockFace.WEST && velocity.getX() < 0D)) {
        LOGGER.info("Falling block {} hit!", falling);
        return;
      }
    }
  }

Things I have thought of

  1. Possible collision event, I do not think this exists
  2. Listen to EntityMoveEvent and calculate this specific motion/check blockfaces on each move. This seems very costly so I do not want to do this, and will require storing previous positions as well to calculate correct movement. I am afraid this will create many false positives and false negatives, it will be very tight algorithm and will not be easy to expand for other cases like this.
  3. Use ByteBuddyAgent to rewrite class for falling blocks at runtime. I am told this is not possible without pre-defined agent via bootstrap or access to the server classloader, which I do not have. I have not been able to do this successfully, my test code fails with no error just silent:

Java:
ByteBuddyAgent.install();
new ByteBuddy()
        .redefine(FallingBlockEntity.class)
        .method(
          ElementMatchers.named("tick")
        )
        .intercept(MethodDelegation.to(FallingFakeBlockEntity.class))
        .make()
        .load(FallingBlockEntity.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Java:
public class FallingFakeBlockEntity {
  public void tick() {
    System.out.println("ticked");
  }
}

Please advise if you have any ideas, I am okay with use of NMS or anything hacky I just can not have bootstrap for server. It must work like normal plugin and ideal I should be able to make it compatible with /reload but this is not requirement.
 
Version Output
1.17+