Skip to content

Commit

Permalink
Add ExplosionKnockbackEvent (#1017)
Browse files Browse the repository at this point in the history
  • Loading branch information
TelepathicGrunt authored Jun 5, 2024
1 parent a97bfc7 commit af94732
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
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 @@ -164,6 +164,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 @@ -598,6 +599,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());
}
}

0 comments on commit af94732

Please sign in to comment.