Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit 4b79ec8

Browse files
committed
Make slightly less hacky!
The idea is to add an inject in the same place as the method we would be redirecting (but are instead cancelling) so that we can capture locals, and grab the builder that we would otherwise be missing. The downside is that we are effectively overwriting the lambda that vanilla uses in favor of our own.
1 parent 1e2885a commit 4b79ec8

File tree

1 file changed

+28
-41
lines changed

1 file changed

+28
-41
lines changed

patchwork-loot/src/main/java/net/patchworkmc/mixin/loot/MixinLootManager.java

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,24 @@
1919

2020
package net.patchworkmc.mixin.loot;
2121

22-
import java.io.IOException;
23-
import java.util.Deque;
2422
import java.util.Map;
2523
import java.util.function.BiConsumer;
2624

2725
import com.google.common.collect.ImmutableMap;
28-
import com.google.common.collect.Queues;
2926
import com.google.gson.Gson;
30-
import com.google.gson.JsonElement;
3127
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;
3330
import org.spongepowered.asm.mixin.Mixin;
34-
import org.spongepowered.asm.mixin.Unique;
31+
import org.spongepowered.asm.mixin.Shadow;
3532
import org.spongepowered.asm.mixin.injection.At;
33+
import org.spongepowered.asm.mixin.injection.Inject;
3634
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;
3737

3838
import net.minecraft.loot.LootManager;
39+
import net.minecraft.loot.LootTable;
3940
import net.minecraft.resource.Resource;
4041
import net.minecraft.resource.ResourceManager;
4142
import net.minecraft.util.Identifier;
@@ -45,44 +46,30 @@
4546

4647
@Mixin(LootManager.class)
4748
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;
5152

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;
5556

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
7460
}
7561

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+
});
8774
}
8875
}

0 commit comments

Comments
 (0)