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

Initial implementation of Entity Interaction Events #183

Draft
wants to merge 21 commits into
base: 1.19
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions library/entity/interaction/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id("qsl.module")
}

qslModule {
name = "Quilt Entity Interaction API"
moduleName = "interaction"
id = "quilt_entity_interaction"
description = "An API to support entity interaction events."
library = "entity"
moduleDependencies {
core {
api("qsl_base")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2022 QuiltMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.quiltmc.qsl.entity.interaction.api;

import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import org.quiltmc.qsl.base.api.event.Event;

/**
* Invoked when an entity damages another entity. Is only invoked on the logical server.
* <p>
* Returning false will cancel further processing and the entity will not take damage.
*/
@FunctionalInterface
public interface LivingEntityAttackCallback {

Event<LivingEntityAttackCallback> EVENT = Event.create(LivingEntityAttackCallback.class,
callbacks -> (attacker, target, source, amount) -> {
for (LivingEntityAttackCallback callback : callbacks) {
boolean result = callback.onAttack(attacker, target, source, amount);

if (!result) return false;
}
return true;
});

/**
* Invoked when an entity damages another entity.
*
* @param attacker the attacking living entity
* @param target the target entity
* @param source the damage source
* @param amount the damage amount
* @return {@code false} to cancel the event and the attacking action,
* otherwise {@code true} to pass to the next listener
*/
boolean onAttack(LivingEntity attacker, Entity target, DamageSource source, float amount);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2016, 2017, 2018, 2019 FabricMC
* Copyright 2022 QuiltMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.quiltmc.qsl.entity.interaction.api.player;

import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.quiltmc.qsl.base.api.event.Event;

/**
* A callback that is invoked if a player attacks (left-clicks) a block.
* <p>
* Is hooked before the spectator check, so make sure to check the player's game mode!
Quplet marked this conversation as resolved.
Show resolved Hide resolved
* <ul>
* <li>{@link ActionResult#SUCCESS} cancels further processing and, on the client, sends a packet to the server.</li>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

linking the class of the packet would be useful! (also in all the other places that have similar docs)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Easy enough to do, but I'm not so sure why that would be helpful. All the packet really does is tell the logical server to process the event on their side.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just lets devs jump around the codebase a little easier, in case they want to look at how the interaction is processed

* <li>{@link ActionResult#PASS} falls back to further processing.</li>
* <li>{@link ActionResult#FAIL} cancels further processing and does not send a packet to the server.</li>
* </ul>
*/
public interface AttackBlockCallback {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is based on the QM name, but I don't like calling it "attacking" a block, because it's really the beginning of a player breaking (destroying) a block.

Would this maybe make more sense if it was part of BreakBlockEvents?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they have different purposes... its kinda hard to describe. The action of left clicking vs the event of breaking.
Break block events to me are designed to be acted upon the block's breaking more than the player's action while this is more the player's action than the block breaking, if that makes any sense.

I'm fine with moving it over tho if people agree it fits better with the block breaking events.


Event<AttackBlockCallback> EVENT = Event.create(AttackBlockCallback.class,
callbacks -> (player, world, hand, pos, direction) -> {
for (AttackBlockCallback callback : callbacks) {
ActionResult result = callback.onAttackBlock(player, world, hand, pos, direction);

if (result != ActionResult.PASS) return result;
}
return ActionResult.PASS;
});

/**
* Invoked if a player attacks (left-clicks) a block.
*
* @param player the player attacking the block
* @param world the world the event is occurring in
* @param hand the hand used
* @param pos the block's position
* @param direction the side of the block hit
* @return {@link ActionResult#SUCCESS} to cancel processing and send a packet to the server,
* {@link ActionResult#PASS} to fall back to further processing,
* {@link ActionResult#FAIL} to cancel further processing
*/
ActionResult onAttackBlock(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction direction);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2016, 2017, 2018, 2019 FabricMC
* Copyright 2022 QuiltMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.quiltmc.qsl.entity.interaction.api.player;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
import org.quiltmc.qsl.base.api.event.Event;

/**
* A callback that is invoked when a Player attacks (left clicks) an entity.
* <p>
* Upon return:
* <ul>
* <li>{@link ActionResult#SUCCESS} cancels further processing and, on the client, sends a packet to the server.</li>
* <li>{@link ActionResult#PASS} falls back to further processing.</li>
* <li>{@link ActionResult#FAIL} cancels further processing and does not send a packet to the server.</li>
* </ul>
*/
@FunctionalInterface
public interface AttackEntityCallback {

Event<AttackEntityCallback> EVENT = Event.create(AttackEntityCallback.class,
callbacks -> (player, world, hand, entity) -> {
for (AttackEntityCallback callback : callbacks) {
ActionResult result = callback.onAttack(player, world, hand, entity);

if (result != ActionResult.PASS) return result;
}
return ActionResult.PASS;
});

/**
* Invoked when a player attacks (left-clicks) an entity.
*
* @param player the interacting player
* @param world the world the event occurs in
* @param hand the hand used
* @param entity the hit entity
* @return {@link ActionResult#SUCCESS} to cancel processing and send packet to the server,
* {@link ActionResult#PASS} to fall back to further processing,
* {@link ActionResult#FAIL} to cancel further processing
*/
ActionResult onAttack(PlayerEntity player, World world, Hand hand, Entity entity);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2016, 2017, 2018, 2019 FabricMC
* Copyright 2022 QuiltMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.quiltmc.qsl.entity.interaction.api.player;

import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.quiltmc.qsl.base.api.event.Event;

import javax.annotation.Nullable;

/**
* Contains events that invoke when a player breaks a block.
*/
public class PlayerBreakBlockEvents {

/**
* Invokes prior to the player breaking a block, so it is cancelable by
* returning false. It is invoked on both the client and server, but the
* client end result will be synced with the server.
*
* <p>
* If any listener cancels the breaking action, the block
* breaking event will be canceled and {@link PlayerBreakBlockEvents#CANCELED}
* will be invoked. If the event is completed,
* {@link PlayerBreakBlockEvents#AFTER} will be invoked.
*/
public static final Event<Before> BEFORE = Event.create(Before.class,
callbacks -> (player, world, pos, state, blockEntity) -> {
for (Before callback : callbacks) {
boolean result = callback.beforePlayerBreakBlock(player, world, pos, state, blockEntity);

if (!result) return false;
}
return true;
});

/**
* Invoked after a block is broken.
*/
public static final Event<After> AFTER = Event.create(After.class,
callbacks -> (player, world, pos, state, blockEntity) -> {
for (After callback : callbacks) {
callback.afterPlayerBreakBlock(player, world, pos, state, blockEntity);
}
});

/**
* Invoked if the block breaking event is canceled.
*/
public static final Event<Cancel> CANCELED = Event.create(Cancel.class,
callbacks -> (player, world, pos, state, blockEntity) -> {
for (Cancel callback : callbacks) {
callback.cancelPlayerBreakBlock(player, world, pos, state, blockEntity);
}
});

@FunctionalInterface
public interface Before {
/**
* Invoked before a block is broken by a player and allows canceling of the action.
* <p>
* Implementations should not assume the block break has succeeded or failed.
*
* @param player the player breaking the block
* @param world the world the block in broken in
* @param pos the position of the block
* @param state the block state <strong>before</strong> the block is broken
* @param blockEntity the block entity <strong>before</strong> the block is broken, can be {@code null}
* @return {@code false} to cancel the event and the block breaking action,
* otherwise {@code true} to pass to the next listener
*/
boolean beforePlayerBreakBlock(PlayerEntity player, World world, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity);
}

@FunctionalInterface
public interface After {
/**
* Invoked after a block has been broken by a player.
*
* @param player the player breaking the block
* @param world the world the block in broken in
* @param pos the position of the block
* @param state the block state <strong>before</strong> the block is broken
* @param blockEntity the block entity <strong>before</strong> the block is broken, can be {@code null}
*/
void afterPlayerBreakBlock(PlayerEntity player, World world, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity);
}

@FunctionalInterface
public interface Cancel {
/**
* Invoked if the block breaking event has been canceled.
*
* @param player the player breaking the block
* @param world the world the block in broken in
* @param pos the position of the block
* @param state the block state <strong>before</strong> the block is broken
* @param blockEntity the block entity <strong>before</strong> the block is broken, can be {@code null}
*/
void cancelPlayerBreakBlock(PlayerEntity player, World world, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2016, 2017, 2018, 2019 FabricMC
* Copyright 2022 QuiltMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.quiltmc.qsl.entity.interaction.api.player;

import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.world.World;
import org.quiltmc.qsl.base.api.event.Event;

/**
* Invoked whenever a player interacts (right clicks) a block.
* <p>
* Upon return:
* <ul>
* <li>{@link ActionResult#SUCCESS} cancels further processing and, on the client, sends a packet to the server.</li>
* <li>{@link ActionResult#PASS} falls back to further processing.</li>
* <li>{@link ActionResult#FAIL} cancels further processing and does not send a packet to the server.</li>
* </ul>
*/
@FunctionalInterface
public interface UseBlockCallback {

Event<UseBlockCallback> EVENT = Event.create(UseBlockCallback.class,
callbacks -> (player, world, hand, hitResult) -> {
for (UseBlockCallback callback : callbacks) {
ActionResult result = callback.onUseBlock(player, world, hand, hitResult);

if (result != ActionResult.PASS) return result;
}
return ActionResult.PASS;
});

/**
* Invoked when a player uses (right-clicks) a block.
*
* @param player the interacting player
* @param world the world the event occurs in
* @param hand the hand used
* @param hitResult the hit result of the interaction
* @return {@link ActionResult#SUCCESS} to cancel processing and send a packet to the server,
* {@link ActionResult#PASS} to fall back to further processing,
* {@link ActionResult#FAIL} to cancel further processing.
*/
ActionResult onUseBlock(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult);
}
Loading