Add LightningEvent, FallingBlock land, move break/place to BlockEvent

This commit is contained in:
Max
2021-02-15 18:15:03 +01:00
parent 35dfe7ccbc
commit b78cce58ee
14 changed files with 201 additions and 20 deletions

View File

@@ -20,6 +20,9 @@
package me.shedaniel.architectury.event;
import me.shedaniel.architectury.annotations.ExpectPlatform;
import me.shedaniel.architectury.event.events.BlockEvent;
import me.shedaniel.architectury.event.events.EntityEvent;
import me.shedaniel.architectury.event.events.PlayerEvent;
import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.utils.Env;
import net.fabricmc.api.EnvType;
@@ -38,6 +41,8 @@ public final class EventHandler {
registerCommon();
if (Platform.getEnvironment() == Env.SERVER)
registerServer();
registerDelegates();
}
@ExpectPlatform
@@ -56,4 +61,10 @@ public final class EventHandler {
private static void registerServer() {
throw new AssertionError();
}
@SuppressWarnings("deprecation")
private static void registerDelegates() {
BlockEvent.PLACE.register((EntityEvent.PLACE_BLOCK.invoker()::placeBlock));
BlockEvent.BREAK.register((PlayerEvent.BREAK_BLOCK.invoker()::breakBlock));
}
}

View File

@@ -0,0 +1,44 @@
package me.shedaniel.architectury.event.events;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import me.shedaniel.architectury.utils.IntValue;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
public interface BlockEvent {
// Block interaction events
/**
* Called when a player breaks a block.
*/
Event<Break> BREAK = EventFactory.createInteractionResult();
/**
* Called when a block is placed in the world by an entity.
*/
Event<Place> PLACE = EventFactory.createInteractionResult();
/**
* Called when a falling block (sand, anvil, etc.) is about to land.
* Use fallState#getBlock to get the type of block for more granular control.
*/
Event<FallingLand> FALLING_LAND = EventFactory.createLoop();
interface Break {
InteractionResult breakBlock(Level world, BlockPos pos, BlockState state, ServerPlayer player, @Nullable IntValue xp);
}
interface Place {
InteractionResult placeBlock(Level world, BlockPos pos, BlockState state, @Nullable Entity placer);
}
interface FallingLand {
void onLand(Level level, BlockPos pos, BlockState fallState, BlockState landOn, FallingBlockEntity entity);
}
}

View File

@@ -28,6 +28,7 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
public interface EntityEvent {
@@ -43,6 +44,12 @@ public interface EntityEvent {
* Invoked before entity is added to a world, equivalent to forge's {@code EntityJoinWorldEvent}.
*/
Event<Add> ADD = EventFactory.createInteractionResult();
/**
* @deprecated use {@link BlockEvent#PLACE}
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
Event<PlaceBlock> PLACE_BLOCK = EventFactory.createInteractionResult();
interface LivingDeath {

View File

@@ -0,0 +1,26 @@
package me.shedaniel.architectury.event.events;
import me.shedaniel.architectury.event.Event;
import me.shedaniel.architectury.event.EventFactory;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import java.util.List;
public interface LightningEvent {
// TODO Pre - Called before a lightning bolt entity is added to the world. (cancellable)
/**
* Invoked after the lightning has gathered a list of entities to strike.
* Remove entities from the list to stop them from being hit.
*/
Event<Strike> STRIKE = EventFactory.createLoop();
// TODO Post - Called before a lightning bolt entity is removed from the world.
interface Strike {
void onStrike(LightningBolt bolt, Level level, Vec3 pos, List<Entity> toStrike);
}
}

View File

@@ -34,6 +34,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
public interface PlayerEvent {
@@ -50,6 +51,12 @@ public interface PlayerEvent {
Event<DropItem> DROP_ITEM = EventFactory.createLoop();
Event<OpenMenu> OPEN_MENU = EventFactory.createLoop();
Event<CloseMenu> CLOSE_MENU = EventFactory.createLoop();
/**
* @deprecated use {@link BlockEvent#BREAK}
*/
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.0")
Event<BreakBlock> BREAK_BLOCK = EventFactory.createInteractionResult();
interface PlayerJoin {

View File

@@ -0,0 +1,29 @@
package me.shedaniel.architectury.mixin;
import me.shedaniel.architectury.event.events.BlockEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.item.FallingBlockEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.FallingBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(FallingBlock.class)
public abstract class MixinFallingBlock extends Block {
public MixinFallingBlock(Properties properties) {
super(properties);
throw new IllegalStateException();
}
@Inject(method = "onLand", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD)
public void handleLand(Level level, BlockPos pos, BlockState fallState, BlockState landOn, FallingBlockEntity entity, CallbackInfo ci) {
BlockEvent.FALLING_LAND.invoker().onLand(level, pos, fallState, landOn, entity);
}
}

View File

@@ -0,0 +1,39 @@
package me.shedaniel.architectury.mixin;
import me.shedaniel.architectury.event.events.LightningEvent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.List;
@Mixin(LightningBolt.class)
public abstract class MixinLightningBolt extends Entity {
public MixinLightningBolt(EntityType<?> type, Level level) {
super(type, level);
throw new IllegalStateException();
}
@Inject(method = "tick", at = @At(
value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/level/Level;getEntities(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;)Ljava/util/List;",
ordinal = 0,
shift = At.Shift.BY,
by = 1
), locals = LocalCapture.CAPTURE_FAILHARD)
public void handleLightning(CallbackInfo ci, double d0, List<Entity> list) {
if (this.removed || this.level.isClientSide) {
return;
}
LightningEvent.STRIKE.invoker().onStrike((LightningBolt) (Object) this, this.level, this.position(), list);
}
}

View File

@@ -0,0 +1,16 @@
{
"required": true,
"package": "me.shedaniel.architectury.mixin",
"compatibilityLevel": "JAVA_8",
"minVersion": "0.7.11",
"client": [
],
"mixins": [
"MixinFallingBlock",
"MixinLightningBolt"
],
"injectors": {
"maxShiftBy": 5,
"defaultRequire": 1
}
}

View File

@@ -19,7 +19,7 @@
package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.event.events.EntityEvent;
import me.shedaniel.architectury.event.events.BlockEvent;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.context.BlockPlaceContext;
@@ -35,9 +35,9 @@ public abstract class MixinBlockItem {
target = "Lnet/minecraft/world/item/context/BlockPlaceContext;getClickedPos()Lnet/minecraft/core/BlockPos;"),
cancellable = true)
private void place(BlockPlaceContext context, CallbackInfoReturnable<InteractionResult> cir) {
InteractionResult result = EntityEvent.PLACE_BLOCK.invoker().placeBlock(context.getLevel(), context.getClickedPos(), context.getLevel().getBlockState(context.getClickedPos()), context.getPlayer());
InteractionResult result = BlockEvent.PLACE.invoker().placeBlock(context.getLevel(), context.getClickedPos(), context.getLevel().getBlockState(context.getClickedPos()), context.getPlayer());
if (result != InteractionResult.PASS) {
cir.setReturnValue(result);
}
}
}
}

View File

@@ -19,7 +19,7 @@
package me.shedaniel.architectury.mixin.fabric;
import me.shedaniel.architectury.event.events.PlayerEvent;
import me.shedaniel.architectury.event.events.BlockEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -44,7 +44,7 @@ public class MixinServerPlayerGameMode {
ordinal = 0),
locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
private void onBreak(BlockPos blockPos, CallbackInfoReturnable<Boolean> cir, BlockState state) {
if (PlayerEvent.BREAK_BLOCK.invoker().breakBlock(this.level, blockPos, state, this.player, null) == InteractionResult.FAIL) {
if (BlockEvent.BREAK.invoker().breakBlock(this.level, blockPos, state, this.player, null) == InteractionResult.FAIL) {
cir.setReturnValue(false);
}
}

View File

@@ -10,6 +10,7 @@
"license": "LGPL-3",
"environment": "*",
"mixins": [
"architectury-common.mixins.json",
"architectury.mixins.json"
],
"entrypoints": {
@@ -30,4 +31,4 @@
"custom": {
"modmenu:api": true
}
}
}

View File

@@ -4,7 +4,7 @@ plugins {
}
loom {
mixinConfig = "architectury.mixins.json"
mixinConfigs = ["architectury.mixins.json", "architectury-common.mixins.json"]
}
configurations {

View File

@@ -44,7 +44,8 @@ import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
import net.minecraftforge.event.entity.player.PlayerEvent.*;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.BlockEvent.BreakEvent;
import net.minecraftforge.event.world.BlockEvent.EntityPlaceEvent;
import net.minecraftforge.event.world.ExplosionEvent.Detonate;
import net.minecraftforge.event.world.ExplosionEvent.Start;
import net.minecraftforge.event.world.WorldEvent;
@@ -288,9 +289,9 @@ public class EventHandlerImplCommon {
}
@SubscribeEvent
public static void event(BlockEvent.BreakEvent event) {
public static void event(BreakEvent event) {
if (event.getPlayer() instanceof ServerPlayer && event.getWorld() instanceof Level) {
InteractionResult result = PlayerEvent.BREAK_BLOCK.invoker().breakBlock((Level) event.getWorld(), event.getPos(), event.getState(), (ServerPlayer) event.getPlayer(), new IntValue() {
InteractionResult result = BlockEvent.BREAK.invoker().breakBlock((Level) event.getWorld(), event.getPos(), event.getState(), (ServerPlayer) event.getPlayer(), new IntValue() {
@Override
public int getAsInt() {
return event.getExpToDrop();
@@ -308,9 +309,9 @@ public class EventHandlerImplCommon {
}
@SubscribeEvent
public static void event(BlockEvent.EntityPlaceEvent event) {
public static void event(EntityPlaceEvent event) {
if (event.getWorld() instanceof Level) {
InteractionResult result = EntityEvent.PLACE_BLOCK.invoker().placeBlock((Level) event.getWorld(), event.getPos(), event.getState(), event.getEntity());
InteractionResult result = BlockEvent.PLACE.invoker().placeBlock((Level) event.getWorld(), event.getPos(), event.getState(), event.getEntity());
if (result != InteractionResult.PASS) {
event.setCanceled(true);
}

View File

@@ -49,6 +49,14 @@ public class DebugEvents {
}
public static void debugEvents() {
BlockEvent.BREAK.register((world, pos, state, player, xp) -> {
SINK.accept(player.getScoreboardName() + " breaks " + toShortString(pos) + logSide(player.level));
return InteractionResult.PASS;
});
BlockEvent.PLACE.register((world, pos, state, placer) -> {
SINK.accept(Optional.ofNullable(placer).map(Entity::getScoreboardName).orElse("null") + " places block at " + toShortString(pos) + logSide(world));
return InteractionResult.PASS;
});
ChatEvent.SERVER.register((player, message, component) -> {
SINK.accept("Server chat received: " + message);
return InteractionResultHolder.pass(component);
@@ -78,10 +86,6 @@ public class DebugEvents {
}
return InteractionResult.PASS;
});
EntityEvent.PLACE_BLOCK.register((world, pos, state, placer) -> {
SINK.accept(Optional.ofNullable(placer).map(Entity::getScoreboardName).orElse("null") + " places block at " + toShortString(pos) + logSide(world));
return InteractionResult.PASS;
});
ExplosionEvent.DETONATE.register((world, explosion, affectedEntities) -> {
SINK.accept(world.dimension().location() + " explodes at " + toShortString(ExplosionHooks.getPosition(explosion)) + logSide(world));
});
@@ -155,10 +159,6 @@ public class DebugEvents {
SINK.accept(player.getScoreboardName() + " drops " + new TranslatableComponent(entity.getItem().getDescriptionId()).getString() + logSide(player.level));
return InteractionResult.PASS;
});
PlayerEvent.BREAK_BLOCK.register((world, pos, state, player, xp) -> {
SINK.accept(player.getScoreboardName() + " breaks " + toShortString(pos) + logSide(player.level));
return InteractionResult.PASS;
});
PlayerEvent.OPEN_MENU.register((player, menu) -> {
SINK.accept(player.getScoreboardName() + " opens " + toSimpleName(menu) + logSide(player.level));
});