Pārlūkot izejas kodu

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

Max 4 gadi atpakaļ
vecāks
revīzija
b78cce58ee

+ 11 - 0
common/src/main/java/me/shedaniel/architectury/event/EventHandler.java

@@ -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));
+    }
 }

+ 44 - 0
common/src/main/java/me/shedaniel/architectury/event/events/BlockEvent.java

@@ -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);
+    }
+}

+ 7 - 0
common/src/main/java/me/shedaniel/architectury/event/events/EntityEvent.java

@@ -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 {

+ 26 - 0
common/src/main/java/me/shedaniel/architectury/event/events/LightningEvent.java

@@ -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);
+    }
+    
+}

+ 7 - 0
common/src/main/java/me/shedaniel/architectury/event/events/PlayerEvent.java

@@ -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 {

+ 29 - 0
common/src/main/java/me/shedaniel/architectury/mixin/MixinFallingBlock.java

@@ -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);
+    }
+    
+}

+ 39 - 0
common/src/main/java/me/shedaniel/architectury/mixin/MixinLightningBolt.java

@@ -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);
+    }
+    
+}

+ 16 - 0
common/src/main/resources/architectury-common.mixins.json

@@ -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
+    }
+}

+ 3 - 3
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinBlockItem.java

@@ -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);
         }
     }
-}
+}

+ 2 - 2
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinServerPlayerGameMode.java

@@ -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);
         }
     }

+ 2 - 1
fabric/src/main/resources/fabric.mod.json

@@ -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
   }
-}
+}

+ 1 - 1
forge/build.gradle

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

+ 6 - 5
forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplCommon.java

@@ -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);
             }

+ 8 - 8
testmod-common/src/main/java/me/shedaniel/architectury/test/events/DebugEvents.java

@@ -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));
         });