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

Add ExplosionEvent.Knockback event #1017

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions patches/net/minecraft/world/level/Explosion.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@
Vec3 vec3 = new Vec3(this.x, this.y, this.z);

for (Entity entity : list) {
@@ -298,6 +_,7 @@
d7 *= d10;
d9 *= d10;
Vec3 vec31 = new Vec3(d5, d7, d9);
+ vec31 = net.neoforged.neoforge.event.EventHooks.getExplosionKnockback(this.level, this, entity, vec31);
entity.setDeltaMovement(entity.getDeltaMovement().add(vec31));
if (entity instanceof Player) {
Player player = (Player)entity;
17 changes: 17 additions & 0 deletions src/main/java/net/neoforged/neoforge/event/EventHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
import net.neoforged.neoforge.event.level.ChunkTicketLevelUpdatedEvent;
import net.neoforged.neoforge.event.level.ChunkWatchEvent;
import net.neoforged.neoforge.event.level.ExplosionEvent;
import net.neoforged.neoforge.event.level.ExplosionKnockbackEvent;
import net.neoforged.neoforge.event.level.LevelEvent;
import net.neoforged.neoforge.event.level.PistonEvent;
import net.neoforged.neoforge.event.level.SleepFinishedTimeEvent;
Expand Down Expand Up @@ -594,6 +595,22 @@ public static void onExplosionDetonate(Level level, Explosion explosion, List<En
NeoForge.EVENT_BUS.post(new ExplosionEvent.Detonate(level, explosion, list));
}

/**
* To be called when an explosion has calculated the knockback velocity
* but has not yet added the knockback to the entity caught in blast.
*
* @param level The level that the explosion is in
* @param explosion Explosion that is happening
* @param entity The entity caught in the explosion's blast
* @param initialVelocity The explosion calculated velocity for the entity
* @return The new explosion velocity to add to the entity's existing velocity
*/
public static Vec3 getExplosionKnockback(Level level, Explosion explosion, Entity entity, Vec3 initialVelocity) {
ExplosionKnockbackEvent event = new ExplosionKnockbackEvent(level, explosion, entity, initialVelocity);
NeoForge.EVENT_BUS.post(event);
return event.getKnockbackVelocity();
}

public static boolean onCreateWorldSpawn(Level level, ServerLevelData settings) {
return NeoForge.EVENT_BUS.post(new LevelEvent.CreateSpawnPosition(level, settings)).isCanceled();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.event.level;

import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.neoforged.bus.api.ICancellableEvent;
import net.neoforged.neoforge.common.NeoForge;

/**
* ExplosionKnockbackEvent is fired once the explosion has calculated the knockback velocity to add to the entity caught in blast.<br>
* <br>
* This event is not {@link ICancellableEvent}.<br>
* This event does not use {@link HasResult}.<br>
* This event is fired on the {@link NeoForge#EVENT_BUS}.<br>
*/
public class ExplosionKnockbackEvent extends ExplosionEvent {
private final Entity entity;
private Vec3 knockbackVelocity;

public ExplosionKnockbackEvent(Level level, Explosion explosion, Entity entity, Vec3 knockbackVelocity) {
super(level, explosion);
this.entity = entity;
this.knockbackVelocity = knockbackVelocity;
}

/** return the list of blocks affected by the explosion. */
public List<BlockPos> getAffectedBlocks() {
return getExplosion().getToBlow();
}

/** return the entity affected by the explosion knockback. */
public Entity getAffectedEntity() {
return entity;
}

/** return the explosion knockback velocity to apply to entity. */
public Vec3 getKnockbackVelocity() {
return knockbackVelocity;
}

/** Sets the explosion knockback velocity to add to the entity's existing velocity. */
public void setKnockbackVelocity(Vec3 newKnockbackVelocity) {
this.knockbackVelocity = newKnockbackVelocity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package net.neoforged.neoforge.debug.entity;

import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.world.entity.EntityType;
Expand All @@ -13,8 +14,12 @@
import net.minecraft.world.entity.animal.Pig;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.event.entity.EntityAttributeModificationEvent;
import net.neoforged.neoforge.event.entity.EntityTeleportEvent;
import net.neoforged.neoforge.event.level.ExplosionKnockbackEvent;
import net.neoforged.testframework.DynamicTest;
import net.neoforged.testframework.annotation.ForEachTest;
import net.neoforged.testframework.annotation.TestHolder;
Expand Down Expand Up @@ -69,4 +74,23 @@ static void entityAttributeModificationEvent(final DynamicTest test, final Regis
donkey, d -> d.getAttribute(testAttr).getValue(), "test attribute", 1.5D))
.thenSucceed());
}

@GameTest
@EmptyTemplate(value = "15x5x15", floor = true)
@TestHolder(description = "Tests if the pig only gets vertical knockback from explosion knockback event")
static void entityVerticalExplosionKnockbackEvent(final DynamicTest test) {
test.eventListeners().forge().addListener((final ExplosionKnockbackEvent event) -> {
if (event.getAffectedEntity() instanceof Pig) {
event.setKnockbackVelocity(new Vec3(0, event.getKnockbackVelocity().y(), 0));
}
});

test.onGameTest(helper -> helper.startSequence(() -> helper.spawnWithNoFreeWill(EntityType.PIG, 8, 3, 7))
.thenExecute(pig -> helper.setBlock(8, 2, 7, Blocks.ACACIA_LEAVES))
.thenExecute(pig -> helper.getLevel().explode(null, helper.getLevel().damageSources().generic(), null, helper.absolutePos(new BlockPos(7, 2, 7)).getCenter(), 2f, false, Level.ExplosionInteraction.BLOW))
.thenExecute(pig -> helper.assertEntityProperty(pig, p -> pig.getDeltaMovement().x() == 0 && pig.getDeltaMovement().y() != 0 && pig.getDeltaMovement().z() == 0, "Check explosion Knockback"))
.thenIdle(10)
.thenExecute(helper::killAllEntities)
.thenSucceed());
}
}
Loading