From baccad6a9566e943093b085ddc14b5e241d5cb52 Mon Sep 17 00:00:00 2001
From: Adrian Siekierka <kontakt@asie.pl>
Date: Fri, 30 Nov 2018 11:57:58 +0100
Subject: [PATCH] add ToolManager

---
 .../render/BlockEntityRendererRegistry.java   |   4 +-
 .../client/render/EntityRendererRegistry.java |  10 +-
 .../fabric/helpers/FabricBlockBuilder.java    |   1 +
 .../mixin/registry/MixinWorldSaveHandler.java |  12 +-
 .../render/MixinBlockEntityRenderManager.java |   8 +-
 .../render/MixinEntityRenderManager.java      |   8 +-
 .../fabric/mixin/tools/MixinItemStack.java    |  56 ++++++++++
 .../mixin/tools/MixinMiningToolItem.java      |  33 ++++++
 .../fabric/registry/RegistrySyncManager.java  |  18 +--
 .../BootstrapBlockRegistryListener.java       |   1 -
 .../resources/ModDirectoryResourcePack.java   |  13 +++
 .../fabric/resources/ModResourcePackUtil.java |  10 +-
 .../fabric/resources/ModZipResourcePack.java  |  14 ++-
 .../fabricmc/fabric/tags/FabricItemTags.java  |  34 ++++++
 .../fabric/tools/MiningToolDelegate.java      |  21 ++++
 .../fabricmc/fabric/tools/ToolManager.java    | 103 ++++++++++++++++++
 .../net/fabricmc/fabric/util/TriState.java    |  31 ++++++
 .../data/fabric/tags/items/axes.json          |  10 ++
 .../data/fabric/tags/items/hoes.json          |  10 ++
 .../data/fabric/tags/items/pickaxes.json      |  10 ++
 .../data/fabric/tags/items/shovels.json       |  10 ++
 .../data/fabric/tags/items/swords.json        |  10 ++
 .../net.fabricmc.fabric.mixins.common.json    |   4 +-
 23 files changed, 396 insertions(+), 35 deletions(-)
 create mode 100644 src/main/java/net/fabricmc/fabric/mixin/tools/MixinItemStack.java
 create mode 100644 src/main/java/net/fabricmc/fabric/mixin/tools/MixinMiningToolItem.java
 create mode 100644 src/main/java/net/fabricmc/fabric/tags/FabricItemTags.java
 create mode 100644 src/main/java/net/fabricmc/fabric/tools/MiningToolDelegate.java
 create mode 100644 src/main/java/net/fabricmc/fabric/tools/ToolManager.java
 create mode 100644 src/main/java/net/fabricmc/fabric/util/TriState.java
 create mode 100644 src/main/resources/data/fabric/tags/items/axes.json
 create mode 100644 src/main/resources/data/fabric/tags/items/hoes.json
 create mode 100644 src/main/resources/data/fabric/tags/items/pickaxes.json
 create mode 100644 src/main/resources/data/fabric/tags/items/shovels.json
 create mode 100644 src/main/resources/data/fabric/tags/items/swords.json

diff --git a/src/main/java/net/fabricmc/fabric/client/render/BlockEntityRendererRegistry.java b/src/main/java/net/fabricmc/fabric/client/render/BlockEntityRendererRegistry.java
index 5596ca10f..b80462a01 100644
--- a/src/main/java/net/fabricmc/fabric/client/render/BlockEntityRendererRegistry.java
+++ b/src/main/java/net/fabricmc/fabric/client/render/BlockEntityRendererRegistry.java
@@ -17,7 +17,7 @@
 package net.fabricmc.fabric.client.render;
 
 import net.minecraft.block.entity.BlockEntity;
-import net.minecraft.client.render.block.entity.BlockEntityRenderManager;
+import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
 import net.minecraft.client.render.block.entity.BlockEntityRenderer;
 
 import java.util.Map;
@@ -41,6 +41,6 @@ public class BlockEntityRendererRegistry {
 	public void register(Class<? extends BlockEntity> blockEntityClass, BlockEntityRenderer<? extends BlockEntity> blockEntityRenderer) {
 		// TODO: warn on duplicate
 		blockEntityRenderers.put(blockEntityClass, blockEntityRenderer);
-		blockEntityRenderer.setRenderManager(BlockEntityRenderManager.instance);
+		blockEntityRenderer.setRenderManager(BlockEntityRenderDispatcher.INSTANCE);
 	}
 }
diff --git a/src/main/java/net/fabricmc/fabric/client/render/EntityRendererRegistry.java b/src/main/java/net/fabricmc/fabric/client/render/EntityRendererRegistry.java
index 2fe87d3b1..dbbb9914c 100644
--- a/src/main/java/net/fabricmc/fabric/client/render/EntityRendererRegistry.java
+++ b/src/main/java/net/fabricmc/fabric/client/render/EntityRendererRegistry.java
@@ -16,7 +16,7 @@
 
 package net.fabricmc.fabric.client.render;
 
-import net.minecraft.client.render.entity.EntityRenderManager;
+import net.minecraft.client.render.entity.EntityRenderDispatcher;
 import net.minecraft.client.render.entity.EntityRenderer;
 import net.minecraft.client.render.item.ItemRenderer;
 import net.minecraft.client.texture.TextureManager;
@@ -30,7 +30,7 @@ import java.util.function.Function;
 public class EntityRendererRegistry {
 	@FunctionalInterface
 	public interface Factory {
-		EntityRenderer<? extends Entity> create(EntityRenderManager manager, EntityRendererRegistry.Context context);
+		EntityRenderer<? extends Entity> create(EntityRenderDispatcher manager, EntityRendererRegistry.Context context);
 	}
 
 	public static final class Context {
@@ -54,14 +54,14 @@ public class EntityRendererRegistry {
 	}
 
 	public static final EntityRendererRegistry INSTANCE = new EntityRendererRegistry();
-	private final Map<EntityRenderManager, Context> renderManagerMap = new WeakHashMap<>();
+	private final Map<EntityRenderDispatcher, Context> renderManagerMap = new WeakHashMap<>();
 	private final Map<Class<? extends Entity>, EntityRendererRegistry.Factory> renderSupplierMap = new HashMap<>();
 
 	private EntityRendererRegistry() {
 
 	}
 
-	public void initialize(EntityRenderManager manager, TextureManager textureManager, ItemRenderer itemRenderer, Map<Class<? extends Entity>, EntityRenderer<? extends Entity>> map) {
+	public void initialize(EntityRenderDispatcher manager, TextureManager textureManager, ItemRenderer itemRenderer, Map<Class<? extends Entity>, EntityRenderer<? extends Entity>> map) {
 		synchronized (renderSupplierMap) {
 			if (renderManagerMap.containsKey(manager)) {
 				return;
@@ -79,7 +79,7 @@ public class EntityRendererRegistry {
 		synchronized (renderSupplierMap) {
 			// TODO: warn on duplicate
 			renderSupplierMap.put(entityClass, factory);
-			for (EntityRenderManager manager : renderManagerMap.keySet()) {
+			for (EntityRenderDispatcher manager : renderManagerMap.keySet()) {
 				renderManagerMap.get(manager).rendererMap.put(entityClass, factory.create(manager, renderManagerMap.get(manager)));
 			}
 		}
diff --git a/src/main/java/net/fabricmc/fabric/helpers/FabricBlockBuilder.java b/src/main/java/net/fabricmc/fabric/helpers/FabricBlockBuilder.java
index 6c894cb76..e6c8e4a03 100644
--- a/src/main/java/net/fabricmc/fabric/helpers/FabricBlockBuilder.java
+++ b/src/main/java/net/fabricmc/fabric/helpers/FabricBlockBuilder.java
@@ -16,6 +16,7 @@
 
 package net.fabricmc.fabric.helpers;
 
+import net.fabricmc.fabric.tools.ToolManager;
 import net.minecraft.block.Block;
 import net.minecraft.block.Material;
 import net.minecraft.sound.BlockSoundGroup;
diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinWorldSaveHandler.java b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinWorldSaveHandler.java
index 6db14e64f..1d7105341 100644
--- a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinWorldSaveHandler.java
+++ b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinWorldSaveHandler.java
@@ -18,8 +18,8 @@ package net.fabricmc.fabric.mixin.registry;
 
 import net.fabricmc.fabric.registry.RegistrySyncManager;
 import net.fabricmc.fabric.registry.RemapException;
-import net.minecraft.nbt.TagCompound;
-import net.minecraft.nbt.TagStorageHelper;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.NbtIo;
 import net.minecraft.world.OldWorldSaveHandler;
 import net.minecraft.world.level.LevelProperties;
 import org.apache.logging.log4j.Logger;
@@ -42,13 +42,13 @@ public class MixinWorldSaveHandler {
 	private static Logger LOGGER;
 	@Shadow
 	public File worldDir;
-	private TagCompound lastSavedIdMap = null;
+	private CompoundTag lastSavedIdMap = null;
 
 	private boolean readWorldIdMap(File file) {
 		try {
 			if (file.exists()) {
 				FileInputStream fileInputStream = new FileInputStream(file);
-				TagCompound tag = TagStorageHelper.readCompoundTagCompressed(fileInputStream);
+				CompoundTag tag = NbtIo.readCompressed(fileInputStream);
 				fileInputStream.close();
 				if (tag != null) {
 					RegistrySyncManager.apply(tag, true);
@@ -80,7 +80,7 @@ public class MixinWorldSaveHandler {
 			}
 		}
 
-		TagCompound newIdMap = RegistrySyncManager.toTag(false);
+		CompoundTag newIdMap = RegistrySyncManager.toTag(false);
 		if (!newIdMap.equals(lastSavedIdMap)) {
 			for (int i = ID_REGISTRY_BACKUPS - 1; i >= 0; i--) {
 				File file = getWorldIdMapFile(i);
@@ -96,7 +96,7 @@ public class MixinWorldSaveHandler {
 
 			try {
 				FileOutputStream fileOutputStream = new FileOutputStream(getWorldIdMapFile(0));
-				TagStorageHelper.writeCompoundTagCompressed(newIdMap, fileOutputStream);
+				NbtIo.writeCompressed(newIdMap, fileOutputStream);
 				fileOutputStream.close();
 			} catch (IOException e) {
 				e.printStackTrace();
diff --git a/src/main/java/net/fabricmc/fabric/mixin/render/MixinBlockEntityRenderManager.java b/src/main/java/net/fabricmc/fabric/mixin/render/MixinBlockEntityRenderManager.java
index 51696f5ed..61adab581 100644
--- a/src/main/java/net/fabricmc/fabric/mixin/render/MixinBlockEntityRenderManager.java
+++ b/src/main/java/net/fabricmc/fabric/mixin/render/MixinBlockEntityRenderManager.java
@@ -18,7 +18,7 @@ package net.fabricmc.fabric.mixin.render;
 
 import net.fabricmc.fabric.client.render.BlockEntityRendererRegistry;
 import net.minecraft.block.entity.BlockEntity;
-import net.minecraft.client.render.block.entity.BlockEntityRenderManager;
+import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
 import net.minecraft.client.render.block.entity.BlockEntityRenderer;
 import org.spongepowered.asm.mixin.Mixin;
 import org.spongepowered.asm.mixin.Shadow;
@@ -28,13 +28,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 
 import java.util.Map;
 
-@Mixin(BlockEntityRenderManager.class)
+@Mixin(BlockEntityRenderDispatcher.class)
 public class MixinBlockEntityRenderManager {
 	@Shadow
-	private Map<Class<? extends BlockEntity>, BlockEntityRenderer<? extends BlockEntity>> blockEntityRenderers;
+	private Map<Class<? extends BlockEntity>, BlockEntityRenderer<? extends BlockEntity>> renderers;
 
 	@Inject(method = "<init>()V", at = @At("RETURN"))
 	public void init(CallbackInfo info) {
-		BlockEntityRendererRegistry.INSTANCE.initialize(blockEntityRenderers);
+		BlockEntityRendererRegistry.INSTANCE.initialize(renderers);
 	}
 }
diff --git a/src/main/java/net/fabricmc/fabric/mixin/render/MixinEntityRenderManager.java b/src/main/java/net/fabricmc/fabric/mixin/render/MixinEntityRenderManager.java
index c47ff5efb..7b7d80ec6 100644
--- a/src/main/java/net/fabricmc/fabric/mixin/render/MixinEntityRenderManager.java
+++ b/src/main/java/net/fabricmc/fabric/mixin/render/MixinEntityRenderManager.java
@@ -17,7 +17,7 @@
 package net.fabricmc.fabric.mixin.render;
 
 import net.fabricmc.fabric.client.render.EntityRendererRegistry;
-import net.minecraft.client.render.entity.EntityRenderManager;
+import net.minecraft.client.render.entity.EntityRenderDispatcher;
 import net.minecraft.client.render.entity.EntityRenderer;
 import net.minecraft.client.render.item.ItemRenderer;
 import net.minecraft.client.texture.TextureManager;
@@ -30,13 +30,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 
 import java.util.Map;
 
-@Mixin(EntityRenderManager.class)
+@Mixin(EntityRenderDispatcher.class)
 public class MixinEntityRenderManager {
 	@Shadow
-	private Map<Class<? extends Entity>, EntityRenderer<? extends Entity>> RENDER_MAP;
+	private Map<Class<? extends Entity>, EntityRenderer<? extends Entity>> renderers;
 
 	@Inject(method = "<init>(Lnet/minecraft/client/texture/TextureManager;Lnet/minecraft/client/render/item/ItemRenderer;)V", at = @At("RETURN"))
 	public void init(TextureManager textureManager, ItemRenderer itemRenderer, CallbackInfo info) {
-		EntityRendererRegistry.INSTANCE.initialize((EntityRenderManager) (Object) this, textureManager, itemRenderer, RENDER_MAP);
+		EntityRendererRegistry.INSTANCE.initialize((EntityRenderDispatcher) (Object) this, textureManager, itemRenderer, renderers);
 	}
 }
diff --git a/src/main/java/net/fabricmc/fabric/mixin/tools/MixinItemStack.java b/src/main/java/net/fabricmc/fabric/mixin/tools/MixinItemStack.java
new file mode 100644
index 000000000..61fc4f5ba
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/mixin/tools/MixinItemStack.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.tools;
+
+import net.fabricmc.fabric.tools.MiningToolDelegate;
+import net.fabricmc.fabric.tools.ToolManager;
+import net.fabricmc.fabric.util.TriState;
+import net.minecraft.block.BlockState;
+import net.minecraft.item.Item;
+import net.minecraft.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.CallbackInfoReturnable;
+
+@Mixin(ItemStack.class)
+public abstract class MixinItemStack {
+	@Shadow
+	public abstract Item getItem();
+
+	@Inject(at = @At("HEAD"), method = "isEffectiveOn", cancellable = true)
+	public void isEffectiveOn(BlockState state, CallbackInfoReturnable<Boolean> info) {
+		TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state);
+		if (triState != TriState.DEFAULT) {
+			info.setReturnValue(triState.get());
+			info.cancel();
+		}
+	}
+
+	@Inject(at = @At("HEAD"), method = "getBlockBreakingSpeed", cancellable = true)
+	public void getBlockBreakingSpeed(BlockState state, CallbackInfoReturnable<Float> info) {
+		if (this.getItem() instanceof MiningToolDelegate) {
+			TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state);
+			if (triState != TriState.DEFAULT) {
+				info.setReturnValue(triState.get() ? ((MiningToolDelegate) this.getItem()).getMiningToolEfficiency() : 1.0F);
+				info.cancel();
+			}
+		}
+	}
+
+}
diff --git a/src/main/java/net/fabricmc/fabric/mixin/tools/MixinMiningToolItem.java b/src/main/java/net/fabricmc/fabric/mixin/tools/MixinMiningToolItem.java
new file mode 100644
index 000000000..a4f85dbe9
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/mixin/tools/MixinMiningToolItem.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.tools;
+
+import net.fabricmc.fabric.tools.MiningToolDelegate;
+import net.minecraft.item.MiningToolItem;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+@Mixin(MiningToolItem.class)
+public class MixinMiningToolItem implements MiningToolDelegate {
+	@Shadow
+	protected float efficiency;
+
+	@Override
+	public float getMiningToolEfficiency() {
+		return efficiency;
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/registry/RegistrySyncManager.java b/src/main/java/net/fabricmc/fabric/registry/RegistrySyncManager.java
index ee6f8ec84..d4924c63e 100644
--- a/src/main/java/net/fabricmc/fabric/registry/RegistrySyncManager.java
+++ b/src/main/java/net/fabricmc/fabric/registry/RegistrySyncManager.java
@@ -23,7 +23,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
 import net.fabricmc.fabric.networking.CustomPayloadHandlerRegistry;
 import net.fabricmc.fabric.networking.PacketContext;
 import net.minecraft.client.network.packet.CustomPayloadClientPacket;
-import net.minecraft.nbt.TagCompound;
+import net.minecraft.nbt.CompoundTag;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.PacketByteBuf;
 import net.minecraft.util.registry.IdRegistry;
@@ -52,7 +52,7 @@ public final class RegistrySyncManager {
 	}
 
 	public static void receivePacket(PacketContext context, PacketByteBuf buf) {
-		TagCompound compound = buf.readTagCompound();
+		CompoundTag compound = buf.readTagCompound();
 
 		try {
 			apply(compound, false);
@@ -62,8 +62,8 @@ public final class RegistrySyncManager {
 		}
 	}
 
-	public static TagCompound toTag(boolean isClientSync) {
-		TagCompound mainTag = new TagCompound();
+	public static CompoundTag toTag(boolean isClientSync) {
+		CompoundTag mainTag = new CompoundTag();
 
 		for (Identifier registryId : Registry.REGISTRIES.keys()) {
 			if (REGISTRY_BLACKLIST.contains(registryId)) {
@@ -74,7 +74,7 @@ public final class RegistrySyncManager {
 
 			ModifiableRegistry registry = Registry.REGISTRIES.get(registryId);
 			if (registry instanceof IdRegistry && registry instanceof RemappableRegistry) {
-				TagCompound registryTag = new TagCompound();
+				CompoundTag registryTag = new CompoundTag();
 				//noinspection unchecked
 				for (Identifier identifier : (Set<Identifier>) registry.keys()) {
 					registryTag.setInt(identifier.toString(), registry.getRawId(registry.get(identifier)));
@@ -83,22 +83,22 @@ public final class RegistrySyncManager {
 			}
 		}
 
-		TagCompound tag = new TagCompound();
+		CompoundTag tag = new CompoundTag();
 		tag.setInt("version", 1);
 		tag.setTag("registries", mainTag);
 
 		return tag;
 	}
 
-	public static void apply(TagCompound tag, boolean reallocateMissingEntries) throws RemapException {
-		TagCompound mainTag = tag.getTagCompound("registries");
+	public static void apply(CompoundTag tag, boolean reallocateMissingEntries) throws RemapException {
+		CompoundTag mainTag = tag.getTagCompound("registries");
 
 		for (Identifier registryId : Registry.REGISTRIES.keys()) {
 			if (!mainTag.containsKey(registryId.toString())) {
 				continue;
 			}
 
-			TagCompound registryTag = mainTag.getTagCompound(registryId.toString());
+			CompoundTag registryTag = mainTag.getTagCompound(registryId.toString());
 			ModifiableRegistry registry = Registry.REGISTRIES.get(registryId);
 			if (registry instanceof IdRegistry && registry instanceof RemappableRegistry) {
 				Object2IntMap<Identifier> idMap = new Object2IntOpenHashMap<>();
diff --git a/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBlockRegistryListener.java b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBlockRegistryListener.java
index 622220246..a634c1948 100644
--- a/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBlockRegistryListener.java
+++ b/src/main/java/net/fabricmc/fabric/registry/listeners/BootstrapBlockRegistryListener.java
@@ -41,7 +41,6 @@ public class BootstrapBlockRegistryListener implements RegistryListener<Block> {
 
 	@Override
 	public void afterRegistryRegistration(Registry<Block> registry, int id, Identifier identifier, Block object) {
-		System.out.println(identifier);
 		// refer net.minecraft.block.Blocks
 		object.getDropTableId();
 	}
diff --git a/src/main/java/net/fabricmc/fabric/resources/ModDirectoryResourcePack.java b/src/main/java/net/fabricmc/fabric/resources/ModDirectoryResourcePack.java
index 9a4e2d81a..86a0e4d49 100644
--- a/src/main/java/net/fabricmc/fabric/resources/ModDirectoryResourcePack.java
+++ b/src/main/java/net/fabricmc/fabric/resources/ModDirectoryResourcePack.java
@@ -20,8 +20,11 @@ import net.fabricmc.loader.ModInfo;
 import net.minecraft.resource.DirectoryResourcePack;
 import net.minecraft.resource.ResourceNotFoundException;
 import net.minecraft.resource.ResourceType;
+import net.minecraft.util.Identifier;
 
 import java.io.*;
+import java.util.Collection;
+import java.util.function.Predicate;
 
 public class ModDirectoryResourcePack extends DirectoryResourcePack implements ModResourcePack {
     private final ModInfo info;
@@ -49,6 +52,16 @@ public class ModDirectoryResourcePack extends DirectoryResourcePack implements M
         }
     }
 
+	@Override
+	public Collection<Identifier> findResources(ResourceType var1, String var2, int var3, Predicate<String> var4) {
+    	System.out.println("called " + var1 + " " + var2 + " " + var3);
+		Collection<Identifier> test = super.findResources(var1, var2, var3, var4);
+		for (Identifier id : test) {
+			System.out.println("- " + id);
+		}
+		return test;
+	}
+
     @Override
     protected boolean containsFilename(String filename) {
         return super.containsFilename(filename) || ModResourcePackUtil.containsDefault(info, filename);
diff --git a/src/main/java/net/fabricmc/fabric/resources/ModResourcePackUtil.java b/src/main/java/net/fabricmc/fabric/resources/ModResourcePackUtil.java
index d3d228789..b66842bb1 100644
--- a/src/main/java/net/fabricmc/fabric/resources/ModResourcePackUtil.java
+++ b/src/main/java/net/fabricmc/fabric/resources/ModResourcePackUtil.java
@@ -42,14 +42,20 @@ public final class ModResourcePackUtil {
     public static void appendModResourcePacks(List<ResourcePack> packList, ResourceType type) {
         for (ModContainer container : FabricLoader.INSTANCE.getMods()) {
             File file = container.getOriginFile();
+            ResourcePack pack = null;
+
             if (file.isDirectory()) {
-                packList.add(new ModDirectoryResourcePack(container.getInfo(), file));
+            	pack = new ModDirectoryResourcePack(container.getInfo(), file);
             } else {
                 String name = file.getName().toLowerCase(Locale.ROOT);
                 if (name.endsWith(".zip") || name.endsWith(".jar")) {
-                    packList.add(new ModZipResourcePack(container.getInfo(), file));
+                    pack = new ModZipResourcePack(container.getInfo(), file);
                 }
             }
+
+            if (pack != null && !pack.getNamespaces(type).isEmpty()) {
+            	packList.add(pack);
+            }
         }
     }
 
diff --git a/src/main/java/net/fabricmc/fabric/resources/ModZipResourcePack.java b/src/main/java/net/fabricmc/fabric/resources/ModZipResourcePack.java
index c656ed53f..3f2f49dcc 100644
--- a/src/main/java/net/fabricmc/fabric/resources/ModZipResourcePack.java
+++ b/src/main/java/net/fabricmc/fabric/resources/ModZipResourcePack.java
@@ -16,16 +16,18 @@
 
 package net.fabricmc.fabric.resources;
 
-import com.google.common.io.ByteStreams;
 import net.fabricmc.loader.ModInfo;
 import net.minecraft.resource.ResourceNotFoundException;
 import net.minecraft.resource.ResourceType;
 import net.minecraft.resource.ZipResourcePack;
+import net.minecraft.util.Identifier;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collection;
+import java.util.function.Predicate;
 
 public class ModZipResourcePack extends ZipResourcePack implements ModResourcePack {
     private final ModInfo info;
@@ -53,6 +55,16 @@ public class ModZipResourcePack extends ZipResourcePack implements ModResourcePa
         }
     }
 
+	@Override
+	public Collection<Identifier> findResources(ResourceType var1, String var2, int var3, Predicate<String> var4) {
+		System.out.println("called " + var1 + " " + var2 + " " + var3);
+		Collection<Identifier> test = super.findResources(var1, var2, var3, var4);
+		for (Identifier id : test) {
+			System.out.println("- " + id);
+		}
+		return test;
+	}
+
     @Override
     public boolean containsFilename(String filename) {
         return super.containsFilename(filename) || ModResourcePackUtil.containsDefault(info, filename);
diff --git a/src/main/java/net/fabricmc/fabric/tags/FabricItemTags.java b/src/main/java/net/fabricmc/fabric/tags/FabricItemTags.java
new file mode 100644
index 000000000..705b684a7
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/tags/FabricItemTags.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.tags;
+
+import net.minecraft.item.Item;
+import net.minecraft.tag.ItemTags;
+import net.minecraft.tag.Tag;
+import net.minecraft.util.Identifier;
+
+public class FabricItemTags {
+	public static final Tag<Item> AXES = register("axes");
+	public static final Tag<Item> HOES = register("hoes");
+	public static final Tag<Item> PICKAXES = register("pickaxes");
+	public static final Tag<Item> SHOVELS = register("shovels");
+	public static final Tag<Item> SWORDS = register("swords");
+
+	private static Tag<Item> register(String id) {
+		return new ItemTags.class_3490(new Identifier("fabric", id));
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/tools/MiningToolDelegate.java b/src/main/java/net/fabricmc/fabric/tools/MiningToolDelegate.java
new file mode 100644
index 000000000..96067cf3d
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/tools/MiningToolDelegate.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.tools;
+
+public interface MiningToolDelegate {
+	float getMiningToolEfficiency();
+}
diff --git a/src/main/java/net/fabricmc/fabric/tools/ToolManager.java b/src/main/java/net/fabricmc/fabric/tools/ToolManager.java
new file mode 100644
index 000000000..2751d1b99
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/tools/ToolManager.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.tools;
+
+import net.fabricmc.fabric.util.TriState;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockState;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.ToolItem;
+import net.minecraft.tag.Tag;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public final class ToolManager {
+	private static class Entry {
+		@SuppressWarnings("unchecked")
+		private Tag<Item>[] tags = (Tag<Item>[]) new Tag[0];
+		private int[] tagLevels = new int[0];
+		private TriState defaultValue = TriState.DEFAULT;
+
+		public void setDefaultValue(TriState defaultValue) {
+			this.defaultValue = defaultValue;
+		}
+
+		public void addTag(Tag<Item> tag, int miningLevel) {
+			for (int i = 0; i < tags.length; i++) {
+				if (tags[i] == tag) {
+					tagLevels[i] = miningLevel;
+					return;
+				}
+			}
+
+			//noinspection unchecked
+			Tag<Item>[] newTags = (Tag<Item>[]) new Tag[tags.length + 1];
+			int[] newTagLevels = new int[tagLevels.length + 1];
+			System.arraycopy(tags, 0, newTags, 0, tags.length);
+			System.arraycopy(tagLevels, 0, newTagLevels, 0, tagLevels.length);
+			newTags[tags.length] = tag;
+			newTagLevels[tagLevels.length] = miningLevel;
+			tags = newTags;
+			tagLevels = newTagLevels;
+		}
+	}
+
+	private static final Map<Block, Entry> entries = new HashMap<>();
+
+	private ToolManager() {
+
+	}
+
+	private static Entry computeEntry(Block b) {
+		return entries.computeIfAbsent(b, (bb) -> new Entry());
+	}
+
+	public static void registerBreakByHand(Block block, boolean value) {
+		computeEntry(block).defaultValue = TriState.of(value);
+	}
+
+	public static void registerBreakByTool(Block block, Tag<Item> tag, int miningLevel) {
+		computeEntry(block).defaultValue = TriState.FALSE;
+		computeEntry(block).addTag(tag, miningLevel);
+	}
+
+	public static int getMiningLevel(ItemStack stack) {
+		if (stack.getItem() instanceof ToolItem) {
+			return ((ToolItem) stack.getItem()).getType().getMiningLevel();
+		} else {
+			return 0;
+		}
+	}
+
+	public static TriState handleIsEffectiveOn(ItemStack stack, BlockState state) {
+		Entry entry = entries.get(state.getBlock());
+		if (entry != null) {
+			Item item = stack.getItem();
+			for (int i = 0; i < entry.tags.length; i++) {
+				if (item.matches(entry.tags[i])) {
+					return TriState.of(getMiningLevel(stack) >= entry.tagLevels[i]);
+				}
+			}
+
+			return entry.defaultValue;
+		} else {
+			return TriState.DEFAULT;
+		}
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/util/TriState.java b/src/main/java/net/fabricmc/fabric/util/TriState.java
new file mode 100644
index 000000000..5b7bb481c
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/util/TriState.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, 2017, 2018 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.util;
+
+public enum TriState {
+	FALSE,
+	DEFAULT,
+	TRUE;
+
+	public static TriState of(boolean b) {
+		return b ? TRUE : FALSE;
+	}
+
+	public boolean get() {
+		return this == TRUE;
+	}
+}
diff --git a/src/main/resources/data/fabric/tags/items/axes.json b/src/main/resources/data/fabric/tags/items/axes.json
new file mode 100644
index 000000000..ba3393896
--- /dev/null
+++ b/src/main/resources/data/fabric/tags/items/axes.json
@@ -0,0 +1,10 @@
+{
+  "replace": false,
+  "values": [
+    "minecraft:wooden_axe",
+    "minecraft:stone_axe",
+    "minecraft:iron_axe",
+    "minecraft:golden_axe",
+    "minecraft:diamond_axe"
+  ]
+}
\ No newline at end of file
diff --git a/src/main/resources/data/fabric/tags/items/hoes.json b/src/main/resources/data/fabric/tags/items/hoes.json
new file mode 100644
index 000000000..6f5068b75
--- /dev/null
+++ b/src/main/resources/data/fabric/tags/items/hoes.json
@@ -0,0 +1,10 @@
+{
+  "replace": false,
+  "values": [
+    "minecraft:wooden_hoe",
+    "minecraft:stone_hoe",
+    "minecraft:iron_hoe",
+    "minecraft:golden_hoe",
+    "minecraft:diamond_hoe"
+  ]
+}
\ No newline at end of file
diff --git a/src/main/resources/data/fabric/tags/items/pickaxes.json b/src/main/resources/data/fabric/tags/items/pickaxes.json
new file mode 100644
index 000000000..1b8ccd6a7
--- /dev/null
+++ b/src/main/resources/data/fabric/tags/items/pickaxes.json
@@ -0,0 +1,10 @@
+{
+  "replace": false,
+  "values": [
+    "minecraft:wooden_pickaxe",
+    "minecraft:stone_pickaxe",
+    "minecraft:iron_pickaxe",
+    "minecraft:golden_pickaxe",
+    "minecraft:diamond_pickaxe"
+  ]
+}
\ No newline at end of file
diff --git a/src/main/resources/data/fabric/tags/items/shovels.json b/src/main/resources/data/fabric/tags/items/shovels.json
new file mode 100644
index 000000000..ea012498e
--- /dev/null
+++ b/src/main/resources/data/fabric/tags/items/shovels.json
@@ -0,0 +1,10 @@
+{
+  "replace": false,
+  "values": [
+    "minecraft:wooden_shovel",
+    "minecraft:stone_shovel",
+    "minecraft:iron_shovel",
+    "minecraft:golden_shovel",
+    "minecraft:diamond_shovel"
+  ]
+}
\ No newline at end of file
diff --git a/src/main/resources/data/fabric/tags/items/swords.json b/src/main/resources/data/fabric/tags/items/swords.json
new file mode 100644
index 000000000..d5fa2e2ea
--- /dev/null
+++ b/src/main/resources/data/fabric/tags/items/swords.json
@@ -0,0 +1,10 @@
+{
+  "replace": false,
+  "values": [
+    "minecraft:wooden_sword",
+    "minecraft:stone_sword",
+    "minecraft:iron_sword",
+    "minecraft:golden_sword",
+    "minecraft:diamond_sword"
+  ]
+}
\ No newline at end of file
diff --git a/src/main/resources/net.fabricmc.fabric.mixins.common.json b/src/main/resources/net.fabricmc.fabric.mixins.common.json
index 32c2aa3c3..de1f23eb8 100644
--- a/src/main/resources/net.fabricmc.fabric.mixins.common.json
+++ b/src/main/resources/net.fabricmc.fabric.mixins.common.json
@@ -12,7 +12,9 @@
     "registry.MixinIdRegistry",
     "registry.MixinServerPlayNetworkHandler",
     "registry.MixinWorldSaveHandler",
-    "resources.MixinMinecraftServer"
+    "resources.MixinMinecraftServer",
+    "tools.MixinItemStack",
+    "tools.MixinMiningToolItem"
   ],
   "injectors": {
     "defaultRequire": 1