shedaniel 4 лет назад
Родитель
Сommit
d2ab1c5110
27 измененных файлов с 608 добавлено и 26 удалено
  1. 4 0
      common/build.gradle
  2. 8 0
      common/src/main/java/me/shedaniel/architectury/ArchitecturyPopulator.java
  3. 18 0
      common/src/main/java/me/shedaniel/architectury/event/events/EntityEvent.java
  4. 19 0
      common/src/main/java/me/shedaniel/architectury/event/events/PlayerEvent.java
  5. 58 0
      common/src/main/java/me/shedaniel/architectury/registry/BlockProperties.java
  6. 9 0
      common/src/main/java/me/shedaniel/architectury/registry/BlockPropertiesExtension.java
  7. 55 0
      common/src/main/java/me/shedaniel/architectury/registry/ToolType.java
  8. 2 0
      common/src/main/resources/architectury-common.accessWidener
  9. 2 1
      common/src/main/resources/fabric.mod.json
  10. 22 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinFurnaceResultSlot.java
  11. 33 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinItemEntity.java
  12. 22 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinLivingEntity.java
  13. 29 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinServerLevel.java
  14. 23 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/PlayerAttackInvoker.java
  15. 10 0
      fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinClientLevel.java
  16. 66 0
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/BlockPropertiesImpl.java
  17. 28 0
      fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ToolTypeImpl.java
  18. 46 1
      fabric/src/main/resources/architectury.accessWidener
  19. 3 2
      fabric/src/main/resources/architectury.mixins.json
  20. 2 2
      forge/build.gradle
  21. 33 4
      forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImpl.java
  22. 7 0
      forge/src/main/java/me/shedaniel/architectury/forge/ArchitecturyForge.java
  23. 2 11
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/ExplosionHooksImpl.java
  24. 1 5
      forge/src/main/java/me/shedaniel/architectury/hooks/forge/ScreenHooksImpl.java
  25. 60 0
      forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockPropertiesImpl.java
  26. 28 0
      forge/src/main/java/me/shedaniel/architectury/registry/forge/ToolTypeImpl.java
  27. 18 0
      forge/src/main/resources/META-INF/accesstransformer.cfg

+ 4 - 0
common/build.gradle

@@ -2,6 +2,10 @@ plugins {
     id "fabric-loom"
 }
 
+loom {
+    accessWidener = file("src/main/resources/architectury-common.accessWidener")
+}
+
 dependencies {
     minecraft "com.mojang:minecraft:${rootProject.architect.minecraft}"
     mappings minecraft.officialMojangMappings()

+ 8 - 0
common/src/main/java/me/shedaniel/architectury/ArchitecturyPopulator.java

@@ -24,6 +24,14 @@ import java.lang.reflect.Modifier;
 public final class ArchitecturyPopulator {
     private ArchitecturyPopulator() {}
     
+    public static void populate() {
+        try {
+            populate(Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()));
+        } catch (Throwable e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
     public static void populate(Object o) {
         try {
             if (o instanceof Class) {

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

@@ -20,15 +20,33 @@ import me.shedaniel.architectury.event.Event;
 import me.shedaniel.architectury.event.EventFactory;
 import net.minecraft.world.InteractionResult;
 import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.level.Level;
 
 public interface EntityEvent {
     /**
      * Invoked before LivingEntity#die, equivalent to forge's {@code LivingDeathEvent}.
      */
     Event<LivingDeath> LIVING_DEATH = EventFactory.createInteractionResult(LivingDeath.class);
+    /**
+     * Invoked before LivingEntity#hurt, equivalent to forge's {@code LivingAttackEvent}.
+     */
+    Event<LivingAttack> LIVING_ATTACK = EventFactory.createInteractionResult(LivingAttack.class);
+    /**
+     * Invoked before entity is added to a world, equivalent to forge's {@code EntityJoinWorldEvent}.
+     */
+    Event<Add> ADD = EventFactory.createInteractionResult(Add.class);
     
     interface LivingDeath {
         InteractionResult die(LivingEntity entity, DamageSource source);
     }
+    
+    interface LivingAttack {
+        InteractionResult attack(LivingEntity entity, DamageSource source, float amount);
+    }
+    
+    interface Add {
+        InteractionResult add(Entity entity, Level world);
+    }
 }

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

@@ -23,6 +23,10 @@ import net.fabricmc.api.Environment;
 import net.minecraft.advancements.Advancement;
 import net.minecraft.client.player.LocalPlayer;
 import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.entity.item.ItemEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.ItemStack;
 
 public interface PlayerEvent {
     Event<PlayerJoin> PLAYER_JOIN = EventFactory.createLoop(PlayerJoin.class);
@@ -33,6 +37,9 @@ public interface PlayerEvent {
     @Environment(EnvType.CLIENT) Event<ClientPlayerRespawn> CLIENT_PLAYER_RESPAWN = EventFactory.createLoop(ClientPlayerRespawn.class);
     Event<PlayerAdvancement> PLAYER_ADVANCEMENT = EventFactory.createLoop(PlayerAdvancement.class);
     Event<PlayerClone> PLAYER_CLONE = EventFactory.createLoop(PlayerClone.class);
+    Event<SmeltItem> SMELT_ITEM = EventFactory.createLoop(SmeltItem.class);
+    Event<PickupItemPredicate> PICKUP_ITEM_PRE = EventFactory.createInteractionResult(PickupItemPredicate.class);
+    Event<PickupItem> PICKUP_ITEM_POST = EventFactory.createLoop(PickupItem.class);
     
     interface PlayerJoin {
         void join(ServerPlayer player);
@@ -54,6 +61,18 @@ public interface PlayerEvent {
         void award(ServerPlayer player, Advancement advancement);
     }
     
+    interface SmeltItem {
+        void smelt(Player player, ItemStack smelted);
+    }
+    
+    interface PickupItemPredicate {
+        InteractionResult canPickup(Player player, ItemEntity entity, ItemStack smelted);
+    }
+    
+    interface PickupItem {
+        void pickup(Player player, ItemEntity entity, ItemStack smelted);
+    }
+    
     @Environment(EnvType.CLIENT)
     interface ClientPlayerJoin {
         void join(LocalPlayer player);

+ 58 - 0
common/src/main/java/me/shedaniel/architectury/registry/BlockProperties.java

@@ -0,0 +1,58 @@
+package me.shedaniel.architectury.registry;
+
+import me.shedaniel.architectury.ArchitecturyPopulator;
+import me.shedaniel.architectury.Populatable;
+import net.minecraft.world.item.DyeColor;
+import net.minecraft.world.level.block.state.BlockBehaviour;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.Material;
+import net.minecraft.world.level.material.MaterialColor;
+
+import java.util.function.Function;
+
+public abstract class BlockProperties extends BlockBehaviour.Properties implements BlockPropertiesExtension {
+    @Populatable
+    private static final Impl IMPL = null;
+    
+    public BlockProperties(Material material, Function<BlockState, MaterialColor> function) {
+        super(material, function);
+    }
+    
+    public static BlockProperties of(Material material) {
+        return of(material, material.getColor());
+    }
+    
+    public static BlockProperties of(Material material, DyeColor color) {
+        return of(material, color.getMaterialColor());
+    }
+    
+    public static BlockProperties of(Material material, MaterialColor color) {
+        return IMPL.of(material, color);
+    }
+    
+    public static BlockProperties of(Material material, Function<BlockState, MaterialColor> color) {
+        return IMPL.of(material, color);
+    }
+    
+    public static BlockProperties copy(BlockBehaviour block) {
+        return IMPL.copy(block);
+    }
+    
+    public static BlockProperties copy(BlockBehaviour.Properties properties) {
+        return IMPL.copy(properties);
+    }
+    
+    public interface Impl {
+        BlockProperties of(Material material, MaterialColor color);
+        
+        BlockProperties of(Material material, Function<BlockState, MaterialColor> color);
+        
+        BlockProperties copy(BlockBehaviour block);
+        
+        BlockProperties copy(BlockBehaviour.Properties properties);
+    }
+    
+    static {
+        ArchitecturyPopulator.populate();
+    }
+}

+ 9 - 0
common/src/main/java/me/shedaniel/architectury/registry/BlockPropertiesExtension.java

@@ -0,0 +1,9 @@
+package me.shedaniel.architectury.registry;
+
+public interface BlockPropertiesExtension {
+    default BlockProperties tool(ToolType type) {
+        return tool(type, 0);
+    }
+    
+    BlockProperties tool(ToolType type, int level);
+}

+ 55 - 0
common/src/main/java/me/shedaniel/architectury/registry/ToolType.java

@@ -0,0 +1,55 @@
+package me.shedaniel.architectury.registry;
+
+import me.shedaniel.architectury.Populatable;
+import net.minecraft.tags.Tag;
+import net.minecraft.world.item.Item;
+
+import java.util.function.Supplier;
+
+public final class ToolType {
+    public static final ToolType PICKAXE = create("pickaxe", ToolType::pickaxeTag);
+    public static final ToolType AXE = create("axe", ToolType::axeTag);
+    public static final ToolType HOE = create("hoe", ToolType::hoeTag);
+    public static final ToolType SHOVEL = create("shovel", ToolType::shovelTag);
+    @Populatable
+    private static final Impl IMPL = null;
+    
+    private static Tag<Item> pickaxeTag() {
+        return IMPL.pickaxeTag();
+    }
+    
+    private static Tag<Item> axeTag() {
+        return IMPL.axeTag();
+    }
+    
+    private static Tag<Item> hoeTag() {
+        return IMPL.hoeTag();
+    }
+    
+    private static Tag<Item> shovelTag() {
+        return IMPL.shovelTag();
+    }
+    
+    public final String forgeName;
+    public final Supplier<Tag<Item>> fabricTag;
+    private Object obj;
+    
+    private ToolType(String forgeName, Supplier<Tag<Item>> fabricTag) {
+        this.forgeName = forgeName;
+        this.fabricTag = fabricTag;
+    }
+    
+    public static ToolType create(String forgeName, Supplier<Tag<Item>> fabricTag) {
+        return new ToolType(forgeName, fabricTag);
+    }
+    
+    public interface Impl {
+        Tag<Item> pickaxeTag();
+        
+        Tag<Item> axeTag();
+        
+        Tag<Item> hoeTag();
+        
+        Tag<Item> shovelTag();
+    }
+}

+ 2 - 0
common/src/main/resources/architectury-common.accessWidener

@@ -0,0 +1,2 @@
+accessWidener v1 named
+accessible method net/minecraft/world/level/block/state/BlockBehaviour$Properties <init> (Lnet/minecraft/world/level/material/Material;Ljava/util/function/Function;)V

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

@@ -2,5 +2,6 @@
   "_comment": "This file is here to make fabric loader load this on the Knot classloader.",
   "schemaVersion": 1,
   "id": "architectury-common",
-  "version": "0.0.1"
+  "version": "0.0.1",
+  "accessWidener": "architectury-common.accessWidener"
 }

+ 22 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinFurnaceResultSlot.java

@@ -0,0 +1,22 @@
+package me.shedaniel.architectury.mixin.fabric;
+
+import me.shedaniel.architectury.event.events.PlayerEvent;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.inventory.FurnaceResultSlot;
+import net.minecraft.world.item.ItemStack;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(FurnaceResultSlot.class)
+public class MixinFurnaceResultSlot {
+    @Shadow @Final private Player player;
+    
+    @Inject(method = "checkTakeAchievements", at = @At("RETURN"))
+    private void checkTakeAchievements(ItemStack itemStack, CallbackInfo ci) {
+        PlayerEvent.SMELT_ITEM.invoker().smelt(player, itemStack);
+    }
+}

+ 33 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinItemEntity.java

@@ -0,0 +1,33 @@
+package me.shedaniel.architectury.mixin.fabric;
+
+import me.shedaniel.architectury.event.events.PlayerEvent;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.entity.item.ItemEntity;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.ItemStack;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(ItemEntity.class)
+public abstract class MixinItemEntity {
+    @Shadow
+    public abstract ItemStack getItem();
+    
+    @Inject(method = "playerTouch",
+            at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getCount()I"), cancellable = true)
+    private void prePickup(Player player, CallbackInfo ci) {
+        InteractionResult canPickUp = PlayerEvent.PICKUP_ITEM_PRE.invoker().canPickup(player, (ItemEntity) (Object) this, getItem());
+        if (canPickUp == InteractionResult.FAIL) {
+            ci.cancel();
+        }
+    }
+    
+    @Inject(method = "playerTouch",
+            at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;take(Lnet/minecraft/world/entity/Entity;I)V"))
+    private void pickup(Player player, CallbackInfo ci) {
+        PlayerEvent.PICKUP_ITEM_POST.invoker().pickup(player, (ItemEntity) (Object) this, getItem());
+    }
+}

+ 22 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinLivingEntity.java

@@ -0,0 +1,22 @@
+package me.shedaniel.architectury.mixin.fabric;
+
+import me.shedaniel.architectury.event.events.EntityEvent;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+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.CallbackInfoReturnable;
+
+@Mixin(LivingEntity.class)
+public class MixinLivingEntity {
+    @Inject(method = "hurt", at = @At("HEAD"), cancellable = true)
+    private void hurt(DamageSource damageSource, float f, CallbackInfoReturnable<Boolean> cir) {
+        if ((Object) this instanceof Player) return;
+        if (EntityEvent.LIVING_ATTACK.invoker().attack((LivingEntity) (Object) this, damageSource, f) == InteractionResult.FAIL) {
+            cir.setReturnValue(false);
+        }
+    }
+}

+ 29 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/MixinServerLevel.java

@@ -16,13 +16,18 @@
 
 package me.shedaniel.architectury.mixin.fabric;
 
+import me.shedaniel.architectury.event.events.EntityEvent;
 import me.shedaniel.architectury.event.events.LifecycleEvent;
 import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
 import net.minecraft.util.ProgressListener;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.entity.Entity;
 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.CallbackInfoReturnable;
 
 @Mixin(ServerLevel.class)
 public class MixinServerLevel {
@@ -30,4 +35,28 @@ public class MixinServerLevel {
     private void save(ProgressListener progressListener, boolean bl, boolean bl2, CallbackInfo ci) {
         LifecycleEvent.SERVER_WORLD_SAVE.invoker().act((ServerLevel) (Object) this);
     }
+    
+    @Inject(method = "addEntity", at = @At(value = "INVOKE",
+                                           target = "Lnet/minecraft/server/level/ServerLevel;getChunk(IILnet/minecraft/world/level/chunk/ChunkStatus;Z)Lnet/minecraft/world/level/chunk/ChunkAccess;"),
+            cancellable = true)
+    private void addEntity(Entity entity, CallbackInfoReturnable<Boolean> cir) {
+        if (EntityEvent.ADD.invoker().add(entity, (ServerLevel) (Object) this) == InteractionResult.FAIL) {
+            cir.setReturnValue(false);
+        }
+    }
+    
+    @Inject(method = "addPlayer", at = @At("HEAD"), cancellable = true)
+    private void addPlayer(ServerPlayer serverPlayer, CallbackInfo ci) {
+        if (EntityEvent.ADD.invoker().add(serverPlayer, (ServerLevel) (Object) this) == InteractionResult.FAIL) {
+            ci.cancel();
+        }
+    }
+    
+    @Inject(method = "loadFromChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;add(Lnet/minecraft/world/entity/Entity;)V"),
+            cancellable = true)
+    private void loadFromChunk(Entity entity, CallbackInfoReturnable<Boolean> cir) {
+        if (EntityEvent.ADD.invoker().add(entity, (ServerLevel) (Object) this) == InteractionResult.FAIL) {
+            cir.setReturnValue(false);
+        }
+    }
 }

+ 23 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/PlayerAttackInvoker.java

@@ -0,0 +1,23 @@
+package me.shedaniel.architectury.mixin.fabric;
+
+import me.shedaniel.architectury.event.events.EntityEvent;
+import net.minecraft.client.player.LocalPlayer;
+import net.minecraft.client.player.RemotePlayer;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.damagesource.DamageSource;
+import net.minecraft.world.entity.LivingEntity;
+import net.minecraft.world.entity.player.Player;
+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.CallbackInfoReturnable;
+
+@Mixin(value = {LocalPlayer.class, Player.class, RemotePlayer.class})
+public class PlayerAttackInvoker {
+    @Inject(method = "hurt", at = @At("HEAD"), cancellable = true)
+    private void hurt(DamageSource damageSource, float f, CallbackInfoReturnable<Boolean> cir) {
+        if (EntityEvent.LIVING_ATTACK.invoker().attack((LivingEntity) (Object) this, damageSource, f) == InteractionResult.FAIL && (Object) this instanceof Player) {
+            cir.setReturnValue(false);
+        }
+    }
+}

+ 10 - 0
fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinClientLevel.java

@@ -16,12 +16,15 @@
 
 package me.shedaniel.architectury.mixin.fabric.client;
 
+import me.shedaniel.architectury.event.events.EntityEvent;
 import me.shedaniel.architectury.event.events.LifecycleEvent;
 import net.minecraft.client.multiplayer.ClientLevel;
 import net.minecraft.client.multiplayer.ClientPacketListener;
 import net.minecraft.client.renderer.LevelRenderer;
 import net.minecraft.resources.ResourceKey;
 import net.minecraft.util.profiling.ProfilerFiller;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.entity.Entity;
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.dimension.DimensionType;
 import org.spongepowered.asm.mixin.Mixin;
@@ -37,4 +40,11 @@ public class MixinClientLevel {
     private void construct(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey<Level> resourceKey, DimensionType dimensionType, int i, Supplier<ProfilerFiller> supplier, LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
         LifecycleEvent.CLIENT_WORLD_LOAD.invoker().act((ClientLevel) (Object) this);
     }
+    
+    @Inject(method = "addEntity", at = @At("HEAD"), cancellable = true)
+    private void addEntity(int i, Entity entity, CallbackInfo ci) {
+        if (EntityEvent.ADD.invoker().add(entity, (ClientLevel) (Object) this) == InteractionResult.FAIL) {
+            ci.cancel();
+        }
+    }
 }

+ 66 - 0
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/BlockPropertiesImpl.java

@@ -0,0 +1,66 @@
+package me.shedaniel.architectury.registry.fabric;
+
+import me.shedaniel.architectury.registry.BlockProperties;
+import me.shedaniel.architectury.registry.ToolType;
+import net.fabricmc.fabric.impl.object.builder.BlockSettingsInternals;
+import net.fabricmc.fabric.impl.object.builder.FabricBlockInternals;
+import net.minecraft.world.level.block.state.BlockBehaviour;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.Material;
+import net.minecraft.world.level.material.MaterialColor;
+
+import java.util.function.Function;
+
+public class BlockPropertiesImpl implements BlockProperties.Impl {
+    @Override
+    public BlockProperties of(Material material, MaterialColor color) {
+        return new Impl(material, (state) -> color);
+    }
+    
+    @Override
+    public BlockProperties of(Material material, Function<BlockState, MaterialColor> color) {
+        return new Impl(material, color);
+    }
+    
+    @Override
+    public BlockProperties copy(BlockBehaviour old) {
+        return copy(old.properties);
+    }
+    
+    @Override
+    public BlockProperties copy(BlockBehaviour.Properties old) {
+        BlockProperties properties = of(old.material, old.materialColor);
+        properties.material = old.material;
+        properties.destroyTime = old.destroyTime;
+        properties.explosionResistance = old.explosionResistance;
+        properties.hasCollision = old.hasCollision;
+        properties.isRandomlyTicking = old.isRandomlyTicking;
+        properties.lightEmission = old.lightEmission;
+        properties.materialColor = old.materialColor;
+        properties.soundType = old.soundType;
+        properties.friction = old.friction;
+        properties.speedFactor = old.speedFactor;
+        properties.dynamicShape = old.dynamicShape;
+        properties.canOcclude = old.canOcclude;
+        properties.isAir = old.isAir;
+        properties.requiresCorrectToolForDrops = old.requiresCorrectToolForDrops;
+        BlockSettingsInternals otherInternals = (BlockSettingsInternals) old;
+        FabricBlockInternals.ExtraData extraData = otherInternals.getExtraData();
+        if (extraData != null) {
+            ((BlockSettingsInternals) this).setExtraData(extraData);
+        }
+        return properties;
+    }
+    
+    private static final class Impl extends BlockProperties {
+        public Impl(Material material, Function<BlockState, MaterialColor> function) {
+            super(material, function);
+        }
+        
+        @Override
+        public BlockProperties tool(ToolType type, int level) {
+            FabricBlockInternals.computeExtraData(this).addMiningLevel(type.fabricTag.get(), level);
+            return this;
+        }
+    }
+}

+ 28 - 0
fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ToolTypeImpl.java

@@ -0,0 +1,28 @@
+package me.shedaniel.architectury.registry.fabric;
+
+import me.shedaniel.architectury.registry.ToolType;
+import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
+import net.minecraft.tags.Tag;
+import net.minecraft.world.item.Item;
+
+public class ToolTypeImpl implements ToolType.Impl {
+    @Override
+    public Tag<Item> pickaxeTag() {
+        return FabricToolTags.PICKAXES;
+    }
+    
+    @Override
+    public Tag<Item> axeTag() {
+        return FabricToolTags.AXES;
+    }
+    
+    @Override
+    public Tag<Item> hoeTag() {
+        return FabricToolTags.HOES;
+    }
+    
+    @Override
+    public Tag<Item> shovelTag() {
+        return FabricToolTags.SHOVELS;
+    }
+}

+ 46 - 1
fabric/src/main/resources/architectury.accessWidener

@@ -1,4 +1,49 @@
 accessWidener v1 named
 accessible method net/minecraft/client/gui/screens/Screen addButton (Lnet/minecraft/client/gui/components/AbstractWidget;)Lnet/minecraft/client/gui/components/AbstractWidget;
 accessible method net/minecraft/client/gui/screens/Screen addWidget (Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener;
-accessible field net/minecraft/client/gui/screens/Screen buttons Ljava/util/List;
+accessible field net/minecraft/client/gui/screens/Screen buttons Ljava/util/List;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour properties Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties material Lnet/minecraft/world/level/material/Material;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties material Lnet/minecraft/world/level/material/Material;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties materialColor Ljava/util/function/Function;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties materialColor Ljava/util/function/Function;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties hasCollision Z
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties hasCollision Z
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties soundType Lnet/minecraft/world/level/block/SoundType;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties soundType Lnet/minecraft/world/level/block/SoundType;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties lightEmission Ljava/util/function/ToIntFunction;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties lightEmission Ljava/util/function/ToIntFunction;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties explosionResistance F
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties explosionResistance F
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties destroyTime F
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties destroyTime F
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties requiresCorrectToolForDrops Z
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties requiresCorrectToolForDrops Z
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties isRandomlyTicking Z
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties isRandomlyTicking Z
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties friction F
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties friction F
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties speedFactor F
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties speedFactor F
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties jumpFactor F
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties jumpFactor F
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties drops Lnet/minecraft/resources/ResourceLocation;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties drops Lnet/minecraft/resources/ResourceLocation;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties canOcclude Z
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties canOcclude Z
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties isAir Z
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties isAir Z
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties isValidSpawn Lnet/minecraft/world/level/block/state/BlockBehaviour$StateArgumentPredicate;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties isValidSpawn Lnet/minecraft/world/level/block/state/BlockBehaviour$StateArgumentPredicate;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties isRedstoneConductor Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties isRedstoneConductor Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties isSuffocating Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties isSuffocating Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties isViewBlocking Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties isViewBlocking Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties hasPostProcess Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties hasPostProcess Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties emissiveRendering Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties emissiveRendering Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;
+accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties dynamicShape Z
+mutable field net/minecraft/world/level/block/state/BlockBehaviour$Properties dynamicShape Z

+ 3 - 2
fabric/src/main/resources/architectury.mixins.json

@@ -12,8 +12,9 @@
     "client.MixinScreen"
   ],
   "mixins": [
-    "ExplosionPreInvoker", "LivingDeathInvoker", "MixinCommands", "MixinExplosion", "MixinPlayer", "MixinPlayerAdvancements", "MixinPlayerList",
-    "MixinServerGamePacketListenerImpl", "MixinServerLevel", "MixinServerPlayer"
+    "ExplosionPreInvoker", "LivingDeathInvoker", "MixinCommands", "MixinExplosion", "MixinFurnaceResultSlot", "MixinItemEntity", "MixinLivingEntity",
+    "MixinPlayer", "MixinPlayerAdvancements", "MixinPlayerList", "MixinServerGamePacketListenerImpl", "MixinServerLevel", "MixinServerPlayer",
+    "PlayerAttackInvoker"
   ],
   "injectors": {
     "defaultRequire": 1

+ 2 - 2
forge/build.gradle

@@ -23,7 +23,7 @@ minecraft {
         client {
             workingDirectory project.file("run")
             mods {
-                examplemod {
+                architectury {
                     source sourceSets.main
                 }
             }
@@ -31,7 +31,7 @@ minecraft {
         server {
             workingDirectory project.file("run")
             mods {
-                examplemod {
+                architectury {
                     source sourceSets.main
                 }
             }

+ 33 - 4
forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImpl.java

@@ -34,13 +34,13 @@ import net.minecraftforge.event.CommandEvent;
 import net.minecraftforge.event.RegisterCommandsEvent;
 import net.minecraftforge.event.ServerChatEvent;
 import net.minecraftforge.event.TickEvent.*;
+import net.minecraftforge.event.entity.EntityJoinWorldEvent;
+import net.minecraftforge.event.entity.living.LivingAttackEvent;
 import net.minecraftforge.event.entity.living.LivingDeathEvent;
 import net.minecraftforge.event.entity.player.AdvancementEvent;
+import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
 import net.minecraftforge.event.entity.player.ItemTooltipEvent;
-import net.minecraftforge.event.entity.player.PlayerEvent.Clone;
-import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent;
-import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedOutEvent;
-import net.minecraftforge.event.entity.player.PlayerEvent.PlayerRespawnEvent;
+import net.minecraftforge.event.entity.player.PlayerEvent.*;
 import net.minecraftforge.event.world.ExplosionEvent.Detonate;
 import net.minecraftforge.event.world.ExplosionEvent.Start;
 import net.minecraftforge.event.world.WorldEvent;
@@ -306,6 +306,35 @@ public class EventHandlerImpl implements EventHandler.Impl {
         public static void event(Detonate event) {
             ExplosionEvent.DETONATE.invoker().explode(event.getWorld(), event.getExplosion(), event.getAffectedEntities());
         }
+        
+        @SubscribeEvent
+        public static void event(LivingAttackEvent event) {
+            if (EntityEvent.LIVING_ATTACK.invoker().attack(event.getEntityLiving(), event.getSource(), event.getAmount()) == ActionResultType.FAIL) {
+                event.setCanceled(true);
+            }
+        }
+        
+        @SubscribeEvent
+        public static void event(EntityJoinWorldEvent event) {
+            if (EntityEvent.ADD.invoker().add(event.getEntity(), event.getWorld()) == ActionResultType.FAIL) {
+                event.setCanceled(true);
+            }
+        }
+        
+        @SubscribeEvent
+        public static void event(ItemSmeltedEvent event) {
+            PlayerEvent.SMELT_ITEM.invoker().smelt(event.getPlayer(), event.getSmelting());
+        }
+        
+        @SubscribeEvent
+        public static void event(EntityItemPickupEvent event) {
+            PlayerEvent.PICKUP_ITEM_PRE.invoker().canPickup(event.getPlayer(), event.getItem(), event.getItem().getItem());
+        }
+        
+        @SubscribeEvent
+        public static void event(ItemPickupEvent event) {
+            PlayerEvent.PICKUP_ITEM_POST.invoker().pickup(event.getPlayer(), event.getOriginalEntity(), event.getStack());
+        }
     }
     
     @OnlyIn(Dist.DEDICATED_SERVER)

+ 7 - 0
forge/src/main/java/me/shedaniel/architectury/forge/ArchitecturyForge.java

@@ -0,0 +1,7 @@
+package me.shedaniel.architectury.forge;
+
+import net.minecraftforge.fml.common.Mod;
+
+@Mod("architectury")
+public class ArchitecturyForge {
+}

+ 2 - 11
forge/src/main/java/me/shedaniel/architectury/hooks/forge/ExplosionHooksImpl.java

@@ -20,7 +20,6 @@ import me.shedaniel.architectury.hooks.ExplosionHooks;
 import net.minecraft.entity.Entity;
 import net.minecraft.util.math.vector.Vector3d;
 import net.minecraft.world.Explosion;
-import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
 
 public class ExplosionHooksImpl implements ExplosionHooks.Impl {
     @Override
@@ -35,19 +34,11 @@ public class ExplosionHooksImpl implements ExplosionHooks.Impl {
     
     @Override
     public float getRadius(Explosion explosion) {
-        try {
-            return (float) ObfuscationReflectionHelper.findField(Explosion.class, "field_77280_f").get(explosion);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
+        return explosion.radius;
     }
     
     @Override
     public void setRadius(Explosion explosion, float v) {
-        try {
-            ObfuscationReflectionHelper.findField(Explosion.class, "field_77280_f").set(explosion, v);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
+        explosion.radius = v;
     }
 }

+ 1 - 5
forge/src/main/java/me/shedaniel/architectury/hooks/forge/ScreenHooksImpl.java

@@ -28,11 +28,7 @@ import java.util.List;
 public class ScreenHooksImpl implements ScreenHooks.Impl {
     @Override
     public List<Widget> getButtons(Screen screen) {
-        try {
-            return (List<Widget>) ObfuscationReflectionHelper.findField(Screen.class, "field_230710_m_").get(screen);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
+        return screen.buttons;
     }
     
     @Override

+ 60 - 0
forge/src/main/java/me/shedaniel/architectury/registry/forge/BlockPropertiesImpl.java

@@ -0,0 +1,60 @@
+package me.shedaniel.architectury.registry.forge;
+
+import me.shedaniel.architectury.registry.BlockProperties;
+import me.shedaniel.architectury.registry.ToolType;
+import net.minecraft.block.AbstractBlock;
+import net.minecraft.block.BlockState;
+import net.minecraft.block.material.Material;
+import net.minecraft.block.material.MaterialColor;
+
+import java.util.function.Function;
+
+public class BlockPropertiesImpl implements BlockProperties.Impl {
+    @Override
+    public BlockProperties of(Material material, MaterialColor materialColor) {
+        return new Impl(material, (state) -> materialColor);
+    }
+    
+    @Override
+    public BlockProperties of(Material material, Function<BlockState, MaterialColor> function) {
+        return new Impl(material, function);
+    }
+    
+    @Override
+    public BlockProperties copy(AbstractBlock abstractBlock) {
+        return copy(abstractBlock.properties);
+    }
+    
+    @Override
+    public BlockProperties copy(AbstractBlock.Properties old) {
+        BlockProperties properties = of(old.material, old.materialColor);
+        properties.material = old.material;
+        properties.destroyTime = old.destroyTime;
+        properties.explosionResistance = old.explosionResistance;
+        properties.hasCollision = old.hasCollision;
+        properties.isRandomlyTicking = old.isRandomlyTicking;
+        properties.lightEmission = old.lightEmission;
+        properties.materialColor = old.materialColor;
+        properties.soundType = old.soundType;
+        properties.friction = old.friction;
+        properties.speedFactor = old.speedFactor;
+        properties.dynamicShape = old.dynamicShape;
+        properties.canOcclude = old.canOcclude;
+        properties.isAir = old.isAir;
+        properties.requiresCorrectToolForDrops = old.requiresCorrectToolForDrops;
+        return properties;
+    }
+    
+    private static final class Impl extends BlockProperties {
+        public Impl(Material material, Function<BlockState, MaterialColor> function) {
+            super(material, function);
+        }
+        
+        @Override
+        public BlockProperties tool(ToolType type, int level) {
+            harvestTool(net.minecraftforge.common.ToolType.get(type.forgeName));
+            harvestLevel(level);
+            return this;
+        }
+    }
+}

+ 28 - 0
forge/src/main/java/me/shedaniel/architectury/registry/forge/ToolTypeImpl.java

@@ -0,0 +1,28 @@
+package me.shedaniel.architectury.registry.forge;
+
+
+import me.shedaniel.architectury.registry.ToolType;
+import net.minecraft.item.Item;
+import net.minecraft.tags.ITag;
+
+public class ToolTypeImpl implements ToolType.Impl {
+    @Override
+    public ITag<Item> pickaxeTag() {
+        return null;
+    }
+    
+    @Override
+    public ITag<Item> axeTag() {
+        return null;
+    }
+    
+    @Override
+    public ITag<Item> hoeTag() {
+        return null;
+    }
+    
+    @Override
+    public ITag<Item> shovelTag() {
+        return null;
+    }
+}

+ 18 - 0
forge/src/main/resources/META-INF/accesstransformer.cfg

@@ -0,0 +1,18 @@
+public net.minecraft.block.AbstractBlock field_235684_aB_ #properties
+public net.minecraft.block.AbstractBlock$Properties <init>(Lnet/minecraft/block/material/Material;Ljava/util/function/Function;)V
+public net.minecraft.block.AbstractBlock$Properties field_200953_a #material
+public net.minecraft.block.AbstractBlock$Properties field_200959_g #destroyTime
+public net.minecraft.block.AbstractBlock$Properties field_200958_f #explosionResistance
+public net.minecraft.block.AbstractBlock$Properties field_200955_c #hasCollision
+public net.minecraft.block.AbstractBlock$Properties field_200960_h #isRandomlyTicking
+public net.minecraft.block.AbstractBlock$Properties field_235803_e_ #lightEmission
+public net.minecraft.block.AbstractBlock$Properties field_235800_b_ #materialColor
+public net.minecraft.block.AbstractBlock$Properties field_200956_d #soundType
+public net.minecraft.block.AbstractBlock$Properties field_200961_i #friction
+public net.minecraft.block.AbstractBlock$Properties field_226893_j_ #speedFactor
+public net.minecraft.block.AbstractBlock$Properties field_208772_j #dynamicShape
+public net.minecraft.block.AbstractBlock$Properties field_226895_m_ #canOcclude
+public net.minecraft.block.AbstractBlock$Properties field_235813_o_ #isAir
+public net.minecraft.block.AbstractBlock$Properties field_235806_h_ #requiresCorrectToolForDrops
+public-f net.minecraft.world.Explosion field_77280_f #radius
+public net.minecraft.client.gui.screen.Screen field_230710_m_ #buttons