From b88969cf131f8cae58b66e0c755559805f54e6ff Mon Sep 17 00:00:00 2001
From: Juuxel <kasperi.kauppi@gmail.com>
Date: Fri, 25 Jan 2019 23:53:11 +0100
Subject: [PATCH] (#59) Loot entry extensions

---
 .../fabric/api/loot/LootEntryRegistry.java    | 37 ++++++++++++
 .../impl/loot/LootEntryRegistryImpl.java      | 47 +++++++++++++++
 .../fabric/mixin/loot/MixinLootEntries.java   | 37 ++++++++++++
 .../net.fabricmc.fabric.mixins.common.json    |  1 +
 .../fabricmc/fabric/loot/LootEntryMod.java    | 60 +++++++++++++++++++
 .../minecraft/loot_tables/blocks/stone.json   | 44 ++++++++++++++
 src/test/resources/mod.json                   |  3 +-
 7 files changed, 228 insertions(+), 1 deletion(-)
 create mode 100644 src/main/java/net/fabricmc/fabric/api/loot/LootEntryRegistry.java
 create mode 100644 src/main/java/net/fabricmc/fabric/impl/loot/LootEntryRegistryImpl.java
 create mode 100644 src/main/java/net/fabricmc/fabric/mixin/loot/MixinLootEntries.java
 create mode 100644 src/test/java/net/fabricmc/fabric/loot/LootEntryMod.java
 create mode 100644 src/test/resources/data/minecraft/loot_tables/blocks/stone.json

diff --git a/src/main/java/net/fabricmc/fabric/api/loot/LootEntryRegistry.java b/src/main/java/net/fabricmc/fabric/api/loot/LootEntryRegistry.java
new file mode 100644
index 000000000..3567061fb
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/api/loot/LootEntryRegistry.java
@@ -0,0 +1,37 @@
+/*
+ * 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.api.loot;
+
+import net.fabricmc.fabric.impl.loot.LootEntryRegistryImpl;
+import net.minecraft.world.loot.entry.LootEntry;
+
+/**
+ * Fabric's extensions to {@code net.minecraft.world.loot.entry.LootEntries} for registering
+ * custom loot entry types.
+ *
+ * @see #registerType
+ */
+public interface LootEntryRegistry {
+	LootEntryRegistry INSTANCE = LootEntryRegistryImpl.INSTANCE;
+
+	/**
+	 * Registers a loot entry type by its serializer.
+	 *
+	 * @param serializer the loot entry serializer
+	 */
+	void registerType(LootEntry.Serializer<?> serializer);
+}
diff --git a/src/main/java/net/fabricmc/fabric/impl/loot/LootEntryRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/loot/LootEntryRegistryImpl.java
new file mode 100644
index 000000000..86737f411
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/impl/loot/LootEntryRegistryImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.impl.loot;
+
+import net.fabricmc.fabric.api.loot.LootEntryRegistry;
+import net.minecraft.world.loot.entry.LootEntries;
+import net.minecraft.world.loot.entry.LootEntry;
+
+import java.util.function.Consumer;
+
+public final class LootEntryRegistryImpl implements LootEntryRegistry {
+	private static Consumer<LootEntry.Serializer<?>> registerFunction;
+	public static final LootEntryRegistryImpl INSTANCE = new LootEntryRegistryImpl();
+
+	static {
+		loadLootEntries();
+	}
+
+	private LootEntryRegistryImpl() {}
+
+	@Override
+	public void registerType(LootEntry.Serializer<?> serializer) {
+		registerFunction.accept(serializer);
+	}
+
+	public static void setRegisterFunction(Consumer<LootEntry.Serializer<?>> registerFunction) {
+		LootEntryRegistryImpl.registerFunction = registerFunction;
+	}
+
+	private static void loadLootEntries() {
+		try { Class.forName(LootEntries.class.getCanonicalName()); } catch (ClassNotFoundException e) {}
+	}
+}
diff --git a/src/main/java/net/fabricmc/fabric/mixin/loot/MixinLootEntries.java b/src/main/java/net/fabricmc/fabric/mixin/loot/MixinLootEntries.java
new file mode 100644
index 000000000..1859c8f0a
--- /dev/null
+++ b/src/main/java/net/fabricmc/fabric/mixin/loot/MixinLootEntries.java
@@ -0,0 +1,37 @@
+/*
+ * 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.loot;
+
+import net.fabricmc.fabric.impl.loot.LootEntryRegistryImpl;
+import net.minecraft.world.loot.entry.LootEntries;
+import net.minecraft.world.loot.entry.LootEntry;
+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(LootEntries.class)
+public class MixinLootEntries {
+	@Shadow
+	private static void register(LootEntry.Serializer<?> lootEntry$Serializer_1) {}
+
+	@Inject(method = "<clinit>", at = @At("RETURN"))
+	private static void onClinit(CallbackInfo info) {
+		LootEntryRegistryImpl.setRegisterFunction(MixinLootEntries::register);
+	}
+}
diff --git a/src/main/resources/net.fabricmc.fabric.mixins.common.json b/src/main/resources/net.fabricmc.fabric.mixins.common.json
index 137fd6dfa..283f7cc0a 100644
--- a/src/main/resources/net.fabricmc.fabric.mixins.common.json
+++ b/src/main/resources/net.fabricmc.fabric.mixins.common.json
@@ -19,6 +19,7 @@
     "events.tick.MixinWorld",
     "item.MixinAbstractFurnaceBlockEntity",
     "itemgroup.MixinItemGroup",
+    "loot.MixinLootEntries",
     "misc.MixinCrashReport",
     "networking.MixinServerPlayNetworkHandler",
     "networking.MixinSPacketCustomPayload",
diff --git a/src/test/java/net/fabricmc/fabric/loot/LootEntryMod.java b/src/test/java/net/fabricmc/fabric/loot/LootEntryMod.java
new file mode 100644
index 000000000..3df13bae5
--- /dev/null
+++ b/src/test/java/net/fabricmc/fabric/loot/LootEntryMod.java
@@ -0,0 +1,60 @@
+/*
+ * 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.loot;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.fabric.api.loot.LootEntryRegistry;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.JsonHelper;
+import net.minecraft.world.loot.condition.LootCondition;
+import net.minecraft.world.loot.entry.LootEntry;
+import net.minecraft.world.loot.entry.TagEntry;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class LootEntryMod implements ModInitializer {
+	private static final Logger LOGGER = LogManager.getLogger();
+
+	@Override
+	public void onInitialize() {
+		LootEntryRegistry.INSTANCE.registerType(new TestSerializer());
+	}
+
+	private static class TestSerializer extends LootEntry.Serializer<TagEntry> {
+		private static final TagEntry.Serializer SERIALIZER = new TagEntry.Serializer();
+
+		public TestSerializer() {
+			super(new Identifier("fabric", "extended_tag"), TagEntry.class);
+		}
+
+		@Override
+		public void toJson(JsonObject obj, TagEntry entry, JsonSerializationContext context) {
+			SERIALIZER.method_451(obj, entry, context);
+			obj.addProperty("fabric", true);
+		}
+
+		@Override
+		public TagEntry fromJson(JsonObject var1, JsonDeserializationContext var2, LootCondition[] var3) {
+			LOGGER.info("Is this a Fabric loot entry? " + JsonHelper.getBoolean(var1, "fabric", true));
+			return SERIALIZER.fromJson(var1, var2, var3);
+		}
+	}
+}
+
diff --git a/src/test/resources/data/minecraft/loot_tables/blocks/stone.json b/src/test/resources/data/minecraft/loot_tables/blocks/stone.json
new file mode 100644
index 000000000..6b0ef6c00
--- /dev/null
+++ b/src/test/resources/data/minecraft/loot_tables/blocks/stone.json
@@ -0,0 +1,44 @@
+{
+  "type": "minecraft:block",
+  "pools": [
+    {
+      "rolls": 1,
+      "entries": [
+        {
+          "type": "minecraft:alternatives",
+          "children": [
+            {
+              "type": "minecraft:item",
+              "conditions": [
+                {
+                  "condition": "minecraft:match_tool",
+                  "predicate": {
+                    "enchantments": [
+                      {
+                        "enchantment": "minecraft:silk_touch",
+                        "levels": {
+                          "min": 1
+                        }
+                      }
+                    ]
+                  }
+                }
+              ],
+              "name": "minecraft:stone"
+            },
+            {
+              "type": "fabric:extended_tag",
+              "conditions": [
+                {
+                  "condition": "minecraft:survives_explosion"
+                }
+              ],
+              "name": "minecraft:wool",
+              "expand": false
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/test/resources/mod.json b/src/test/resources/mod.json
index e24ed7115..44b50c290 100644
--- a/src/test/resources/mod.json
+++ b/src/test/resources/mod.json
@@ -9,6 +9,7 @@
     "net.fabricmc.fabric.colormapper.ColorProviderMod",
     "net.fabricmc.fabric.events.ServerEventMod",
     "net.fabricmc.fabric.containers.ContainerMod",
-    "net.fabricmc.fabric.containers.ContainerModClient"
+    "net.fabricmc.fabric.containers.ContainerModClient",
+    "net.fabricmc.fabric.loot.LootEntryMod"
   ]
 }