diff --git a/patchwork-events-lifecycle/src/main/java/net/minecraftforge/fml/event/server/FMLServerStoppedEvent.java b/patchwork-events-lifecycle/src/main/java/net/minecraftforge/fml/event/server/FMLServerStoppedEvent.java
new file mode 100644
index 00000000..fdd56c06
--- /dev/null
+++ b/patchwork-events-lifecycle/src/main/java/net/minecraftforge/fml/event/server/FMLServerStoppedEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.minecraftforge.fml.event.server;
+
+import net.minecraft.server.MinecraftServer;
+
+/**
+ * Called after {@link FMLServerStoppingEvent} when the server has completely shut down.
+ * Called immediately before shutting down, on the dedicated server, and before returning
+ * to the main menu on the client.
+ *
+ * @author cpw
+ */
+public class FMLServerStoppedEvent extends ServerLifecycleEvent {
+ public FMLServerStoppedEvent(MinecraftServer server) {
+ super(server);
+ }
+}
diff --git a/patchwork-events-lifecycle/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java b/patchwork-events-lifecycle/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java
index c3c1b8fc..034bf4bb 100644
--- a/patchwork-events-lifecycle/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java
+++ b/patchwork-events-lifecycle/src/main/java/net/minecraftforge/fml/server/ServerLifecycleHooks.java
@@ -19,6 +19,8 @@
package net.minecraftforge.fml.server;
+import java.util.concurrent.CountDownLatch;
+
import net.minecraft.server.MinecraftServer;
import net.patchworkmc.impl.event.lifecycle.LifecycleEvents;
@@ -28,6 +30,7 @@
*/
public class ServerLifecycleHooks {
public static MinecraftServer currentServer;
+ public static volatile CountDownLatch exitLatch = null;
public static MinecraftServer getCurrentServer() {
return currentServer;
@@ -48,4 +51,8 @@ public static boolean handleServerStarting(final MinecraftServer server) {
public static void handleServerStarted(final MinecraftServer server) {
LifecycleEvents.handleServerStarted(server);
}
+
+ public static void handleServerStopped(final MinecraftServer server) {
+ LifecycleEvents.handleServerStopped(server);
+ }
}
diff --git a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java
index 8c950a0c..5dd0e083 100644
--- a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java
+++ b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/impl/event/lifecycle/LifecycleEvents.java
@@ -20,6 +20,7 @@
package net.patchworkmc.impl.event.lifecycle;
import java.nio.file.Path;
+import java.util.concurrent.CountDownLatch;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.TickEvent;
@@ -30,6 +31,7 @@
import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
+import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import net.minecraftforge.fml.loading.FileUtils;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
@@ -93,6 +95,18 @@ public static void handleLoadComplete() {
loadCompleteCallback.run();
}
+ public static void handleServerStopped(final MinecraftServer server) {
+ MinecraftForge.EVENT_BUS.post(new FMLServerStoppedEvent(server));
+ ServerLifecycleHooks.currentServer = null;
+ LogicalSidedProvider.setServer(null);
+ CountDownLatch latch = ServerLifecycleHooks.exitLatch;
+
+ if (latch != null) {
+ latch.countDown();
+ ServerLifecycleHooks.exitLatch = null;
+ }
+ }
+
@Override
public void onInitialize() {
WorldTickCallback.EVENT.register(world -> fireWorldTickEvent(TickEvent.Phase.END, world));
diff --git a/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftServer.java b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftServer.java
new file mode 100644
index 00000000..6527d290
--- /dev/null
+++ b/patchwork-events-lifecycle/src/main/java/net/patchworkmc/mixin/event/lifecycle/MixinMinecraftServer.java
@@ -0,0 +1,37 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.patchworkmc.mixin.event.lifecycle;
+
+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 net.minecraft.server.MinecraftServer;
+
+import net.patchworkmc.impl.event.lifecycle.LifecycleEvents;
+
+@Mixin(MinecraftServer.class)
+public class MixinMinecraftServer {
+ @Inject(method = "run", at = @At(value = "INVOKE", target = "net/minecraft/server/MinecraftServer.exit ()V"))
+ private void serverStoppedHook(CallbackInfo ci) {
+ LifecycleEvents.handleServerStopped((MinecraftServer) (Object) this);
+ }
+}
diff --git a/patchwork-god-classes/build.gradle b/patchwork-god-classes/build.gradle
index 24901999..ad0f0d6a 100644
--- a/patchwork-god-classes/build.gradle
+++ b/patchwork-god-classes/build.gradle
@@ -7,4 +7,5 @@ dependencies {
compile project(path: ':patchwork-events-entity', configuration: 'dev')
compile project(path: ':patchwork-events-lifecycle', configuration: 'dev')
compile project(path: ':patchwork-events-rendering', configuration: 'dev')
+ compile project(path: ':patchwork-loot', configuration: 'dev')
}
diff --git a/patchwork-god-classes/src/main/java/net/minecraftforge/common/ForgeHooks.java b/patchwork-god-classes/src/main/java/net/minecraftforge/common/ForgeHooks.java
index dea1ec51..65e86ca0 100644
--- a/patchwork-god-classes/src/main/java/net/minecraftforge/common/ForgeHooks.java
+++ b/patchwork-god-classes/src/main/java/net/minecraftforge/common/ForgeHooks.java
@@ -23,6 +23,8 @@
import javax.annotation.Nullable;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.eventbus.api.Event;
@@ -33,12 +35,16 @@
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.loot.LootManager;
+import net.minecraft.loot.LootTable;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
+import net.minecraft.util.Identifier;
import net.minecraft.world.IWorld;
import net.minecraft.world.MobSpawnerLogic;
import net.patchworkmc.impl.event.entity.EntityEvents;
+import net.patchworkmc.impl.loot.LootHooks;
/*
* Note: this class is intended for mod use only, to dispatch to the implementations kept in their own modules.
@@ -98,4 +104,13 @@ public static boolean onLivingDrops(LivingEntity entity, DamageSource source, Co
public static boolean onPlayerAttackTarget(PlayerEntity player, Entity target) {
return EntityEvents.attackEntity(player, target);
}
+
+ @Nullable
+ public static LootTable loadLootTable(Gson gson, Identifier name, JsonObject data, boolean custom, LootManager lootTableManager) {
+ return LootHooks.loadLootTable(gson, name, data, custom, lootTableManager);
+ }
+
+ public static String readPoolName(JsonObject json) {
+ return LootHooks.readPoolName(json);
+ }
}
diff --git a/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
index f6bc5485..665926e3 100644
--- a/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
+++ b/patchwork-god-classes/src/main/java/net/minecraftforge/event/ForgeEventFactory.java
@@ -28,12 +28,16 @@
import net.minecraft.entity.SpawnType;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.loot.LootManager;
+import net.minecraft.loot.LootTable;
+import net.minecraft.util.Identifier;
import net.minecraft.world.IWorld;
import net.minecraft.world.MobSpawnerLogic;
import net.minecraft.world.World;
import net.patchworkmc.impl.capability.CapabilityEvents;
import net.patchworkmc.impl.event.entity.EntityEvents;
+import net.patchworkmc.impl.event.loot.LootEvents;
/*
* Note: this class is intended for mod use only, to dispatch to the implementations kept in their own modules.
@@ -65,4 +69,8 @@ public static void onPlayerFall(PlayerEntity player, float distance, float multi
public static boolean doSpecialSpawn(MobEntity entity, World world, float x, float y, float z, MobSpawnerLogic spawner, SpawnType spawnReason) {
return EntityEvents.doSpecialSpawn(entity, world, x, y, z, spawner, spawnReason);
}
+
+ public static LootTable loadLootTable(Identifier name, LootTable table, LootManager lootTableManager) {
+ return LootEvents.loadLootTable(name, table, lootTableManager);
+ }
}
diff --git a/patchwork-god-classes/src/main/resources/fabric.mod.json b/patchwork-god-classes/src/main/resources/fabric.mod.json
index 07c35810..388b9196 100644
--- a/patchwork-god-classes/src/main/resources/fabric.mod.json
+++ b/patchwork-god-classes/src/main/resources/fabric.mod.json
@@ -19,7 +19,8 @@
"patchwork-fml": "*",
"patchwork-capabilities": "*",
"patchwork-events-lifecycle": "*",
- "patchwork-events-rendering": "*"
+ "patchwork-events-rendering": "*",
+ "patchwork-loot": "*"
},
"custom": {
"modmenu:api": true,
diff --git a/patchwork-loot/build.gradle b/patchwork-loot/build.gradle
index 9029bd24..0caa77dc 100644
--- a/patchwork-loot/build.gradle
+++ b/patchwork-loot/build.gradle
@@ -1,2 +1,7 @@
archivesBaseName = "patchwork-loot"
version = getSubprojectVersion(project, "0.2.0")
+
+dependencies {
+ compile project(path: ':patchwork-fml', configuration: 'dev')
+}
+
diff --git a/patchwork-loot/src/main/java/net/minecraftforge/event/LootTableLoadEvent.java b/patchwork-loot/src/main/java/net/minecraftforge/event/LootTableLoadEvent.java
new file mode 100644
index 00000000..93ecb6b8
--- /dev/null
+++ b/patchwork-loot/src/main/java/net/minecraftforge/event/LootTableLoadEvent.java
@@ -0,0 +1,67 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.minecraftforge.event;
+
+import net.minecraftforge.eventbus.api.Event;
+
+import net.minecraft.loot.LootManager;
+import net.minecraft.loot.LootTable;
+import net.minecraft.util.Identifier;
+
+/**
+ * Event fired when a LootTable json is loaded from json.
+ * This event is fired whenever resources are loaded, or when the server starts.
+ * This event will NOT be fired for LootTables loaded from the world folder, these are
+ * considered configurations files and should not be modified by mods.
+ *
+ *
Canceling the event will make it load a empty loot table.
+ */
+public class LootTableLoadEvent extends Event {
+ private final Identifier name;
+ private LootTable table;
+ private LootManager lootTableManager;
+
+ public LootTableLoadEvent(Identifier name, LootTable table, LootManager lootTableManager) {
+ this.name = name;
+ this.table = table;
+ this.lootTableManager = lootTableManager;
+ }
+
+ public Identifier getName() {
+ return this.name;
+ }
+
+ public LootTable getTable() {
+ return this.table;
+ }
+
+ public void setTable(LootTable table) {
+ this.table = table;
+ }
+
+ public LootManager getLootTableManager() {
+ return this.lootTableManager;
+ }
+
+ @Override
+ public boolean isCancelable() {
+ return true;
+ }
+}
diff --git a/patchwork-loot/src/main/java/net/patchworkmc/api/loot/ForgeLootPool.java b/patchwork-loot/src/main/java/net/patchworkmc/api/loot/ForgeLootPool.java
new file mode 100644
index 00000000..7aef5158
--- /dev/null
+++ b/patchwork-loot/src/main/java/net/patchworkmc/api/loot/ForgeLootPool.java
@@ -0,0 +1,42 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.patchworkmc.api.loot;
+
+import net.minecraft.loot.LootPool;
+import net.minecraft.loot.LootTableRange;
+import net.minecraft.loot.UniformLootTableRange;
+
+/**
+ * Interface for adding Forge methods added to LootPool and its inner classes.
+ */
+public interface ForgeLootPool {
+ // TODO: doesn't include methods having to do with freezing yet
+
+ String getName();
+ LootTableRange getRolls();
+ LootTableRange getBonusRolls();
+ void setRolls(UniformLootTableRange v);
+ void setBonusRolls(UniformLootTableRange v);
+
+ public interface Builder {
+ LootPool.Builder name(String name);
+ LootPool.Builder bonusRolls(float min, float max);
+ }
+}
diff --git a/patchwork-loot/src/main/java/net/patchworkmc/api/loot/ForgeLootTable.java b/patchwork-loot/src/main/java/net/patchworkmc/api/loot/ForgeLootTable.java
new file mode 100644
index 00000000..86650bac
--- /dev/null
+++ b/patchwork-loot/src/main/java/net/patchworkmc/api/loot/ForgeLootTable.java
@@ -0,0 +1,33 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.patchworkmc.api.loot;
+
+import net.minecraft.loot.LootPool;
+
+/**
+ * Interface for adding Forge methods added to LootTable.
+ */
+public interface ForgeLootTable {
+ // TODO: doesn't include methods having to do with freezing yet
+
+ LootPool getPool(String name);
+ LootPool removePool(String name);
+ void addPool(LootPool pool);
+}
diff --git a/patchwork-loot/src/main/java/net/patchworkmc/impl/event/loot/LootEvents.java b/patchwork-loot/src/main/java/net/patchworkmc/impl/event/loot/LootEvents.java
new file mode 100644
index 00000000..c732f201
--- /dev/null
+++ b/patchwork-loot/src/main/java/net/patchworkmc/impl/event/loot/LootEvents.java
@@ -0,0 +1,39 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.patchworkmc.impl.event.loot;
+
+import net.minecraftforge.event.LootTableLoadEvent;
+import net.minecraftforge.common.MinecraftForge;
+
+import net.minecraft.loot.LootManager;
+import net.minecraft.loot.LootTable;
+import net.minecraft.util.Identifier;
+
+public class LootEvents {
+ public static LootTable loadLootTable(Identifier name, LootTable table, LootManager manager) {
+ LootTableLoadEvent event = new LootTableLoadEvent(name, table, manager);
+
+ if (MinecraftForge.EVENT_BUS.post(event)) {
+ return LootTable.EMPTY;
+ }
+
+ return event.getTable();
+ }
+}
diff --git a/patchwork-loot/src/main/java/net/patchworkmc/impl/loot/LootHooks.java b/patchwork-loot/src/main/java/net/patchworkmc/impl/loot/LootHooks.java
new file mode 100644
index 00000000..93492205
--- /dev/null
+++ b/patchwork-loot/src/main/java/net/patchworkmc/impl/loot/LootHooks.java
@@ -0,0 +1,149 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.patchworkmc.impl.loot;
+
+import java.util.Deque;
+import java.util.HashSet;
+
+import javax.annotation.Nullable;
+
+import com.google.common.collect.Queues;
+import com.google.common.collect.Sets;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import org.spongepowered.asm.mixin.Unique;
+
+import net.minecraft.loot.LootManager;
+import net.minecraft.loot.LootTable;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.JsonHelper;
+
+import net.patchworkmc.impl.event.loot.LootEvents;
+
+// NOTE: this class is more or less a direct copy of parts of Forge's ForgeHooks.
+public class LootHooks {
+ @Unique
+ private static ThreadLocal> lootContext = new ThreadLocal>();
+
+ public static LootTable loadLootTable(Gson gson, Identifier name, JsonElement data, boolean custom, LootManager lootTableManager) {
+ Deque que = lootContext.get();
+
+ if (que == null) {
+ que = Queues.newArrayDeque();
+ lootContext.set(que);
+ }
+
+ LootTable ret = null;
+
+ try {
+ que.push(new LootTableContext(name, custom));
+ ret = gson.fromJson(data, LootTable.class);
+ que.pop();
+ } catch (JsonParseException e) {
+ que.pop();
+ throw e;
+ }
+
+ if (!custom) {
+ ret = LootEvents.loadLootTable(name, ret, lootTableManager);
+ }
+
+ // if (ret != null) {
+ // ret.freeze();
+ // }
+
+ return ret;
+ }
+
+ private static LootTableContext getLootTableContext() {
+ LootTableContext ctx = lootContext.get().peek();
+
+ if (ctx == null) {
+ throw new JsonParseException("Invalid call stack, could not grab json context!"); // Should I throw this? Do we care about custom deserializers outside the manager?
+ }
+
+ return ctx;
+ }
+
+ public static String readPoolName(JsonObject json) {
+ LootTableContext ctx = LootHooks.getLootTableContext();
+ ctx.resetPoolCtx();
+
+ if (json.has("name")) {
+ return JsonHelper.getString(json, "name");
+ }
+
+ if (ctx.custom) {
+ return "custom#" + json.hashCode(); //We don't care about custom ones modders shouldn't be editing them!
+ }
+
+ ctx.poolCount++;
+
+ if (!ctx.vanilla) {
+ throw new JsonParseException("Loot Table \"" + ctx.name.toString() + "\" Missing `name` entry for pool #" + (ctx.poolCount - 1));
+ }
+
+ return ctx.poolCount == 1 ? "main" : "pool" + (ctx.poolCount - 1);
+ }
+
+ private static class LootTableContext {
+ public final Identifier name;
+ public final boolean custom;
+ private final boolean vanilla;
+ public int poolCount = 0;
+ public int entryCount = 0;
+ private HashSet entryNames = Sets.newHashSet();
+
+ private LootTableContext(Identifier name, boolean custom) {
+ this.name = name;
+ this.custom = custom;
+ this.vanilla = "minecraft".equals(this.name.getNamespace());
+ }
+
+ private void resetPoolCtx() {
+ this.entryCount = 0;
+ this.entryNames.clear();
+ }
+
+ public String validateEntryName(@Nullable String name) {
+ if (name != null && !this.entryNames.contains(name)) {
+ this.entryNames.add(name);
+ return name;
+ }
+
+ if (!this.vanilla) {
+ throw new JsonParseException("Loot Table \"" + this.name.toString() + "\" Duplicate entry name \"" + name + "\" for pool #" + (this.poolCount - 1) + " entry #" + (this.entryCount - 1));
+ }
+
+ int x = 0;
+
+ while (this.entryNames.contains(name + "#" + x)) {
+ x++;
+ }
+
+ name = name + "#" + x;
+ this.entryNames.add(name);
+
+ return name;
+ }
+ }
+}
diff --git a/patchwork-loot/src/main/java/net/patchworkmc/impl/loot/PatchworkLootPool.java b/patchwork-loot/src/main/java/net/patchworkmc/impl/loot/PatchworkLootPool.java
new file mode 100644
index 00000000..68770139
--- /dev/null
+++ b/patchwork-loot/src/main/java/net/patchworkmc/impl/loot/PatchworkLootPool.java
@@ -0,0 +1,28 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.patchworkmc.impl.loot;
+
+/**
+ * Forge does this through patching the constructor, we just add methods with
+ * mixins instead.
+ */
+public interface PatchworkLootPool {
+ void patchwork$setName(String name);
+}
diff --git a/patchwork-loot/src/main/java/net/patchworkmc/mixin/loot/MixinJsonDataLoader.java b/patchwork-loot/src/main/java/net/patchworkmc/mixin/loot/MixinJsonDataLoader.java
new file mode 100644
index 00000000..85b3b420
--- /dev/null
+++ b/patchwork-loot/src/main/java/net/patchworkmc/mixin/loot/MixinJsonDataLoader.java
@@ -0,0 +1,44 @@
+/*
+ * Minecraft Forge, Patchwork Project
+ * Copyright (c) 2016-2020, 2019-2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.patchworkmc.mixin.loot;
+
+import java.util.Map;
+
+import com.google.gson.JsonObject;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import net.minecraft.resource.JsonDataLoader;
+import net.minecraft.resource.SinglePreparationResourceReloadListener;
+import net.minecraft.util.Identifier;
+
+// TODO: Is there a better place to put this?
+@Mixin(JsonDataLoader.class)
+public abstract class MixinJsonDataLoader extends SinglePreparationResourceReloadListener