Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: raycasting api #2077

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

DeidaraMC
Copy link
Collaborator

A raycasting API integrated into Minestom.

The design philosophy behind this API is to collect as much information as possible from the raycast, then give the user tools in the resulting CastResult to easily grab the information they need.

Cast a Ray against blocks, entities, or both simultaneously with an additional Configuration option to apply filters and more.

Code examples:

// Grab the entities the ray intersected before it collided with a block
MinecraftServer.getGlobalEventHandler().addListener(PlayerUseItemEvent.class, e -> {
    Player player = e.getPlayer();
    Instance instance = e.getInstance();
    Pos pos = player.getPosition();

    // origin, direction, distance
    Ray ray = new Ray(pos.add(0, player.getEyeHeight(), 0), pos.direction(), 16, config -> {
        config.blockFilter(Block::isSolid);
        config.entityFilter(entity -> !(entity instanceof Player));
    });

    EntityBlockCastResult result = ray.cast(instance, instance.getEntities());
    result.findEntitiesBeforeBlockCollision().forEach(collision -> {
        //do something with collision.entity()
    });
}

// Shoot a flame at the point of ray intersection for each block, moving in the
// the direction of the surface normals
MinecraftServer.getGlobalEventHandler().addListener(PlayerUseItemEvent.class, e -> {
    Player player = e.getPlayer();
    Instance instance = e.getInstance();
    Pos pos = player.getPosition();

    Ray ray = new Ray(pos.add(0, player.getEyeHeight(), 0), pos.direction(), 16, config -> config.blockFilter(Block::isSolid));
    BlockCastResult result = ray.cast(instance);
    result.blockCollisions().forEach(collision -> {
        ParticlePacket entryFlame = new ParticlePacket(Particle.FLAME, collision.entry(), collision.entrySurfaceNormal(), 1, 0);
        ParticlePacket exitFlame = new ParticlePacket(Particle.SOUL_FIRE_FLAME, collision.exit(), collision.exitSurfaceNormal(), 1, 0);
        player.sendPacket(entryFlame);
        player.sendPacket(exitFlame);
    });
}

@Tofaa2
Copy link

Tofaa2 commented Apr 2, 2024

Is there a reason it takes an instance and the instance entities? It can be accessed by the method itself

@DeidaraMC
Copy link
Collaborator Author

Is there a reason it takes an instance and the instance entities? It can be accessed by the method itself

It takes any Block.Getter and any Collection<Entity>
This helps with making the API more versatile (preprocessing your list of entities when needed for example), take a look at the Ray record, depending on the cast method used you get a different interface back

@TogAr2
Copy link
Contributor

TogAr2 commented Apr 2, 2024

Are you aware there is already some raycasting done in Minestom physics (to check for collisions)? See EntityCollision and BlockCollision classes. I agree exposing things in an API could be helpful, but maybe it's better to adapt some of the existing code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants