diff --git a/patches/minecraft/net/minecraft/world/level/storage/loot/LootPool.java.patch b/patches/minecraft/net/minecraft/world/level/storage/loot/LootPool.java.patch index 55da5a1bd8..c2850cab4b 100644 --- a/patches/minecraft/net/minecraft/world/level/storage/loot/LootPool.java.patch +++ b/patches/minecraft/net/minecraft/world/level/storage/loot/LootPool.java.patch @@ -1,6 +1,16 @@ --- a/net/minecraft/world/level/storage/loot/LootPool.java +++ b/net/minecraft/world/level/storage/loot/LootPool.java -@@ -112,6 +_,19 @@ +@@ -39,7 +_,8 @@ + NumberProvider f_79028_; + NumberProvider f_79029_; + +- LootPool(LootPoolEntryContainer[] p_165128_, LootItemCondition[] p_165129_, LootItemFunction[] p_165130_, NumberProvider p_165131_, NumberProvider p_165132_) { ++ LootPool(LootPoolEntryContainer[] p_165128_, LootItemCondition[] p_165129_, LootItemFunction[] p_165130_, NumberProvider p_165131_, NumberProvider p_165132_, @org.jetbrains.annotations.Nullable String name) { ++ this.name = name; + this.f_79023_ = p_165128_; + this.f_79024_ = p_165129_; + this.f_79025_ = LootItemConditions.m_81834_(p_165129_); +@@ -112,6 +_,23 @@ this.f_79028_.m_6169_(p_79052_.m_79365_(".rolls")); this.f_79029_.m_6169_(p_79052_.m_79365_(".bonusRolls")); } @@ -12,6 +22,10 @@ + if (this.isFrozen()) + throw new RuntimeException("Attempted to modify LootPool after being frozen!"); + } ++ @org.jetbrains.annotations.Nullable ++ private final String name; ++ @org.jetbrains.annotations.Nullable ++ public String getName() { return this.name; } + public NumberProvider getRolls() { return this.f_79028_; } + public NumberProvider getBonusRolls() { return this.f_79029_; } + public void setRolls (NumberProvider v){ checkFrozen(); this.f_79028_ = v; } @@ -28,3 +42,36 @@ public LootPool.Builder m_165133_(NumberProvider p_165134_) { this.f_79070_ = p_165134_; +@@ -153,11 +_,16 @@ + return this; + } + ++ public LootPool.Builder name(String name) { ++ this.name = name; ++ return this; ++ } ++ + public LootPool m_79082_() { + if (this.f_79070_ == null) { + throw new IllegalArgumentException("Rolls not set"); + } else { +- return new LootPool(this.f_79067_.toArray(new LootPoolEntryContainer[0]), this.f_79068_.toArray(new LootItemCondition[0]), this.f_79069_.toArray(new LootItemFunction[0]), this.f_79070_, this.f_79071_); ++ return new LootPool(this.f_79067_.toArray(new LootPoolEntryContainer[0]), this.f_79068_.toArray(new LootItemCondition[0]), this.f_79069_.toArray(new LootItemFunction[0]), this.f_79070_, this.f_79071_, name); + } + } + } +@@ -170,11 +_,13 @@ + LootItemFunction[] alootitemfunction = GsonHelper.m_13845_(jsonobject, "functions", new LootItemFunction[0], p_79092_, LootItemFunction[].class); + NumberProvider numberprovider = GsonHelper.m_13836_(jsonobject, "rolls", p_79092_, NumberProvider.class); + NumberProvider numberprovider1 = GsonHelper.m_13845_(jsonobject, "bonus_rolls", ConstantValue.m_165692_(0.0F), p_79092_, NumberProvider.class); +- return new LootPool(alootpoolentrycontainer, alootitemcondition, alootitemfunction, numberprovider, numberprovider1); ++ return new LootPool(alootpoolentrycontainer, alootitemcondition, alootitemfunction, numberprovider, numberprovider1, net.minecraftforge.common.ForgeHooks.readPoolName(jsonobject)); + } + + public JsonElement serialize(LootPool p_79094_, Type p_79095_, JsonSerializationContext p_79096_) { + JsonObject jsonobject = new JsonObject(); ++ if (p_79094_.name != null && !p_79094_.name.startsWith("custom#")) ++ jsonobject.add("name", p_79096_.serialize(p_79094_.name)); + jsonobject.add("rolls", p_79096_.serialize(p_79094_.f_79028_)); + jsonobject.add("bonus_rolls", p_79096_.serialize(p_79094_.f_79029_)); + jsonobject.add("entries", p_79096_.serialize(p_79094_.f_79023_)); diff --git a/patches/minecraft/net/minecraft/world/level/storage/loot/LootTable.java.patch b/patches/minecraft/net/minecraft/world/level/storage/loot/LootTable.java.patch index b5db369099..cc6a8d21d1 100644 --- a/patches/minecraft/net/minecraft/world/level/storage/loot/LootTable.java.patch +++ b/patches/minecraft/net/minecraft/world/level/storage/loot/LootTable.java.patch @@ -44,7 +44,7 @@ } for(int j = 0; j < this.f_79110_.length; ++j) { -@@ -205,6 +_,26 @@ +@@ -205,6 +_,50 @@ return new LootTable.Builder(); } @@ -66,6 +66,30 @@ + this.lootTableId = java.util.Objects.requireNonNull(id); + } + public ResourceLocation getLootTableId() { return this.lootTableId; } ++ ++ @org.jetbrains.annotations.Nullable ++ public LootPool getPool(String name) { ++ return f_79109_.stream().filter(e -> name.equals(e.getName())).findFirst().orElse(null); ++ } ++ ++ @org.jetbrains.annotations.Nullable ++ public LootPool removePool(String name) { ++ checkFrozen(); ++ for (LootPool pool : this.f_79109_) { ++ if (name.equals(pool.getName())) { ++ this.f_79109_.remove(pool); ++ return pool; ++ } ++ } ++ return null; ++ } ++ ++ public void addPool(LootPool pool) { ++ checkFrozen(); ++ if (f_79109_.stream().anyMatch(e -> e == pool || e.getName() != null && e.getName().equals(pool.getName()))) ++ throw new RuntimeException("Attempted to add a duplicate pool to loot table: " + pool.getName()); ++ this.f_79109_.add(pool); ++ } + //======================== FORGE END =============================================== + public static class Builder implements FunctionUserBuilder { diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 88c1ceacfb..407557013c 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -5,12 +5,14 @@ package net.minecraftforge.common; +import com.google.common.collect.Queues; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -778,6 +780,17 @@ public class ForgeHooks return newGameType; } + private static final ThreadLocal> lootContext = new ThreadLocal<>(); + 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 TriFunction> getLootTableDeserializer(Gson gson, String directory) { return (location, data, resourceManager) -> { @@ -797,9 +810,17 @@ public class ForgeHooks public static LootTable loadLootTable(Gson gson, ResourceLocation name, JsonElement data, boolean custom) { + Deque que = lootContext.get(); + if (que == null) + { + que = Queues.newArrayDeque(); + lootContext.set(que); + } + LootTable ret; try { + que.push(new LootTableContext(name, custom)); ret = gson.fromJson(data, LootTable.class); ret.setLootTableId(name); } @@ -807,6 +828,10 @@ public class ForgeHooks { throw e; } + finally + { + que.pop(); + } if (!custom) ret = ForgeEventFactory.loadLootTable(name, ret); @@ -817,6 +842,39 @@ public class ForgeHooks return ret; } + private static class LootTableContext + { + public final ResourceLocation name; + public final boolean vanilla; + public final boolean custom; + public int poolCount = 0; + + private LootTableContext(ResourceLocation name, boolean custom) + { + this.name = name; + this.custom = custom; + this.vanilla = "minecraft".equals(this.name.getNamespace()); + } + } + + public static String readPoolName(JsonObject json) + { + LootTableContext ctx = getLootTableContext(); + + if (json.has("name")) + return GsonHelper.getAsString(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); + } + /** * Returns a vanilla fluid type for the given fluid. *