|
19 | 19 |
|
20 | 20 | package net.patchworkmc.mixin.loot; |
21 | 21 |
|
22 | | -import java.io.IOException; |
23 | | -import java.util.Deque; |
24 | 22 | import java.util.Map; |
25 | 23 | import java.util.function.BiConsumer; |
26 | 24 |
|
27 | 25 | import com.google.common.collect.ImmutableMap; |
28 | | -import com.google.common.collect.Queues; |
29 | 26 | import com.google.gson.Gson; |
30 | | -import com.google.gson.JsonElement; |
31 | 27 | import com.google.gson.JsonObject; |
32 | | -import com.google.gson.JsonParseException; |
| 28 | +import org.apache.logging.log4j.Logger; |
| 29 | +import org.spongepowered.asm.mixin.Final; |
33 | 30 | import org.spongepowered.asm.mixin.Mixin; |
34 | | -import org.spongepowered.asm.mixin.Unique; |
| 31 | +import org.spongepowered.asm.mixin.Shadow; |
35 | 32 | import org.spongepowered.asm.mixin.injection.At; |
| 33 | +import org.spongepowered.asm.mixin.injection.Inject; |
36 | 34 | import org.spongepowered.asm.mixin.injection.Redirect; |
| 35 | +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
| 36 | +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; |
37 | 37 |
|
38 | 38 | import net.minecraft.loot.LootManager; |
| 39 | +import net.minecraft.loot.LootTable; |
39 | 40 | import net.minecraft.resource.Resource; |
40 | 41 | import net.minecraft.resource.ResourceManager; |
41 | 42 | import net.minecraft.util.Identifier; |
|
45 | 46 |
|
46 | 47 | @Mixin(LootManager.class) |
47 | 48 | public abstract class MixinLootManager extends MixinJsonDataLoader { |
48 | | - // should this also be part of the static threadlocal? |
49 | | - @Unique |
50 | | - private ResourceManager resourceManager; |
| 49 | + @Shadow |
| 50 | + @Final |
| 51 | + private static Gson GSON; |
51 | 52 |
|
52 | | - // TODO: is reentrancy necessary? |
53 | | - @Unique |
54 | | - private static ThreadLocal<Deque<LootManager>> lootContext = new ThreadLocal<Deque<LootManager>>(); |
| 53 | + @Shadow |
| 54 | + @Final |
| 55 | + private static Logger LOGGER; |
55 | 56 |
|
56 | | - @Redirect(method = "apply", at = @At(value = "INVOKE", target = "java/util/Map.forEach (Ljava/util/function/BiConsumer;)V")) |
57 | | - private void handleContext(Map<Identifier, JsonObject> map, BiConsumer<Identifier, JsonObject> consumer, Map<Identifier, JsonObject> sameMap, ResourceManager resourceManager, Profiler profiler) { |
58 | | - this.resourceManager = resourceManager; |
59 | | - Deque<LootManager> que = lootContext.get(); |
60 | | - |
61 | | - if (que == null) { |
62 | | - que = Queues.newArrayDeque(); |
63 | | - lootContext.set(que); |
64 | | - } |
65 | | - |
66 | | - que.push((LootManager) (Object) this); |
67 | | - |
68 | | - try { |
69 | | - map.forEach(consumer); |
70 | | - } finally { |
71 | | - this.resourceManager = null; |
72 | | - lootContext.get().pop(); |
73 | | - } |
| 57 | + @Redirect(method = "apply", at = @At(value = "INVOKE", target = "java/util/Map.forEach (Ljava/util/function/BiConsumer;)V", ordinal = 0)) |
| 58 | + private void cancel_forEach(Map<Identifier, JsonObject> map, BiConsumer<Identifier, JsonObject> consumer) { |
| 59 | + // ignore this call, we're gonna reintroduce it but with capturing locals |
74 | 60 | } |
75 | 61 |
|
76 | | - @Redirect(method = "method_20711", at = @At(value = "INVOKE", target = "com/google/gson/Gson.fromJson (Lcom/google/gson/JsonElement;Ljava/lang/Class;)Ljava/lang/Object;")) |
77 | | - private static Object loadLootTable(Gson GSON, JsonElement elem, Class cls, ImmutableMap.Builder _bld, Identifier id, JsonObject obj) throws IOException { |
78 | | - LootManager lootManager = lootContext.get().peek(); |
79 | | - |
80 | | - if (lootManager == null) { |
81 | | - throw new JsonParseException("Invalid call stack, could not grab loot manager!"); // Should I throw this? Do we care about custom deserializers outside the manager? |
82 | | - } |
83 | | - |
84 | | - ResourceManager resourceManager = ((MixinLootManager) (Object) lootManager).resourceManager; |
85 | | - Resource res = resourceManager.getResource(((MixinLootManager) (Object) lootManager).getPreparedPath(id)); |
86 | | - return LootHooks.loadLootTable(GSON, id, elem, res == null || !res.getResourcePackName().equals("Default"), lootManager); |
| 62 | + @Inject(method = "apply", at = @At(value = "INVOKE", target = "java/util/Map.forEach (Ljava/util/function/BiConsumer;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) |
| 63 | + private void reintroduce_forEach(Map<Identifier, JsonObject> map, ResourceManager resourceManager, Profiler profiler, CallbackInfo info, ImmutableMap.Builder<Identifier, LootTable> builder) { |
| 64 | + map.forEach((id, jsonObject) -> { |
| 65 | + try { |
| 66 | + LootManager lootManager = (LootManager) (Object) this; |
| 67 | + Resource res = resourceManager.getResource(this.getPreparedPath(id)); |
| 68 | + LootTable lootTable = LootHooks.loadLootTable(GSON, id, jsonObject, res == null || !res.getResourcePackName().equals("Default"), lootManager); |
| 69 | + builder.put(id, lootTable); |
| 70 | + } catch (Exception ex) { |
| 71 | + LOGGER.error("Couldn't parse loot table {}", id, ex); |
| 72 | + } |
| 73 | + }); |
87 | 74 | } |
88 | 75 | } |
0 commit comments