From e4722f5f7b2016e28e68d94dd70de14265742f33 Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 13:34:37 +0300
Subject: [PATCH 01/53] Add AddPoolAction
---
gradle.properties | 4 +-
.../loottablemodifier/LootTableModifier.java | 1 +
.../api/LootModifierActionTypes.java | 28 ++
.../api/datagen/NewLootModifierProvider.java | 252 ++++++++++++++++++
.../datagen/LootTableModifierDatagen.java | 51 +++-
.../resource/NewLootModifier.java | 73 +++++
.../resource/action/AddPoolAction.java | 44 +++
.../resource/action/LootModifierAction.java | 15 ++
.../action/LootModifierActionType.java | 15 ++
9 files changed, 479 insertions(+), 4 deletions(-)
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierActionType.java
diff --git a/gradle.properties b/gradle.properties
index 306cd33..04f3ff0 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -8,9 +8,9 @@ minecraft_version = 1.21.4
# These should be automatically updated, unless the environment
# variable "DISABLE_PROPERTIES_UPDATE" is set.
-fapi_version = 0.119.0+1.21.4
+fapi_version = 0.119.2+1.21.4
yarn_version = 1.21.4+build.8
-loader_version = 0.16.10
+loader_version = 0.16.14
# Dependencies
## DevAuth, check at https://github.com/DJtheRedstoner/DevAuth
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index 7bb3801..b8dab4e 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -9,6 +9,7 @@
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
+import net.minecraft.loot.condition.LootCondition;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryOps;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
new file mode 100644
index 0000000..fdbfc98
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
@@ -0,0 +1,28 @@
+package top.offsetmonkey538.loottablemodifier.api;
+
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.registry.Registry;
+import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.NotNull;
+import top.offsetmonkey538.loottablemodifier.resource.action.AddPoolAction;
+import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
+import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierActionType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static top.offsetmonkey538.loottablemodifier.LootTableModifier.id;
+
+public final class LootModifierActionTypes {
+ private LootModifierActionTypes() {
+
+ }
+
+ public static final LootModifierActionType ADD_ENTRY = register(id("add_pool"), AddPoolAction.CODEC);
+
+ private static LootModifierActionType register(final @NotNull Identifier id, final @NotNull MapCodec extends LootModifierAction> codec) {
+ return Registry.register(LootModifierActionType.REGISTRY, id, new LootModifierActionType(codec));
+ }
+}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
new file mode 100644
index 0000000..75bd957
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
@@ -0,0 +1,252 @@
+package top.offsetmonkey538.loottablemodifier.api.datagen;
+
+import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
+import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider;
+import net.fabricmc.loader.api.FabricLoader;
+import net.fabricmc.loader.api.MappingResolver;
+import net.minecraft.data.DataOutput;
+import net.minecraft.data.loottable.LootTableGenerator;
+import net.minecraft.entity.EntityType;
+import net.minecraft.loot.LootPool;
+import net.minecraft.loot.LootTable;
+import net.minecraft.registry.RegistryKey;
+import net.minecraft.registry.RegistryWrapper;
+import net.minecraft.util.Identifier;
+import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
+import top.offsetmonkey538.loottablemodifier.resource.NewLootModifier;
+import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import static top.offsetmonkey538.loottablemodifier.LootTableModifier.MOD_ID;
+
+/**
+ * FIXME: wrong
+ * A datagen provider for creating loot modifiers.
+ *
+ * Override {@link #generate(RegistryWrapper.WrapperLookup) generate()} and use the {@code addModifier(...)} methods to add modifiers.
+ *
+ *
{@code
+ * @Override
+ * protected void generate(RegistryWrapper.WrapperLookup lookup) {
+ * addModifier(
+ * Identifier.of("testmod", "drop_tnt"),
+ * LootPool.builder()
+ * .rolls(ConstantLootNumberProvider.create(1))
+ * .with(
+ * ItemEntry.builder(Items.TNT)
+ * .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 1)))
+ * ),
+ * EntityType.CREEPER,
+ * EntityType.ZOMBIE
+ * );
+ * }
+ * }
+ */
+public abstract class NewLootModifierProvider extends FabricCodecDataProvider {
+ private BiConsumer provider;
+
+ public NewLootModifierProvider(FabricDataOutput dataOutput, CompletableFuture registriesFuture) {
+ super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, MOD_ID + "/loot_modifier", NewLootModifier.CODEC);
+ }
+
+ @Override
+ protected void configure(BiConsumer provider, RegistryWrapper.WrapperLookup lookup) {
+ this.provider = provider;
+ generate(lookup);
+ }
+
+ @Override
+ public String getName() {
+ return "New Loot Table Modifiers";
+ }
+
+ /**
+ * Override and use {@code addModifier()} methods to add modifiers.
+ *
+ * @param lookup A lookup for registries.
+ */
+ protected abstract void generate(RegistryWrapper.WrapperLookup lookup);
+
+ /**
+ * Adds a new loot table modifier for the given {@link EntityType}s.
+ *
+ * @param name Name of this modifier
+ * @param builder The loot pool to add
+ * @param modifies The {@link EntityType} to add the modifier to
+ * @param modifiesAdditional Additional {@link EntityType}s to add the modifier to
+ */
+ protected void addModifier(Identifier name, LootModifierAction.Builder builder, EntityType> modifies, EntityType>... modifiesAdditional) {
+ addModifier(
+ name,
+ List.of(builder),
+ modifies,
+ modifiesAdditional
+ );
+ }
+
+ /**
+ * Adds a new loot table modifier for the given {@link EntityType}s.
+ *
+ * @param name Name of this modifier
+ * @param builders The loot pools to add
+ * @param modifies The {@link EntityType} to add the modifier to
+ * @param modifiesAdditional Additional {@link EntityType}s to add the modifier to
+ */
+ protected void addModifier(Identifier name, List builders, EntityType> modifies, EntityType>... modifiesAdditional) {
+ addModifier(
+ name,
+ builders,
+ Stream.concat(Stream.of(modifies), Stream.of(modifiesAdditional)).map(EntityLootTableIdGetter.get).toList()
+ );
+ }
+
+ /**
+ * Adds a new loot table modifier for the given {@link RegistryKey}s.
+ *
+ * @param name Name of this modifier
+ * @param builder The loot pool to add
+ * @param modifies The {@link RegistryKey} to add the modifier to
+ * @param modifiesAdditional Additional {@link RegistryKey}s to add the modifier to
+ */
+ protected void addModifier(Identifier name, LootModifierAction.Builder builder, RegistryKey> modifies, RegistryKey>... modifiesAdditional) {
+ addModifier(
+ name,
+ List.of(builder),
+ modifies,
+ modifiesAdditional
+ );
+ }
+
+ /**
+ * Adds a new loot table modifier for the given {@link RegistryKey}s.
+ *
+ * @param name Name of this modifier
+ * @param builders The loot pools to add
+ * @param modifies The {@link RegistryKey} to add the modifier to
+ * @param modifiesAdditional Additional {@link RegistryKey}s to add the modifier to
+ */
+ protected void addModifier(Identifier name, List builders, RegistryKey> modifies, RegistryKey>... modifiesAdditional) {
+ addModifier(
+ name,
+ builders,
+ Stream.concat(Stream.of(modifies), Stream.of(modifiesAdditional)).map(RegistryKey::getValue).toList()
+ );
+ }
+
+ /**
+ * Adds a new loot table modifier for the given {@link Identifier}s.
+ *
+ * @param name Name of this modifier
+ * @param builder The loot pool to add
+ * @param modifies The {@link Identifier} to add the modifier to
+ * @param modifiesAdditional Additional {@link Identifier}s to add the modifier to
+ */
+ protected void addModifier(Identifier name, LootModifierAction.Builder builder, Identifier modifies, Identifier... modifiesAdditional) {
+ addModifier(
+ name,
+ List.of(builder),
+ modifies,
+ modifiesAdditional
+ );
+ }
+
+ /**
+ * Adds a new loot table modifier for the given {@link Identifier}s.
+ *
+ * @param name Name of this modifier
+ * @param builders The loot pools to add
+ * @param modifies The {@link Identifier} to add the modifier to
+ * @param modifiesAdditional Additional {@link Identifier}s to add the modifier to
+ */
+ protected void addModifier(Identifier name, List builders, Identifier modifies, Identifier... modifiesAdditional) {
+ addModifier(
+ name,
+ builders,
+ Stream.concat(Stream.of(modifies), Stream.of(modifiesAdditional)).toList()
+ );
+ }
+
+ private void addModifier(Identifier name, List builders, List modifies) {
+ provider.accept(name, new NewLootModifier(
+ new ArrayList<>(modifies),
+ builders.stream()
+ .map(LootModifierAction.Builder::build)
+ .toList()
+ ));
+ }
+
+
+
+ private static class EntityLootTableIdGetter {
+ // Resolver returns the provided name (like 'method_16351') when it fails to map it
+ private static final MappingResolver RESOLVER = FabricLoader.getInstance().getMappingResolver();
+
+ private static final String V1d21d2 = RESOLVER.mapMethodName("intermediary", "net.minecraft.class_1299", "method_16351", "()Ljava/util/Optional;");
+ private static final String V1d20d5 = RESOLVER.mapMethodName("intermediary", "net.minecraft.class_1299", "method_16351", "()Lnet/minecraft/class_5321;");
+
+ // mod only supports down to 1.20.5 soo: private static final String V1d14d0 = RESOLVER.mapMethodName("intermediary", "net.minecraft.class_1299", "method_16351", "()Lnet/minecraft/util/Identifier;");
+
+ public static final Function, Identifier> get;
+
+ // Should be executed when class is first loaded/accessed
+ static {
+ try {
+ //final Class> entityType = EntityType.class;
+ final Class> entityType = Class.forName(RESOLVER.mapClassName("intermediary", "net.minecraft.class_1299"));
+ final Method method;
+
+ // 1.21.2 to future:tm:
+ if (isMethod(entityType, V1d21d2)) {
+ method = entityType.getDeclaredMethod(V1d21d2);
+ method.setAccessible(true);
+ get = entity -> {
+ try {
+ @SuppressWarnings("unchecked")
+ final Optional> optional = (Optional>) method.invoke(entity);
+ if (optional.isPresent()) return optional.get().getValue();
+ throw new IllegalStateException("Entity '" + entity + "' has no loot table! (It is created with 'builder.dropsNothing()')");
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ };
+ }
+
+ // 1.20.5 to 1.21.1
+ else if (isMethod(entityType, V1d20d5)) {
+ method = entityType.getDeclaredMethod(V1d20d5);
+ method.setAccessible(true);
+ get = entity -> {
+ try {
+ return ((RegistryKey>) method.invoke(entity)).getValue();
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ };
+ }
+
+ else {
+ throw new IllegalStateException("No valid way to get entity loot table id found!");
+ }
+ } catch (NoSuchMethodException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static boolean isMethod(Class> clazz, String method) {
+ try {
+ clazz.getDeclaredMethod(method);
+ return true;
+ } catch (NoSuchMethodException e) {
+ LOGGER.warn("", e);
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java b/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java
index d9e1613..4324dc7 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java
@@ -14,6 +14,8 @@
import net.minecraft.loot.provider.number.UniformLootNumberProvider;
import net.minecraft.registry.RegistryWrapper;
import top.offsetmonkey538.loottablemodifier.api.datagen.LootModifierProvider;
+import top.offsetmonkey538.loottablemodifier.api.datagen.NewLootModifierProvider;
+import top.offsetmonkey538.loottablemodifier.resource.action.AddPoolAction;
import java.util.concurrent.CompletableFuture;
@@ -25,7 +27,8 @@ public class LootTableModifierDatagen implements DataGeneratorEntrypoint {
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
final FabricDataGenerator.Pack pack = fabricDataGenerator.createBuiltinResourcePack(id("example_pack"));
- pack.addProvider(ModLootModifierProvider::new);
+ //pack.addProvider(ModLootModifierProvider::new);
+ pack.addProvider(NewModLootModifierProvider::new);
}
private static class ModLootModifierProvider extends LootModifierProvider {
@@ -59,7 +62,7 @@ protected void generate(RegistryWrapper.WrapperLookup lookup) {
ItemEntry.builder(Items.NETHERITE_SWORD).apply(
EnchantWithLevelsLootFunction
.builder(lookup, UniformLootNumberProvider.create(20, 39))
- //.builder(UniformLootNumberProvider.create(20, 39))
+ //.builder(UniformLootNumberProvider.create(20, 39))
)
),
@@ -67,4 +70,48 @@ protected void generate(RegistryWrapper.WrapperLookup lookup) {
);
}
}
+
+ private static class NewModLootModifierProvider extends NewLootModifierProvider {
+ public NewModLootModifierProvider(FabricDataOutput dataOutput, CompletableFuture registriesFuture) {
+ super(dataOutput, registriesFuture);
+ }
+
+ @Override
+ protected void generate(RegistryWrapper.WrapperLookup lookup) {
+ addModifier(
+ id("drop_tnt"),
+
+
+ AddPoolAction.builder(
+ LootPool.builder()
+ .rolls(ConstantLootNumberProvider.create(1))
+ .with(
+ ItemEntry.builder(Items.TNT)
+ .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 1)))
+ )
+ ),
+
+ EntityType.CREEPER,
+ EntityType.ZOMBIE
+ );
+
+ //todo: temp
+ addModifier(
+ id("test"),
+
+ AddPoolAction.builder(
+ LootPool.builder()
+ .with(
+ ItemEntry.builder(Items.NETHERITE_SWORD).apply(
+ EnchantWithLevelsLootFunction
+ .builder(lookup, UniformLootNumberProvider.create(20, 39))
+ //.builder(UniformLootNumberProvider.create(20, 39))
+ )
+ )
+ ),
+
+ LootTables.ABANDONED_MINESHAFT_CHEST
+ );
+ }
+ }
}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
new file mode 100644
index 0000000..b69a11c
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
@@ -0,0 +1,73 @@
+package top.offsetmonkey538.loottablemodifier.resource;
+
+import com.google.common.collect.ImmutableList;
+import com.ibm.icu.impl.EmojiProps;
+import com.mojang.datafixers.util.Either;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder;
+import net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder;
+import net.minecraft.loot.LootPool;
+import net.minecraft.loot.LootTable;
+import net.minecraft.loot.condition.LootCondition;
+import net.minecraft.loot.condition.LootConditionConsumingBuilder;
+import net.minecraft.loot.entry.LootPoolEntry;
+import net.minecraft.loot.function.LootFunction;
+import net.minecraft.loot.function.LootFunctionConsumingBuilder;
+import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
+import net.minecraft.loot.provider.number.LootNumberProvider;
+import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.NotNull;
+import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public record NewLootModifier(List modifies, List actions) {
+ public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
+ Codec.either(Identifier.CODEC, Identifier.CODEC.listOf()).fieldOf("modifies").forGetter(NewLootModifier::modifiesEither),
+ Codec.either(LootModifierAction.CODEC, LootModifierAction.CODEC.listOf()).fieldOf("actions").forGetter(NewLootModifier::actionsEither)
+ //LootModifierAction.CODEC.listOf().fieldOf("")
+ //Codec.mapEither(LootPool.CODEC.listOf().fieldOf("pools"), LootPool.CODEC.listOf().fieldOf("loot_pools")).forGetter(NewLootModifier::poolsEither)
+ ).apply(instance, NewLootModifier::new));
+
+ private NewLootModifier(Either> modifiesEither, Either> actionsEither) {
+ this(
+ new ArrayList<>(modifiesEither.right().orElseGet(() -> List.of(modifiesEither.left().orElseThrow()))),
+ new ArrayList<>(actionsEither.right().orElseGet(() -> List.of(actionsEither.left().orElseThrow())))
+ );
+ }
+
+ private Either> modifiesEither() {
+ if (modifies.size() == 1) return Either.left(modifies.get(0));
+ return Either.right(modifies);
+ }
+
+ private Either> actionsEither() {
+ if (actions.size() == 1) return Either.left(actions.get(0));
+ return Either.right(actions);
+ }
+
+ // Don't think this is needed? public static NewLootModifier.Builder builder() {
+ // Don't think this is needed? return new NewLootModifier.Builder();
+ // Don't think this is needed? }
+
+ // Don't think this is needed? public static class Builder {
+ // Don't think this is needed? private final ImmutableList.Builder modifies = ImmutableList.builder();
+ // Don't think this is needed? private final ImmutableList.Builder actions = ImmutableList.builder();
+ // Don't think this is needed?
+ // Don't think this is needed? public NewLootModifier.Builder modifies(@NotNull Identifier... modifies) {
+ // Don't think this is needed? this.modifies.add(modifies);
+ // Don't think this is needed? return this;
+ // Don't think this is needed? }
+ // Don't think this is needed?
+ // Don't think this is needed? public NewLootModifier.Builder conditionally(@NotNull LootModifierAction.Builder action) {
+ // Don't think this is needed? this.actions.add(action.build());
+ // Don't think this is needed? return this;
+ // Don't think this is needed? }
+ // Don't think this is needed?
+ // Don't think this is needed? public NewLootModifier build() {
+ // Don't think this is needed? return new NewLootModifier(this.modifies.build(), this.actions.build());
+ // Don't think this is needed? }
+ // Don't think this is needed? }
+}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
new file mode 100644
index 0000000..4877913
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
@@ -0,0 +1,44 @@
+package top.offsetmonkey538.loottablemodifier.resource.action;
+
+import com.google.common.collect.ImmutableList;
+import com.mojang.serialization.MapCodec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.block.Block;
+import net.minecraft.loot.LootPool;
+import org.jetbrains.annotations.NotNull;
+import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
+
+import java.util.List;
+
+public record AddPoolAction(List pools) implements LootModifierAction {
+ public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
+ LootPool.CODEC.listOf().fieldOf("pools").forGetter(AddPoolAction::pools)
+ ).apply(instance, AddPoolAction::new));
+
+ @Override
+ public LootModifierActionType getType() {
+ return LootModifierActionTypes.ADD_ENTRY;
+ }
+
+ public static AddPoolAction.Builder builder(@NotNull LootPool.Builder poolBuilder) {
+ return new AddPoolAction.Builder(poolBuilder);
+ }
+
+ public static class Builder implements LootModifierAction.Builder {
+ private final ImmutableList.Builder pools = ImmutableList.builder();
+
+ private Builder(@NotNull LootPool.Builder poolBuilder) {
+ pools.add(poolBuilder.build());
+ }
+
+ public AddPoolAction.Builder pool(LootPool.Builder poolBuilder) {
+ this.pools.add(poolBuilder.build());
+ return this;
+ }
+
+ @Override
+ public AddPoolAction build() {
+ return new AddPoolAction(pools.build());
+ }
+ }
+}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
new file mode 100644
index 0000000..3d1924b
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
@@ -0,0 +1,15 @@
+package top.offsetmonkey538.loottablemodifier.resource.action;
+
+import com.mojang.serialization.Codec;
+import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
+
+public interface LootModifierAction {
+ Codec CODEC = LootModifierActionType.REGISTRY.getCodec().dispatch(LootModifierAction::getType, LootModifierActionType::codec);
+
+ LootModifierActionType getType();
+
+ @FunctionalInterface
+ interface Builder {
+ LootModifierAction build();
+ }
+}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierActionType.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierActionType.java
new file mode 100644
index 0000000..3d8646f
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierActionType.java
@@ -0,0 +1,15 @@
+package top.offsetmonkey538.loottablemodifier.resource.action;
+
+import com.mojang.serialization.Lifecycle;
+import com.mojang.serialization.MapCodec;
+import net.minecraft.registry.Registry;
+import net.minecraft.registry.RegistryKey;
+import net.minecraft.registry.SimpleRegistry;
+import org.jetbrains.annotations.NotNull;
+import top.offsetmonkey538.loottablemodifier.LootTableModifier;
+
+public record LootModifierActionType(@NotNull MapCodec extends LootModifierAction> codec) {
+ public static final Registry REGISTRY = new SimpleRegistry<>(
+ RegistryKey.ofRegistry(LootTableModifier.id("loot_modifier_action_types")), Lifecycle.stable()
+ );
+}
From b9ee027c11638df542c7b05bffb23434b4288089 Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 14:51:32 +0300
Subject: [PATCH 02/53] Implement loading and applying NewLootModifier, remove
usages of original LootModifier
---
.../loottablemodifier/LootTableModifier.java | 84 +++++--------------
.../api/LootModifierActionTypes.java | 4 +
.../api/datagen/NewLootModifierProvider.java | 1 -
.../resource/NewLootModifier.java | 79 ++++++++++++++++-
.../resource/action/AddPoolAction.java | 15 ++++
.../resource/action/LootModifierAction.java | 9 ++
6 files changed, 122 insertions(+), 70 deletions(-)
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index b8dab4e..91658cc 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -19,11 +19,13 @@
import net.minecraft.resource.ResourceManager;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
+import net.minecraft.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
-import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
+import top.offsetmonkey538.loottablemodifier.resource.NewLootModifier;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@@ -37,27 +39,32 @@ public class LootTableModifier implements ModInitializer {
@Override
public void onInitialize() {
+ LootModifierActionTypes.register();
+
if(FabricLoader.getInstance().isDevelopmentEnvironment()) ResourceManagerHelper.registerBuiltinResourcePack(id("example_pack"), FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow(), Text.of("Example Pack"), ResourcePackActivationType.NORMAL);
}
public static void runModification(ResourceManager resourceManager, Registry lootRegistry, RegistryOps registryOps) {
- final Map modifiers = loadModifiers(resourceManager, registryOps);
+ final Map modifiers = loadModifiers(resourceManager, registryOps);
+ final Map failedModifiers = new HashMap<>(0);
int amountModified = 0;
LOGGER.info("Applying loot table modifiers...");
- for (RegistryEntry.Reference tableReference : getRegistryAsWrapper(lootRegistry).streamEntries().toList()) {
- final RegistryKey tableKey = tableReference.registryKey();
+ for (Map.Entry modifierEntry : modifiers.entrySet()) {
+ final NewLootModifier modifier = modifierEntry.getValue();
+
+ amountModified += modifier.apply(lootRegistry);
- amountModified += applyModifiers(lootRegistry.get(tableKey), tableKey, modifiers);
+ if (!modifier.modifies().isEmpty()) failedModifiers.put(modifierEntry.getKey(), modifier);
}
- modifiersApplied(amountModified, modifiers);
+ modifiersApplied(amountModified, failedModifiers);
}
- private static Map loadModifiers(ResourceManager resourceManager, RegistryOps registryOps) {
+ private static Map loadModifiers(ResourceManager resourceManager, RegistryOps registryOps) {
LOGGER.info("Loading loot table modifiers...");
- final Map result = new HashMap<>();
+ final Map result = new HashMap<>();
for (Map.Entry entry : resourceManager.findResources(MOD_ID + "/loot_modifier", path -> path.toString().endsWith(".json")).entrySet()) {
final Identifier id = entry.getKey();
@@ -65,7 +72,7 @@ private static Map loadModifiers(ResourceManager resou
try {
result.put(
id,
- LootModifier.CODEC.decode(registryOps, JsonParser.parseReader(entry.getValue().getReader())).getOrThrow().getFirst()
+ NewLootModifier.CODEC.decode(registryOps, JsonParser.parseReader(entry.getValue().getReader())).getOrThrow().getFirst()
);
} catch (IOException e) {
//noinspection StringConcatenationArgumentToLogCall
@@ -78,44 +85,13 @@ private static Map loadModifiers(ResourceManager resou
return result;
}
- // Returns: amount of loot tables modified
- private static int applyModifiers(LootTable table, RegistryKey tableKey, Map modifiers) {
- final Identifier currentId = tableKey.getValue();
- final List usable = modifiers.keySet().stream().filter(entry -> modifiers.get(entry).modifies().contains(currentId)).toList();
-
- if (usable.isEmpty()) return 0;
-
- final List newPools = ImmutableList.builder()
- .addAll(table.pools)
- .addAll(
- usable.stream()
- .map(modifiers::get)
- .map(LootModifier::pools)
- .flatMap(List::stream)
- .toList()
- )
- .build();
-
- ((LootTableAccessor) table).setPools(newPools);
-
- for (Identifier modifierId : usable) {
- final LootModifier modifier = modifiers.get(modifierId);
-
- modifier.modifies().remove(currentId);
-
- if (modifier.modifies().isEmpty()) modifiers.remove(modifierId);
- }
-
- return usable.size();
- }
-
- private static void modifiersApplied(int amountModified, Map modifiers) {
+ private static void modifiersApplied(int amountModified, Map failedModifiers) {
LOGGER.info("Modified {} loot tables!", amountModified);
- if (modifiers.isEmpty()) return;
+ if (failedModifiers.isEmpty()) return;
LOGGER.warn("There were unused modifiers:");
- for (Map.Entry entry : modifiers.entrySet()) {
+ for (Map.Entry entry : failedModifiers.entrySet()) {
LOGGER.warn("\tModifier '{}' failed to modify loot table for entities: ", entry.getKey());
for (Identifier id : entry.getValue().modifies()) {
LOGGER.warn("\t\t- {}", id);
@@ -123,28 +99,6 @@ private static void modifiersApplied(int amountModified, Map RegistryWrapper getRegistryAsWrapper(@NotNull Registry registry) {
- //noinspection ConstantValue,RedundantSuppression: On lower versions, Registry doesn't extend RegistryWrapper and thus the 'isAssignableFrom' check can be false. The redundant supression is for the unchecked cast below.
- if (RegistryWrapper.class.isAssignableFrom(registry.getClass()))
- //noinspection unchecked,RedundantCast: I swear it casts 🤞
- return (RegistryWrapper) registry;
-
- try {
- //noinspection unchecked: Seriously I swear 🤞🤞
- return (RegistryWrapper) registry.getClass().getDeclaredMethod(FabricLoader.getInstance().getMappingResolver().mapMethodName("intermediary", "net.minecraft.class_2378", "method_46771", "()Lnet/minecraft/class_7225$class_7226;")).invoke(registry);
- } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
- }
-
public static Identifier id(String path) {
return Identifier.of(MOD_ID, path);
}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
index fdbfc98..4802aef 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
@@ -25,4 +25,8 @@ private LootModifierActionTypes() {
private static LootModifierActionType register(final @NotNull Identifier id, final @NotNull MapCodec extends LootModifierAction> codec) {
return Registry.register(LootModifierActionType.REGISTRY, id, new LootModifierActionType(codec));
}
+
+ public static void register() {
+ // Registers action types by loading the class
+ }
}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
index 75bd957..430896e 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
@@ -12,7 +12,6 @@
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.Identifier;
-import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
import top.offsetmonkey538.loottablemodifier.resource.NewLootModifier;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
index b69a11c..3717e6a 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
@@ -7,6 +7,7 @@
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder;
import net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder;
+import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.condition.LootCondition;
@@ -16,14 +17,21 @@
import net.minecraft.loot.function.LootFunctionConsumingBuilder;
import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
import net.minecraft.loot.provider.number.LootNumberProvider;
+import net.minecraft.registry.Registry;
+import net.minecraft.registry.RegistryKey;
+import net.minecraft.registry.RegistryWrapper;
+import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
+import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
-public record NewLootModifier(List modifies, List actions) {
+// Using ArrayList as I want it to be modifiable because I empty it when applying, so I can check for things that weren't applied
+public record NewLootModifier(@NotNull ArrayList modifies, @NotNull List actions) {
public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.either(Identifier.CODEC, Identifier.CODEC.listOf()).fieldOf("modifies").forGetter(NewLootModifier::modifiesEither),
Codec.either(LootModifierAction.CODEC, LootModifierAction.CODEC.listOf()).fieldOf("actions").forGetter(NewLootModifier::actionsEither)
@@ -31,10 +39,16 @@ public record NewLootModifier(List modifies, List> modifiesEither, Either> actionsEither) {
+ private NewLootModifier(@NotNull Either> modifiesEither, @NotNull Either> actionsEither) {
this(
- new ArrayList<>(modifiesEither.right().orElseGet(() -> List.of(modifiesEither.left().orElseThrow()))),
- new ArrayList<>(actionsEither.right().orElseGet(() -> List.of(actionsEither.left().orElseThrow())))
+ modifiesEither.right().orElseGet(() -> List.of(modifiesEither.left().orElseThrow())),
+ actionsEither.right().orElseGet(() -> List.of(actionsEither.left().orElseThrow()))
+ );
+ }
+ public NewLootModifier(@NotNull List modifies, @NotNull List actions) {
+ this(
+ new ArrayList<>(modifies),
+ actions
);
}
@@ -48,6 +62,63 @@ private Either> actionsEither() {
return Either.right(actions);
}
+ /**
+ * @param tableRegistry registry of loot tables to modify
+ * @return amount of loot tables modified
+ */
+ public int apply(final @NotNull Registry tableRegistry) {
+ final List> tableKeys = getRegistryAsWrapper(tableRegistry).streamEntries().map(RegistryEntry.Reference::registryKey).filter(key -> modifies.contains(key.getValue())).toList();
+ if (tableKeys.isEmpty()) return 0;
+ // At this point only ones in 'modifies' remain
+
+ int modified = 0;
+
+ for (RegistryKey key : tableKeys) {
+ final LootTable table = tableRegistry.get(key);
+
+ if (table == null) throw new IllegalStateException("Loot table with id '%s' is null!".formatted(key));
+
+ modified += apply(table) ? 1 : 0;
+ modifies.remove(key.getValue());
+ }
+
+ return modified;
+ }
+
+ /**
+ * @param table table to modify
+ * @return true when any of the 'actions' could be applied, false otherwise
+ */
+ private boolean apply(final @NotNull LootTable table) {
+ boolean result = false;
+ for (LootModifierAction action : actions) {
+ if (action.apply(table)) result = true;
+ }
+ return result;
+ }
+
+ /*
+ In 1.21.4, the 'Registry' class extends 'RegistryWrapper' and inherits the 'streamEntries' method from *it*.
+ In 1.20.5, the 'Registry' class *doesn't* extend the 'RegistryWrapper' and implements its own 'streamEntries' method.
+ Compiling on both versions works, because the names of the methods are the same, but they compile to different intermediary names, thus a jar compiled for 1.20.5 doesn't work on 1.21.4 and vice versa.
+ Solution: Turn the 'Registry' into a 'RegistryWrapper' as its 'streamEntries' retains the same intermediary on both versions.
+ If 'Registry' implements 'RegistryWrapper': cast it
+ Else: call 'getReadOnlyWrapper' on the registry (doesn't exist on 1.21.4, otherwise would've used 'registry.getReadOnlyWrapper().streamEntries()')
+ */
+ private static RegistryWrapper getRegistryAsWrapper(@NotNull Registry registry) {
+ //noinspection ConstantValue,RedundantSuppression: On lower versions, Registry doesn't extend RegistryWrapper and thus the 'isAssignableFrom' check can be false. The redundant supression is for the unchecked cast below.
+ if (RegistryWrapper.class.isAssignableFrom(registry.getClass()))
+ //noinspection unchecked,RedundantCast: I swear it casts 🤞
+ return (RegistryWrapper) registry;
+
+ try {
+ //noinspection unchecked: Seriously I swear 🤞🤞
+ return (RegistryWrapper) registry.getClass().getDeclaredMethod(FabricLoader.getInstance().getMappingResolver().mapMethodName("intermediary", "net.minecraft.class_2378", "method_46771", "()Lnet/minecraft/class_7225$class_7226;")).invoke(registry);
+ } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
// Don't think this is needed? public static NewLootModifier.Builder builder() {
// Don't think this is needed? return new NewLootModifier.Builder();
// Don't think this is needed? }
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
index 4877913..574cd94 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
@@ -5,8 +5,11 @@
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.block.Block;
import net.minecraft.loot.LootPool;
+import net.minecraft.loot.LootTable;
+import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
+import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
import java.util.List;
@@ -20,6 +23,18 @@ public LootModifierActionType getType() {
return LootModifierActionTypes.ADD_ENTRY;
}
+ @Override
+ public boolean apply(@NotNull LootTable table) {
+ final List newPools = ImmutableList.builder()
+ .addAll(table.pools)
+ .addAll(this.pools)
+ .build();
+
+ ((LootTableAccessor) table).setPools(newPools);
+
+ return true;
+ }
+
public static AddPoolAction.Builder builder(@NotNull LootPool.Builder poolBuilder) {
return new AddPoolAction.Builder(poolBuilder);
}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
index 3d1924b..c5064d4 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
@@ -1,6 +1,8 @@
package top.offsetmonkey538.loottablemodifier.resource.action;
import com.mojang.serialization.Codec;
+import net.minecraft.loot.LootTable;
+import org.jetbrains.annotations.NotNull;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
public interface LootModifierAction {
@@ -8,6 +10,13 @@ public interface LootModifierAction {
LootModifierActionType getType();
+ /**
+ * Applies this action to the provided table
+ * @param table the table to apply to
+ * @return true when table was modified, false otherwise
+ */
+ boolean apply(final @NotNull LootTable table);
+
@FunctionalInterface
interface Builder {
LootModifierAction build();
From 97d677a6fcd710e7341744b4c040b77534393e1e Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 15:52:47 +0300
Subject: [PATCH 03/53] Make NewLootModifier compatible with old format (the
one with just 'pools' (or the very old one with 'loot_pools') next to
'modifies')
---
.../loottablemodifier/LootTableModifier.java | 7 ++--
.../resource/NewLootModifier.java | 41 +++++++++++++++----
2 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index 91658cc..d7f6285 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -70,17 +70,18 @@ private static Map loadModifiers(ResourceManager re
final Identifier id = entry.getKey();
try {
+ LOGGER.debug("Loading load loot table modifier from '%s'".formatted(id));
result.put(
id,
NewLootModifier.CODEC.decode(registryOps, JsonParser.parseReader(entry.getValue().getReader())).getOrThrow().getFirst()
);
- } catch (IOException e) {
+ } catch (Exception e) {
//noinspection StringConcatenationArgumentToLogCall
- LOGGER.error("Failed to load loot table modifier from '" + id + "'!", e);
+ LOGGER.error("Failed to load loot table modifier from '%s'!".formatted(id), e);
}
}
- LOGGER.info("Loaded {} loot modifiers", result.size());
+ LOGGER.info("Loaded {} loot modifiers!", result.size());
return result;
}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
index 3717e6a..77105bd 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
@@ -4,6 +4,7 @@
import com.ibm.icu.impl.EmojiProps;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
+import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder;
import net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder;
@@ -24,42 +25,64 @@
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
+import top.offsetmonkey538.loottablemodifier.resource.action.AddPoolAction;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Optional;
// Using ArrayList as I want it to be modifiable because I empty it when applying, so I can check for things that weren't applied
public record NewLootModifier(@NotNull ArrayList modifies, @NotNull List actions) {
public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.either(Identifier.CODEC, Identifier.CODEC.listOf()).fieldOf("modifies").forGetter(NewLootModifier::modifiesEither),
- Codec.either(LootModifierAction.CODEC, LootModifierAction.CODEC.listOf()).fieldOf("actions").forGetter(NewLootModifier::actionsEither)
- //LootModifierAction.CODEC.listOf().fieldOf("")
- //Codec.mapEither(LootPool.CODEC.listOf().fieldOf("pools"), LootPool.CODEC.listOf().fieldOf("loot_pools")).forGetter(NewLootModifier::poolsEither)
+ Codec.either(LootModifierAction.CODEC, LootModifierAction.CODEC.listOf()).optionalFieldOf("actions").forGetter(NewLootModifier::actionsOptionalEither),
+ LootPool.CODEC.listOf().optionalFieldOf("pools").forGetter(lootModifier -> Optional.empty()),
+ LootPool.CODEC.listOf().optionalFieldOf("loot_pools").forGetter(lootModifier -> Optional.empty())
).apply(instance, NewLootModifier::new));
- private NewLootModifier(@NotNull Either> modifiesEither, @NotNull Either> actionsEither) {
+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // From codec soo yeah
+ private NewLootModifier(@NotNull Either> modifiesEither, @NotNull Optional>> actions, @NotNull Optional> pools, @NotNull Optional> lootPools) {
this(
modifiesEither.right().orElseGet(() -> List.of(modifiesEither.left().orElseThrow())),
- actionsEither.right().orElseGet(() -> List.of(actionsEither.left().orElseThrow()))
+ getActions(actions, pools, lootPools)
);
}
public NewLootModifier(@NotNull List modifies, @NotNull List actions) {
this(
new ArrayList<>(modifies),
- actions
+ Collections.unmodifiableList(actions)
);
}
+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // From codec soo yeah
+ private static List getActions(@NotNull Optional>> actions, @NotNull Optional> pools, @NotNull Optional> lootPools) {
+ List result = null;
+
+ if (actions.isPresent()) result = actions.get().right().orElseGet(() -> actions.get().left().isEmpty() ? null : List.of(actions.get().left().orElseThrow()));
+
+ if (result != null && pools.isPresent()) throw new IllegalStateException("Both \"actions\" and \"pools\" present in loot modifier!");
+ if (result != null && lootPools.isPresent()) throw new IllegalStateException("Both \"actions\" and \"loot_pools\" present in loot modifier!");
+ if (pools.isPresent() && lootPools.isPresent()) throw new IllegalStateException("Both \"pools\" and \"loot_pools\" present in loot modifier!");
+
+ if (result == null && pools.isPresent()) result = List.of(new AddPoolAction(pools.get()));
+ if (result == null && lootPools.isPresent()) result = List.of(new AddPoolAction(lootPools.get()));
+
+ if (result == null) throw new IllegalStateException("Neither \"actions\" nor \"pools\" present in loot modifier!");
+
+ return result;
+ }
+
private Either> modifiesEither() {
if (modifies.size() == 1) return Either.left(modifies.get(0));
return Either.right(modifies);
}
- private Either> actionsEither() {
- if (actions.size() == 1) return Either.left(actions.get(0));
- return Either.right(actions);
+ private Optional>> actionsOptionalEither() {
+ if (actions.size() == 1) return Optional.of(Either.left(actions.get(0)));
+ return Optional.of(Either.right(actions));
}
/**
From 13f4e9697432aeabe4f5b749d55ccdc082f084bc Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 15:54:05 +0300
Subject: [PATCH 04/53] Remove original LootModifier
---
.../api/datagen/LootModifierProvider.java | 248 ------------------
.../datagen/LootTableModifierDatagen.java | 42 ---
.../resource/LootModifier.java | 34 ---
3 files changed, 324 deletions(-)
delete mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/LootModifierProvider.java
delete mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/LootModifierProvider.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/LootModifierProvider.java
deleted file mode 100644
index 789f549..0000000
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/LootModifierProvider.java
+++ /dev/null
@@ -1,248 +0,0 @@
-package top.offsetmonkey538.loottablemodifier.api.datagen;
-
-import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
-import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider;
-import net.fabricmc.loader.api.FabricLoader;
-import net.fabricmc.loader.api.MappingResolver;
-import net.minecraft.data.DataOutput;
-import net.minecraft.entity.EntityType;
-import net.minecraft.loot.LootPool;
-import net.minecraft.loot.LootTable;
-import net.minecraft.registry.RegistryKey;
-import net.minecraft.registry.RegistryWrapper;
-import net.minecraft.util.Identifier;
-import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.function.BiConsumer;
-import java.util.function.Function;
-import java.util.stream.Stream;
-
-import static top.offsetmonkey538.loottablemodifier.LootTableModifier.MOD_ID;
-
-/**
- * A datagen provider for creating loot modifiers.
- *
- * Override {@link #generate(RegistryWrapper.WrapperLookup) generate()} and use the {@code addModifier(...)} methods to add modifiers.
- *
- * {@code
- * @Override
- * protected void generate(RegistryWrapper.WrapperLookup lookup) {
- * addModifier(
- * Identifier.of("testmod", "drop_tnt"),
- * LootPool.builder()
- * .rolls(ConstantLootNumberProvider.create(1))
- * .with(
- * ItemEntry.builder(Items.TNT)
- * .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 1)))
- * ),
- * EntityType.CREEPER,
- * EntityType.ZOMBIE
- * );
- * }
- * }
- */
-public abstract class LootModifierProvider extends FabricCodecDataProvider {
- private BiConsumer provider;
-
- public LootModifierProvider(FabricDataOutput dataOutput, CompletableFuture registriesFuture) {
- super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, MOD_ID + "/loot_modifier", LootModifier.CODEC);
- }
-
- @Override
- protected void configure(BiConsumer provider, RegistryWrapper.WrapperLookup lookup) {
- this.provider = provider;
- generate(lookup);
- }
-
- @Override
- public String getName() {
- return "Loot Table Modifiers";
- }
-
- /**
- * Override and use {@code addModifier()} methods to add modifiers.
- *
- * @param lookup A lookup for registries.
- */
- protected abstract void generate(RegistryWrapper.WrapperLookup lookup);
-
- /**
- * Adds a new loot table modifier for the given {@link EntityType}s.
- *
- * @param name Name of this modifier
- * @param builder The loot pool to add
- * @param modifies The {@link EntityType} to add the modifier to
- * @param modifiesAdditional Additional {@link EntityType}s to add the modifier to
- */
- protected void addModifier(Identifier name, LootPool.Builder builder, EntityType> modifies, EntityType>... modifiesAdditional) {
- addModifier(
- name,
- List.of(builder),
- modifies,
- modifiesAdditional
- );
- }
-
- /**
- * Adds a new loot table modifier for the given {@link EntityType}s.
- *
- * @param name Name of this modifier
- * @param builders The loot pools to add
- * @param modifies The {@link EntityType} to add the modifier to
- * @param modifiesAdditional Additional {@link EntityType}s to add the modifier to
- */
- protected void addModifier(Identifier name, List builders, EntityType> modifies, EntityType>... modifiesAdditional) {
- addModifier(
- name,
- builders,
- Stream.concat(Stream.of(modifies), Stream.of(modifiesAdditional)).map(EntityLootTableIdGetter.get).toList()
- );
- }
-
- /**
- * Adds a new loot table modifier for the given {@link RegistryKey}s.
- *
- * @param name Name of this modifier
- * @param builder The loot pool to add
- * @param modifies The {@link RegistryKey} to add the modifier to
- * @param modifiesAdditional Additional {@link RegistryKey}s to add the modifier to
- */
- protected void addModifier(Identifier name, LootPool.Builder builder, RegistryKey> modifies, RegistryKey>... modifiesAdditional) {
- addModifier(
- name,
- List.of(builder),
- modifies,
- modifiesAdditional
- );
- }
-
- /**
- * Adds a new loot table modifier for the given {@link RegistryKey}s.
- *
- * @param name Name of this modifier
- * @param builders The loot pools to add
- * @param modifies The {@link RegistryKey} to add the modifier to
- * @param modifiesAdditional Additional {@link RegistryKey}s to add the modifier to
- */
- protected void addModifier(Identifier name, List builders, RegistryKey> modifies, RegistryKey>... modifiesAdditional) {
- addModifier(
- name,
- builders,
- Stream.concat(Stream.of(modifies), Stream.of(modifiesAdditional)).map(RegistryKey::getValue).toList()
- );
- }
-
- /**
- * Adds a new loot table modifier for the given {@link Identifier}s.
- *
- * @param name Name of this modifier
- * @param builder The loot pool to add
- * @param modifies The {@link Identifier} to add the modifier to
- * @param modifiesAdditional Additional {@link Identifier}s to add the modifier to
- */
- protected void addModifier(Identifier name, LootPool.Builder builder, Identifier modifies, Identifier... modifiesAdditional) {
- addModifier(
- name,
- List.of(builder),
- modifies,
- modifiesAdditional
- );
- }
-
- /**
- * Adds a new loot table modifier for the given {@link Identifier}s.
- *
- * @param name Name of this modifier
- * @param builders The loot pools to add
- * @param modifies The {@link Identifier} to add the modifier to
- * @param modifiesAdditional Additional {@link Identifier}s to add the modifier to
- */
- protected void addModifier(Identifier name, List builders, Identifier modifies, Identifier... modifiesAdditional) {
- addModifier(
- name,
- builders,
- Stream.concat(Stream.of(modifies), Stream.of(modifiesAdditional)).toList()
- );
- }
-
- private void addModifier(Identifier name, List builders, List modifies) {
- provider.accept(name, new LootModifier(
- new ArrayList<>(modifies),
- builders.stream().map(LootPool.Builder::build).toList()
- ));
- }
-
-
-
- private static class EntityLootTableIdGetter {
- // Resolver returns the provided name (like 'method_16351') when it fails to map it
- private static final MappingResolver RESOLVER = FabricLoader.getInstance().getMappingResolver();
-
- private static final String V1d21d2 = RESOLVER.mapMethodName("intermediary", "net.minecraft.class_1299", "method_16351", "()Ljava/util/Optional;");
- private static final String V1d20d5 = RESOLVER.mapMethodName("intermediary", "net.minecraft.class_1299", "method_16351", "()Lnet/minecraft/class_5321;");
-
- // mod only supports down to 1.20.5 soo: private static final String V1d14d0 = RESOLVER.mapMethodName("intermediary", "net.minecraft.class_1299", "method_16351", "()Lnet/minecraft/util/Identifier;");
-
- public static final Function, Identifier> get;
-
- // Should be executed when class is first loaded/accessed
- static {
- try {
- //final Class> entityType = EntityType.class;
- final Class> entityType = Class.forName(RESOLVER.mapClassName("intermediary", "net.minecraft.class_1299"));
- final Method method;
-
- // 1.21.2 to future:tm:
- if (isMethod(entityType, V1d21d2)) {
- method = entityType.getDeclaredMethod(V1d21d2);
- method.setAccessible(true);
- get = entity -> {
- try {
- @SuppressWarnings("unchecked")
- final Optional> optional = (Optional>) method.invoke(entity);
- if (optional.isPresent()) return optional.get().getValue();
- throw new IllegalStateException("Entity '" + entity + "' has no loot table! (It is created with 'builder.dropsNothing()')");
- } catch (IllegalAccessException | InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- };
- }
-
- // 1.20.5 to 1.21.1
- else if (isMethod(entityType, V1d20d5)) {
- method = entityType.getDeclaredMethod(V1d20d5);
- method.setAccessible(true);
- get = entity -> {
- try {
- return ((RegistryKey>) method.invoke(entity)).getValue();
- } catch (IllegalAccessException | InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- };
- }
-
- else {
- throw new IllegalStateException("No valid way to get entity loot table id found!");
- }
- } catch (NoSuchMethodException | ClassNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static boolean isMethod(Class> clazz, String method) {
- try {
- clazz.getDeclaredMethod(method);
- return true;
- } catch (NoSuchMethodException e) {
- LOGGER.warn("", e);
- return false;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java b/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java
index 4324dc7..7a09e41 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java
@@ -13,7 +13,6 @@
import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
import net.minecraft.loot.provider.number.UniformLootNumberProvider;
import net.minecraft.registry.RegistryWrapper;
-import top.offsetmonkey538.loottablemodifier.api.datagen.LootModifierProvider;
import top.offsetmonkey538.loottablemodifier.api.datagen.NewLootModifierProvider;
import top.offsetmonkey538.loottablemodifier.resource.action.AddPoolAction;
@@ -27,50 +26,9 @@ public class LootTableModifierDatagen implements DataGeneratorEntrypoint {
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
final FabricDataGenerator.Pack pack = fabricDataGenerator.createBuiltinResourcePack(id("example_pack"));
- //pack.addProvider(ModLootModifierProvider::new);
pack.addProvider(NewModLootModifierProvider::new);
}
- private static class ModLootModifierProvider extends LootModifierProvider {
- public ModLootModifierProvider(FabricDataOutput dataOutput, CompletableFuture registriesFuture) {
- super(dataOutput, registriesFuture);
- }
-
- @Override
- protected void generate(RegistryWrapper.WrapperLookup lookup) {
- addModifier(
- id("drop_tnt"),
-
-
- LootPool.builder()
- .rolls(ConstantLootNumberProvider.create(1))
- .with(
- ItemEntry.builder(Items.TNT)
- .apply(SetCountLootFunction.builder(UniformLootNumberProvider.create(1, 1)))
- ),
-
- EntityType.CREEPER,
- EntityType.ZOMBIE
- );
-
- //todo: temp
- addModifier(
- id("test"),
-
- LootPool.builder()
- .with(
- ItemEntry.builder(Items.NETHERITE_SWORD).apply(
- EnchantWithLevelsLootFunction
- .builder(lookup, UniformLootNumberProvider.create(20, 39))
- //.builder(UniformLootNumberProvider.create(20, 39))
- )
- ),
-
- LootTables.ABANDONED_MINESHAFT_CHEST
- );
- }
- }
-
private static class NewModLootModifierProvider extends NewLootModifierProvider {
public NewModLootModifierProvider(FabricDataOutput dataOutput, CompletableFuture registriesFuture) {
super(dataOutput, registriesFuture);
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
deleted file mode 100644
index 7925d93..0000000
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package top.offsetmonkey538.loottablemodifier.resource;
-
-import com.mojang.datafixers.util.Either;
-import com.mojang.serialization.Codec;
-import com.mojang.serialization.codecs.RecordCodecBuilder;
-import net.minecraft.loot.LootPool;
-import net.minecraft.util.Identifier;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public record LootModifier(ArrayList modifies, List pools) {
- public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
- Codec.either(Identifier.CODEC, Identifier.CODEC.listOf()).fieldOf("modifies").forGetter(LootModifier::modifiesEither),
- Codec.mapEither(LootPool.CODEC.listOf().fieldOf("pools"), LootPool.CODEC.listOf().fieldOf("loot_pools")).forGetter(LootModifier::poolsEither)
- ).apply(instance, LootModifier::new));
-
- private LootModifier(Either> modifiesEither, Either, List> poolsEither) {
- this(
- new ArrayList<>(modifiesEither.right().orElseGet(() -> List.of(modifiesEither.left().orElseThrow()))),
- new ArrayList<>(poolsEither.left().orElseGet(() -> poolsEither.right().orElseThrow()))
- );
- }
-
- private Either> modifiesEither() {
- if (modifies.size() == 1) return Either.left(modifies.get(0));
- return Either.right(modifies);
- }
-
- // Left is "pools", right is "loot_pools". Want datagen to use "pools" so left it is.
- private Either, List> poolsEither() {
- return Either.left(pools);
- }
-}
From 48b4d93f973ae61d681beec1c77b2325b2c1f37d Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 15:55:14 +0300
Subject: [PATCH 05/53] Rename NewLootModifier to LootModifier
---
.../loottablemodifier/LootTableModifier.java | 20 +++++++++----------
.../api/datagen/NewLootModifierProvider.java | 12 +++++------
...NewLootModifier.java => LootModifier.java} | 14 ++++++-------
3 files changed, 23 insertions(+), 23 deletions(-)
rename src/main/java/top/offsetmonkey538/loottablemodifier/resource/{NewLootModifier.java => LootModifier.java} (91%)
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index d7f6285..af41c84 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -25,7 +25,7 @@
import org.slf4j.LoggerFactory;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
-import top.offsetmonkey538.loottablemodifier.resource.NewLootModifier;
+import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@@ -45,13 +45,13 @@ public void onInitialize() {
}
public static void runModification(ResourceManager resourceManager, Registry lootRegistry, RegistryOps registryOps) {
- final Map modifiers = loadModifiers(resourceManager, registryOps);
- final Map failedModifiers = new HashMap<>(0);
+ final Map modifiers = loadModifiers(resourceManager, registryOps);
+ final Map failedModifiers = new HashMap<>(0);
int amountModified = 0;
LOGGER.info("Applying loot table modifiers...");
- for (Map.Entry modifierEntry : modifiers.entrySet()) {
- final NewLootModifier modifier = modifierEntry.getValue();
+ for (Map.Entry modifierEntry : modifiers.entrySet()) {
+ final LootModifier modifier = modifierEntry.getValue();
amountModified += modifier.apply(lootRegistry);
@@ -61,10 +61,10 @@ public static void runModification(ResourceManager resourceManager, Registry loadModifiers(ResourceManager resourceManager, RegistryOps registryOps) {
+ private static Map loadModifiers(ResourceManager resourceManager, RegistryOps registryOps) {
LOGGER.info("Loading loot table modifiers...");
- final Map result = new HashMap<>();
+ final Map result = new HashMap<>();
for (Map.Entry entry : resourceManager.findResources(MOD_ID + "/loot_modifier", path -> path.toString().endsWith(".json")).entrySet()) {
final Identifier id = entry.getKey();
@@ -73,7 +73,7 @@ private static Map loadModifiers(ResourceManager re
LOGGER.debug("Loading load loot table modifier from '%s'".formatted(id));
result.put(
id,
- NewLootModifier.CODEC.decode(registryOps, JsonParser.parseReader(entry.getValue().getReader())).getOrThrow().getFirst()
+ LootModifier.CODEC.decode(registryOps, JsonParser.parseReader(entry.getValue().getReader())).getOrThrow().getFirst()
);
} catch (Exception e) {
//noinspection StringConcatenationArgumentToLogCall
@@ -86,13 +86,13 @@ private static Map loadModifiers(ResourceManager re
return result;
}
- private static void modifiersApplied(int amountModified, Map failedModifiers) {
+ private static void modifiersApplied(int amountModified, Map failedModifiers) {
LOGGER.info("Modified {} loot tables!", amountModified);
if (failedModifiers.isEmpty()) return;
LOGGER.warn("There were unused modifiers:");
- for (Map.Entry entry : failedModifiers.entrySet()) {
+ for (Map.Entry entry : failedModifiers.entrySet()) {
LOGGER.warn("\tModifier '{}' failed to modify loot table for entities: ", entry.getKey());
for (Identifier id : entry.getValue().modifies()) {
LOGGER.warn("\t\t- {}", id);
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
index 430896e..a5dde43 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
@@ -12,7 +12,7 @@
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.Identifier;
-import top.offsetmonkey538.loottablemodifier.resource.NewLootModifier;
+import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
import java.lang.reflect.InvocationTargetException;
@@ -48,15 +48,15 @@
* }
* }
*/
-public abstract class NewLootModifierProvider extends FabricCodecDataProvider {
- private BiConsumer provider;
+public abstract class NewLootModifierProvider extends FabricCodecDataProvider {
+ private BiConsumer provider;
public NewLootModifierProvider(FabricDataOutput dataOutput, CompletableFuture registriesFuture) {
- super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, MOD_ID + "/loot_modifier", NewLootModifier.CODEC);
+ super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, MOD_ID + "/loot_modifier", LootModifier.CODEC);
}
@Override
- protected void configure(BiConsumer provider, RegistryWrapper.WrapperLookup lookup) {
+ protected void configure(BiConsumer provider, RegistryWrapper.WrapperLookup lookup) {
this.provider = provider;
generate(lookup);
}
@@ -173,7 +173,7 @@ protected void addModifier(Identifier name, List bui
}
private void addModifier(Identifier name, List builders, List modifies) {
- provider.accept(name, new NewLootModifier(
+ provider.accept(name, new LootModifier(
new ArrayList<>(modifies),
builders.stream()
.map(LootModifierAction.Builder::build)
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
similarity index 91%
rename from src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
rename to src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
index 77105bd..5511760 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/NewLootModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
@@ -35,22 +35,22 @@
import java.util.Optional;
// Using ArrayList as I want it to be modifiable because I empty it when applying, so I can check for things that weren't applied
-public record NewLootModifier(@NotNull ArrayList modifies, @NotNull List actions) {
- public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
- Codec.either(Identifier.CODEC, Identifier.CODEC.listOf()).fieldOf("modifies").forGetter(NewLootModifier::modifiesEither),
- Codec.either(LootModifierAction.CODEC, LootModifierAction.CODEC.listOf()).optionalFieldOf("actions").forGetter(NewLootModifier::actionsOptionalEither),
+public record LootModifier(@NotNull ArrayList modifies, @NotNull List actions) {
+ public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
+ Codec.either(Identifier.CODEC, Identifier.CODEC.listOf()).fieldOf("modifies").forGetter(LootModifier::modifiesEither),
+ Codec.either(LootModifierAction.CODEC, LootModifierAction.CODEC.listOf()).optionalFieldOf("actions").forGetter(LootModifier::actionsOptionalEither),
LootPool.CODEC.listOf().optionalFieldOf("pools").forGetter(lootModifier -> Optional.empty()),
LootPool.CODEC.listOf().optionalFieldOf("loot_pools").forGetter(lootModifier -> Optional.empty())
- ).apply(instance, NewLootModifier::new));
+ ).apply(instance, LootModifier::new));
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") // From codec soo yeah
- private NewLootModifier(@NotNull Either> modifiesEither, @NotNull Optional>> actions, @NotNull Optional> pools, @NotNull Optional> lootPools) {
+ private LootModifier(@NotNull Either> modifiesEither, @NotNull Optional>> actions, @NotNull Optional> pools, @NotNull Optional> lootPools) {
this(
modifiesEither.right().orElseGet(() -> List.of(modifiesEither.left().orElseThrow())),
getActions(actions, pools, lootPools)
);
}
- public NewLootModifier(@NotNull List modifies, @NotNull List actions) {
+ public LootModifier(@NotNull List modifies, @NotNull List actions) {
this(
new ArrayList<>(modifies),
Collections.unmodifiableList(actions)
From bb7fdc08caf344066e81ada6984f198adf6a47a0 Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 15:55:54 +0300
Subject: [PATCH 06/53] Cleanup
---
.../loottablemodifier/LootTableModifier.java | 12 ------------
.../api/LootModifierActionTypes.java | 5 -----
.../api/datagen/NewLootModifierProvider.java | 2 --
.../loottablemodifier/resource/LootModifier.java | 13 -------------
.../resource/action/AddPoolAction.java | 2 --
.../resource/action/LootModifierAction.java | 1 -
6 files changed, 35 deletions(-)
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index af41c84..eff52e4 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -1,36 +1,24 @@
package top.offsetmonkey538.loottablemodifier;
-import com.google.common.collect.ImmutableList;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.ResourcePackActivationType;
import net.fabricmc.loader.api.FabricLoader;
-import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
-import net.minecraft.loot.condition.LootCondition;
import net.minecraft.registry.Registry;
-import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryOps;
-import net.minecraft.registry.RegistryWrapper;
-import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
-import net.minecraft.util.Pair;
-import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
-import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
public class LootTableModifier implements ModInitializer {
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
index 4802aef..cca0964 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierActionTypes.java
@@ -1,8 +1,6 @@
package top.offsetmonkey538.loottablemodifier.api;
-import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
-import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
@@ -10,9 +8,6 @@
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierActionType;
-import java.util.HashMap;
-import java.util.Map;
-
import static top.offsetmonkey538.loottablemodifier.LootTableModifier.id;
public final class LootModifierActionTypes {
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
index a5dde43..56ef6a1 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
@@ -5,9 +5,7 @@
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.MappingResolver;
import net.minecraft.data.DataOutput;
-import net.minecraft.data.loottable.LootTableGenerator;
import net.minecraft.entity.EntityType;
-import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryWrapper;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
index 5511760..2ffdcd4 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
@@ -1,30 +1,17 @@
package top.offsetmonkey538.loottablemodifier.resource;
-import com.google.common.collect.ImmutableList;
-import com.ibm.icu.impl.EmojiProps;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
-import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
-import net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder;
-import net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
-import net.minecraft.loot.condition.LootCondition;
-import net.minecraft.loot.condition.LootConditionConsumingBuilder;
-import net.minecraft.loot.entry.LootPoolEntry;
-import net.minecraft.loot.function.LootFunction;
-import net.minecraft.loot.function.LootFunctionConsumingBuilder;
-import net.minecraft.loot.provider.number.ConstantLootNumberProvider;
-import net.minecraft.loot.provider.number.LootNumberProvider;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
-import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
import top.offsetmonkey538.loottablemodifier.resource.action.AddPoolAction;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
index 574cd94..004b24e 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/AddPoolAction.java
@@ -3,10 +3,8 @@
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
-import net.minecraft.block.Block;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
-import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
import top.offsetmonkey538.loottablemodifier.mixin.LootTableAccessor;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
index c5064d4..8d56f6e 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/LootModifierAction.java
@@ -3,7 +3,6 @@
import com.mojang.serialization.Codec;
import net.minecraft.loot.LootTable;
import org.jetbrains.annotations.NotNull;
-import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
public interface LootModifierAction {
Codec CODEC = LootModifierActionType.REGISTRY.getCodec().dispatch(LootModifierAction::getType, LootModifierActionType::codec);
From 5ed8e2ced8e19a9487bc9e0433035a8fe06703e8 Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 18:15:03 +0300
Subject: [PATCH 07/53] Allow regex for matching loot table, allow matching
loot table by type
---
.../loottablemodifier/LootTableModifier.java | 24 +++++----
.../api/datagen/NewLootModifierProvider.java | 4 +-
.../resource/LootModifier.java | 29 +++++-----
.../resource/LootTablePredicate.java | 53 +++++++++++++++++++
.../loot-table-modifier.accesswidener | 3 +-
.../resources/loot-table-modifier.mixins.json | 18 +++----
6 files changed, 94 insertions(+), 37 deletions(-)
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index eff52e4..f53f096 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -1,5 +1,6 @@
package top.offsetmonkey538.loottablemodifier;
+import com.google.common.base.Stopwatch;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import net.fabricmc.api.ModInitializer;
@@ -17,6 +18,7 @@
import org.slf4j.LoggerFactory;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
+import top.offsetmonkey538.loottablemodifier.resource.LootTablePredicate;
import java.util.HashMap;
import java.util.Map;
@@ -37,20 +39,24 @@ public static void runModification(ResourceManager resourceManager, Registry failedModifiers = new HashMap<>(0);
int amountModified = 0;
- LOGGER.info("Applying loot table modifiers...");
+ LOGGER.info("Modifying loot tables...");
+ final Stopwatch stopwatch = Stopwatch.createStarted();
for (Map.Entry modifierEntry : modifiers.entrySet()) {
final LootModifier modifier = modifierEntry.getValue();
amountModified += modifier.apply(lootRegistry);
- if (!modifier.modifies().isEmpty()) failedModifiers.put(modifierEntry.getKey(), modifier);
+ // TODO: try to figure smt out abt this: if (!modifier.modifies().isEmpty()) failedModifiers.put(modifierEntry.getKey(), modifier);
}
- modifiersApplied(amountModified, failedModifiers);
+
+ LOGGER.info("Modified {} loot tables in {}!", amountModified, stopwatch);
+ modifiersApplied(failedModifiers);
}
private static Map loadModifiers(ResourceManager resourceManager, RegistryOps registryOps) {
LOGGER.info("Loading loot table modifiers...");
+ final Stopwatch stopwatch = Stopwatch.createStarted();
final Map result = new HashMap<>();
@@ -69,21 +75,19 @@ private static Map loadModifiers(ResourceManager resou
}
}
- LOGGER.info("Loaded {} loot modifiers!", result.size());
+ LOGGER.info("Loaded {} loot modifiers in {}!", result.size(), stopwatch);
return result;
}
- private static void modifiersApplied(int amountModified, Map failedModifiers) {
- LOGGER.info("Modified {} loot tables!", amountModified);
-
+ private static void modifiersApplied(Map failedModifiers) {
if (failedModifiers.isEmpty()) return;
LOGGER.warn("There were unused modifiers:");
for (Map.Entry entry : failedModifiers.entrySet()) {
- LOGGER.warn("\tModifier '{}' failed to modify loot table for entities: ", entry.getKey());
- for (Identifier id : entry.getValue().modifies()) {
- LOGGER.warn("\t\t- {}", id);
+ LOGGER.warn("\tModifier '{}' failed to modify loot table for predicates: ", entry.getKey());
+ for (LootTablePredicate predicate : entry.getValue().modifies()) {
+ LOGGER.warn("\t\t- {}", predicate);
}
}
}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
index 56ef6a1..20b4a96 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
@@ -11,6 +11,7 @@
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.Identifier;
import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
+import top.offsetmonkey538.loottablemodifier.resource.LootTablePredicate;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
import java.lang.reflect.InvocationTargetException;
@@ -19,6 +20,7 @@
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Function;
+import java.util.regex.Pattern;
import java.util.stream.Stream;
import static top.offsetmonkey538.loottablemodifier.LootTableModifier.MOD_ID;
@@ -172,7 +174,7 @@ protected void addModifier(Identifier name, List bui
private void addModifier(Identifier name, List builders, List modifies) {
provider.accept(name, new LootModifier(
- new ArrayList<>(modifies),
+ modifies.stream().map(identifier -> new LootTablePredicate(Pattern.compile(identifier.toString()))).toList(),
builders.stream()
.map(LootModifierAction.Builder::build)
.toList()
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
index 2ffdcd4..40da5cd 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
@@ -10,34 +10,31 @@
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.entry.RegistryEntry;
-import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.UnmodifiableView;
import top.offsetmonkey538.loottablemodifier.resource.action.AddPoolAction;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
// Using ArrayList as I want it to be modifiable because I empty it when applying, so I can check for things that weren't applied
-public record LootModifier(@NotNull ArrayList modifies, @NotNull List actions) {
+public record LootModifier(@NotNull ArrayList modifies, @NotNull @UnmodifiableView List actions) {
public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
- Codec.either(Identifier.CODEC, Identifier.CODEC.listOf()).fieldOf("modifies").forGetter(LootModifier::modifiesEither),
+ Codec.either(LootTablePredicate.CODEC, LootTablePredicate.CODEC.listOf()).fieldOf("modifies").forGetter(LootModifier::modifiesEither),
Codec.either(LootModifierAction.CODEC, LootModifierAction.CODEC.listOf()).optionalFieldOf("actions").forGetter(LootModifier::actionsOptionalEither),
LootPool.CODEC.listOf().optionalFieldOf("pools").forGetter(lootModifier -> Optional.empty()),
LootPool.CODEC.listOf().optionalFieldOf("loot_pools").forGetter(lootModifier -> Optional.empty())
).apply(instance, LootModifier::new));
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") // From codec soo yeah
- private LootModifier(@NotNull Either> modifiesEither, @NotNull Optional>> actions, @NotNull Optional> pools, @NotNull Optional> lootPools) {
+ private LootModifier(@NotNull Either> modifiesEither, @NotNull Optional>> actions, @NotNull Optional> pools, @NotNull Optional> lootPools) {
this(
modifiesEither.right().orElseGet(() -> List.of(modifiesEither.left().orElseThrow())),
getActions(actions, pools, lootPools)
);
}
- public LootModifier(@NotNull List modifies, @NotNull List actions) {
+ public LootModifier(@NotNull List modifies, @NotNull List actions) {
this(
new ArrayList<>(modifies),
Collections.unmodifiableList(actions)
@@ -62,7 +59,7 @@ private static List getActions(@NotNull Optional> modifiesEither() {
+ private Either> modifiesEither() {
if (modifies.size() == 1) return Either.left(modifies.get(0));
return Either.right(modifies);
}
@@ -77,19 +74,19 @@ private Optional>> actionsOp
* @return amount of loot tables modified
*/
public int apply(final @NotNull Registry tableRegistry) {
- final List> tableKeys = getRegistryAsWrapper(tableRegistry).streamEntries().map(RegistryEntry.Reference::registryKey).filter(key -> modifies.contains(key.getValue())).toList();
- if (tableKeys.isEmpty()) return 0;
- // At this point only ones in 'modifies' remain
-
int modified = 0;
- for (RegistryKey key : tableKeys) {
+ for (Iterator> it = getRegistryAsWrapper(tableRegistry).streamEntries().iterator(); it.hasNext(); ) {
+ final RegistryEntry.Reference entry = it.next();
+
+ final RegistryKey key = entry.registryKey();
final LootTable table = tableRegistry.get(key);
if (table == null) throw new IllegalStateException("Loot table with id '%s' is null!".formatted(key));
+ if (modifies.stream().noneMatch(predicate -> predicate.matches(table, key.getValue()))) continue;
+
modified += apply(table) ? 1 : 0;
- modifies.remove(key.getValue());
}
return modified;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java
new file mode 100644
index 0000000..d2acb49
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java
@@ -0,0 +1,53 @@
+package top.offsetmonkey538.loottablemodifier.resource;
+
+import com.mojang.datafixers.util.Either;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.loot.LootTable;
+import net.minecraft.loot.context.LootContextTypes;
+import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+public record LootTablePredicate(@NotNull Pattern identifier, @Nullable Pattern type) {
+ private static final Codec PATTERN_CODEC = Codec.STRING.xmap(Pattern::compile, Pattern::pattern);
+ private static final Codec INLINE_CODEC = PATTERN_CODEC.xmap(LootTablePredicate::new, LootTablePredicate::identifier);
+ private static final Codec FULL_CODEC = RecordCodecBuilder.create(instance -> instance.group(
+ PATTERN_CODEC.fieldOf("identifier").forGetter(LootTablePredicate::identifier),
+ PATTERN_CODEC.optionalFieldOf("type").forGetter(LootTablePredicate::optionalType)
+ ).apply(instance, LootTablePredicate::new));
+ public static final Codec CODEC = Codec.either(LootTablePredicate.INLINE_CODEC, LootTablePredicate.FULL_CODEC).xmap(lootTablePredicateLootTablePredicateEither -> lootTablePredicateLootTablePredicateEither.left().orElseGet(() -> lootTablePredicateLootTablePredicateEither.right().orElseThrow()),
+ lootTablePredicate -> {
+ if (lootTablePredicate.type == null) {
+ return Either.left(lootTablePredicate);
+ }
+ return Either.right(lootTablePredicate);
+ });
+
+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // Codec gib it to me
+ private LootTablePredicate(@NotNull Pattern pattern, @NotNull Optional optionalType) {
+ this(pattern, optionalType.orElse(null));
+ }
+
+ public LootTablePredicate(@NotNull Pattern pattern) {
+ this(pattern, (Pattern) null);
+ }
+
+ private Optional optionalType() {
+ return Optional.ofNullable(type);
+ }
+
+
+ public boolean matches(final @NotNull LootTable table, final @NotNull Identifier tableId) {
+ boolean result = identifier.matcher(tableId.toString()).matches();
+
+ if (type != null) {
+ result = result && type.matcher(LootContextTypes.MAP.inverse().get(table.getType()).toString()).matches();
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/resources/loot-table-modifier.accesswidener b/src/main/resources/loot-table-modifier.accesswidener
index 46a644a..1cbe777 100644
--- a/src/main/resources/loot-table-modifier.accesswidener
+++ b/src/main/resources/loot-table-modifier.accesswidener
@@ -1,3 +1,4 @@
accessWidener v1 named
-accessible field net/minecraft/loot/LootTable pools Ljava/util/List;
\ No newline at end of file
+accessible field net/minecraft/loot/LootTable pools Ljava/util/List;
+accessible field net/minecraft/loot/context/LootContextTypes MAP Lcom/google/common/collect/BiMap;
\ No newline at end of file
diff --git a/src/main/resources/loot-table-modifier.mixins.json b/src/main/resources/loot-table-modifier.mixins.json
index e306650..52a1daa 100644
--- a/src/main/resources/loot-table-modifier.mixins.json
+++ b/src/main/resources/loot-table-modifier.mixins.json
@@ -1,12 +1,12 @@
{
- "required": true,
- "package": "top.offsetmonkey538.loottablemodifier.mixin",
- "compatibilityLevel": "JAVA_17",
- "mixins": [
- "LootTableAccessor",
- "ReloadableRegistriesMixin"
- ],
- "injectors": {
- "defaultRequire": 1
+ "required": true,
+ "package": "top.offsetmonkey538.loottablemodifier.mixin",
+ "compatibilityLevel": "JAVA_17",
+ "mixins": [
+ "LootTableAccessor",
+ "ReloadableRegistriesMixin"
+ ],
+ "injectors": {
+ "defaultRequire": 1
}
}
From 2c9ab5fa21354163670da739947696edfbf9a680 Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Tue, 6 May 2025 19:22:19 +0300
Subject: [PATCH 08/53] Allow matching loot table by function type
Functions (and conditions in the future) only support matching by type, couldn't figure out a good way to match specific ones
---
.../loottablemodifier/LootTableModifier.java | 2 +-
.../api/datagen/NewLootModifierProvider.java | 2 +-
.../resource/LootModifier.java | 1 +
.../resource/LootTablePredicate.java | 53 --------------
.../predicate/LootFunctionPredicate.java | 20 ++++++
.../predicate/LootTablePredicate.java | 72 +++++++++++++++++++
.../resource/predicate/Util.java | 13 ++++
.../loot-table-modifier.accesswidener | 4 +-
8 files changed, 111 insertions(+), 56 deletions(-)
delete mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootFunctionPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootTablePredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/Util.java
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index f53f096..60d1648 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -18,7 +18,7 @@
import org.slf4j.LoggerFactory;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
-import top.offsetmonkey538.loottablemodifier.resource.LootTablePredicate;
+import top.offsetmonkey538.loottablemodifier.resource.predicate.LootTablePredicate;
import java.util.HashMap;
import java.util.Map;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
index 20b4a96..4ebd742 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/api/datagen/NewLootModifierProvider.java
@@ -11,7 +11,7 @@
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.util.Identifier;
import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
-import top.offsetmonkey538.loottablemodifier.resource.LootTablePredicate;
+import top.offsetmonkey538.loottablemodifier.resource.predicate.LootTablePredicate;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
import java.lang.reflect.InvocationTargetException;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
index 40da5cd..62b6d2e 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifier.java
@@ -14,6 +14,7 @@
import org.jetbrains.annotations.UnmodifiableView;
import top.offsetmonkey538.loottablemodifier.resource.action.AddPoolAction;
import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
+import top.offsetmonkey538.loottablemodifier.resource.predicate.LootTablePredicate;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java
deleted file mode 100644
index d2acb49..0000000
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootTablePredicate.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package top.offsetmonkey538.loottablemodifier.resource;
-
-import com.mojang.datafixers.util.Either;
-import com.mojang.serialization.Codec;
-import com.mojang.serialization.codecs.RecordCodecBuilder;
-import net.minecraft.loot.LootTable;
-import net.minecraft.loot.context.LootContextTypes;
-import net.minecraft.util.Identifier;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Optional;
-import java.util.regex.Pattern;
-
-public record LootTablePredicate(@NotNull Pattern identifier, @Nullable Pattern type) {
- private static final Codec PATTERN_CODEC = Codec.STRING.xmap(Pattern::compile, Pattern::pattern);
- private static final Codec INLINE_CODEC = PATTERN_CODEC.xmap(LootTablePredicate::new, LootTablePredicate::identifier);
- private static final Codec FULL_CODEC = RecordCodecBuilder.create(instance -> instance.group(
- PATTERN_CODEC.fieldOf("identifier").forGetter(LootTablePredicate::identifier),
- PATTERN_CODEC.optionalFieldOf("type").forGetter(LootTablePredicate::optionalType)
- ).apply(instance, LootTablePredicate::new));
- public static final Codec CODEC = Codec.either(LootTablePredicate.INLINE_CODEC, LootTablePredicate.FULL_CODEC).xmap(lootTablePredicateLootTablePredicateEither -> lootTablePredicateLootTablePredicateEither.left().orElseGet(() -> lootTablePredicateLootTablePredicateEither.right().orElseThrow()),
- lootTablePredicate -> {
- if (lootTablePredicate.type == null) {
- return Either.left(lootTablePredicate);
- }
- return Either.right(lootTablePredicate);
- });
-
- @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // Codec gib it to me
- private LootTablePredicate(@NotNull Pattern pattern, @NotNull Optional optionalType) {
- this(pattern, optionalType.orElse(null));
- }
-
- public LootTablePredicate(@NotNull Pattern pattern) {
- this(pattern, (Pattern) null);
- }
-
- private Optional optionalType() {
- return Optional.ofNullable(type);
- }
-
-
- public boolean matches(final @NotNull LootTable table, final @NotNull Identifier tableId) {
- boolean result = identifier.matcher(tableId.toString()).matches();
-
- if (type != null) {
- result = result && type.matcher(LootContextTypes.MAP.inverse().get(table.getType()).toString()).matches();
- }
-
- return result;
- }
-}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootFunctionPredicate.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootFunctionPredicate.java
new file mode 100644
index 0000000..31f1786
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootFunctionPredicate.java
@@ -0,0 +1,20 @@
+package top.offsetmonkey538.loottablemodifier.resource.predicate;
+
+import com.mojang.serialization.Codec;
+import net.minecraft.loot.function.LootFunction;
+import net.minecraft.registry.Registries;
+import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+public record LootFunctionPredicate(@NotNull Pattern functionPattern) {
+ public static final Codec CODEC = Util.PATTERN_CODEC.xmap(LootFunctionPredicate::new, LootFunctionPredicate::functionPattern);
+
+ public boolean matches(final @NotNull LootFunction function) {
+ final Identifier functionId = Registries.LOOT_FUNCTION_TYPE.getId(function.getType());
+ if (functionId == null) return false;
+
+ return functionPattern.matcher(functionId.toString()).matches();
+ }
+}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootTablePredicate.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootTablePredicate.java
new file mode 100644
index 0000000..8b98b99
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootTablePredicate.java
@@ -0,0 +1,72 @@
+package top.offsetmonkey538.loottablemodifier.resource.predicate;
+
+import com.mojang.datafixers.util.Either;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+import net.minecraft.loot.LootTable;
+import net.minecraft.loot.context.LootContextTypes;
+import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+public record LootTablePredicate(@Nullable Pattern identifier, @Nullable Pattern type, @Nullable List functions) {
+ private static final Codec INLINE_CODEC = Util.PATTERN_CODEC.xmap(LootTablePredicate::new, LootTablePredicate::identifier);
+ private static final Codec FULL_CODEC = RecordCodecBuilder.create(instance -> instance.group(
+ Util.PATTERN_CODEC.optionalFieldOf("id").forGetter(LootTablePredicate::optionalIdentifier),
+ Util.PATTERN_CODEC.optionalFieldOf("type").forGetter(LootTablePredicate::optionalType),
+ Codec.either(LootFunctionPredicate.CODEC, LootFunctionPredicate.CODEC.listOf()).optionalFieldOf("functions").forGetter(LootTablePredicate::optionalFunctions)
+ ).apply(instance, LootTablePredicate::new));
+ public static final Codec CODEC = Codec.either(LootTablePredicate.INLINE_CODEC, LootTablePredicate.FULL_CODEC).xmap(lootTablePredicateLootTablePredicateEither -> lootTablePredicateLootTablePredicateEither.left().orElseGet(() -> lootTablePredicateLootTablePredicateEither.right().orElseThrow()),
+ lootTablePredicate -> {
+ if (lootTablePredicate.identifier != null && lootTablePredicate.type == null && (lootTablePredicate.functions == null || lootTablePredicate.functions.isEmpty())) {
+ return Either.left(lootTablePredicate);
+ }
+ return Either.right(lootTablePredicate);
+ });
+
+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") // Codec gib it to me
+ private LootTablePredicate(@NotNull Optional optionalIdentifier, @NotNull Optional optionalType, @NotNull Optional>> optionalFunctions) {
+ this(optionalIdentifier.orElse(null), optionalType.orElse(null), optionalFunctions.map(functionsEither -> functionsEither.map(List::of, patterns -> patterns)).orElse(null));
+ }
+
+ public LootTablePredicate(@NotNull Pattern pattern) {
+ this(pattern, null, null);
+ }
+
+ private Optional optionalIdentifier() {
+ return Optional.ofNullable(identifier);
+ }
+ private Optional optionalType() {
+ return Optional.ofNullable(type);
+ }
+ private Optional>> optionalFunctions() {
+ if (functions == null) return Optional.empty();
+ if (functions.size() == 1) return Optional.of(Either.left(functions.get(0)));
+ return Optional.of(Either.right(functions));
+ }
+
+
+ public boolean matches(final @NotNull LootTable table, final @NotNull Identifier tableId) {
+ boolean result = true;
+
+ if (identifier != null) {
+ result = identifier.matcher(tableId.toString()).matches();
+ }
+
+ if (type != null) {
+ result = result && type.matcher(LootContextTypes.MAP.inverse().get(table.getType()).toString()).matches();
+ }
+
+ if (functions != null) {
+ for (LootFunctionPredicate functionPredicate : functions) {
+ result = result && table.functions.stream().anyMatch(functionPredicate::matches);
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/Util.java b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/Util.java
new file mode 100644
index 0000000..41e6cb0
--- /dev/null
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/Util.java
@@ -0,0 +1,13 @@
+package top.offsetmonkey538.loottablemodifier.resource.predicate;
+
+import com.mojang.serialization.Codec;
+
+import java.util.regex.Pattern;
+
+public final class Util {
+ private Util() {
+
+ }
+
+ public static final Codec PATTERN_CODEC = Codec.STRING.xmap(Pattern::compile, Pattern::pattern);
+}
diff --git a/src/main/resources/loot-table-modifier.accesswidener b/src/main/resources/loot-table-modifier.accesswidener
index 1cbe777..1eee9e0 100644
--- a/src/main/resources/loot-table-modifier.accesswidener
+++ b/src/main/resources/loot-table-modifier.accesswidener
@@ -1,4 +1,6 @@
accessWidener v1 named
accessible field net/minecraft/loot/LootTable pools Ljava/util/List;
-accessible field net/minecraft/loot/context/LootContextTypes MAP Lcom/google/common/collect/BiMap;
\ No newline at end of file
+accessible field net/minecraft/loot/LootTable functions Ljava/util/List;
+
+accessible field net/minecraft/loot/context/LootContextTypes MAP Lcom/google/common/collect/BiMap;
From 2e5f8e80db9d132dfc74e571a257dd984367c56d Mon Sep 17 00:00:00 2001
From: OffsetMonkey538 <71213040+OffsetMonkey538@users.noreply.github.com>
Date: Thu, 12 Jun 2025 14:41:31 +0300
Subject: [PATCH 09/53] Lots of broken stuff
---
README.md | 4 +
.../loottablemodifier/LootTableModifier.java | 119 +++++++++++++--
.../api/LootModifierPredicateTypes.java | 40 ++++++
.../api/datagen/NewLootModifierProvider.java | 8 +-
.../resource/LootModifier.java | 58 ++++----
.../resource/LootModifierContext.java | 21 +++
.../resource/action/LootModifierAction.java | 6 +-
.../resource/action/RemovePoolAction.java | 43 ++++++
.../predicate/LootFunctionPredicate.java | 20 ---
.../predicate/LootModifierPredicate.java | 79 ++++++++++
.../predicate/LootModifierPredicateType.java | 15 ++
.../condition/LootConditionPredicate.java | 21 +++
.../predicate/entry/LootEntryPredicate.java | 55 +++++++
.../entry/leaf/EmptyEntryPredicate.java | 40 ++++++
.../entry/leaf/LeafEntryPredicate.java | 44 ++++++
.../function/LootFunctionPredicate.java | 22 +++
.../predicate/op/AllOfLootPredicate.java | 46 ++++++
.../predicate/op/AnyOfLootPredicate.java | 47 ++++++
.../predicate/op/InvertedLootPredicate.java | 29 ++++
.../predicate/op/TermsLootPredicate.java | 72 ++++++++++
.../predicate/pool/LootPoolPredicate.java | 136 ++++++++++++++++++
.../{ => table}/LootTablePredicate.java | 14 +-
.../loot-table-modifier.accesswidener | 2 +
23 files changed, 871 insertions(+), 70 deletions(-)
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/api/LootModifierPredicateTypes.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/LootModifierContext.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/action/RemovePoolAction.java
delete mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootFunctionPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootModifierPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/LootModifierPredicateType.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/condition/LootConditionPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/entry/LootEntryPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/entry/leaf/EmptyEntryPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/entry/leaf/LeafEntryPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/function/LootFunctionPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/op/AllOfLootPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/op/AnyOfLootPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/op/InvertedLootPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/op/TermsLootPredicate.java
create mode 100644 src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/pool/LootPoolPredicate.java
rename src/main/java/top/offsetmonkey538/loottablemodifier/resource/predicate/{ => table}/LootTablePredicate.java (85%)
diff --git a/README.md b/README.md
index d55497d..b3af05c 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,10 @@
Allows datapacks (and thus mods as well) to add to loot tables, instead of just overwriting them.
+This mod shouldn't impact performance while playing the game, but only when datapacks are reloading (joining a world, starting a server, `/reload` command, whatever else).
+Performance impact during pack reloading varies depending on the datapacks.
+The mod writes how long applying modifiers took in the console.
+
Also provides a datagen provider for creating loot table modifiers in mods.
A modifier json file includes two components:
diff --git a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
index 60d1648..a820300 100644
--- a/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
+++ b/src/main/java/top/offsetmonkey538/loottablemodifier/LootTableModifier.java
@@ -7,20 +7,32 @@
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.ResourcePackActivationType;
import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
+import net.minecraft.loot.entry.LootPoolEntry;
import net.minecraft.registry.Registry;
+import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryOps;
+import net.minecraft.registry.RegistryWrapper;
+import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.offsetmonkey538.loottablemodifier.api.LootModifierActionTypes;
import top.offsetmonkey538.loottablemodifier.resource.LootModifier;
-import top.offsetmonkey538.loottablemodifier.resource.predicate.LootTablePredicate;
+import top.offsetmonkey538.loottablemodifier.resource.LootModifierContext;
+import top.offsetmonkey538.loottablemodifier.resource.action.LootModifierAction;
+import top.offsetmonkey538.loottablemodifier.resource.predicate.LootModifierPredicate;
+import top.offsetmonkey538.loottablemodifier.resource.predicate.table.LootTablePredicate;
+import top.offsetmonkey538.loottablemodifier.resource.predicate.entry.LootEntryPredicateTypes;
+import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
public class LootTableModifier implements ModInitializer {
@@ -30,8 +42,10 @@ public class LootTableModifier implements ModInitializer {
@Override
public void onInitialize() {
LootModifierActionTypes.register();
+ LootEntryPredicateTypes.register();
- if(FabricLoader.getInstance().isDevelopmentEnvironment()) ResourceManagerHelper.registerBuiltinResourcePack(id("example_pack"), FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow(), Text.of("Example Pack"), ResourcePackActivationType.NORMAL);
+ if (FabricLoader.getInstance().isDevelopmentEnvironment())
+ ResourceManagerHelper.registerBuiltinResourcePack(id("example_pack"), FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow(), Text.of("Example Pack"), ResourcePackActivationType.NORMAL);
}
public static void runModification(ResourceManager resourceManager, Registry lootRegistry, RegistryOps registryOps) {
@@ -41,16 +55,71 @@ public static void runModification(ResourceManager resourceManager, Registry modifierEntry : modifiers.entrySet()) {
- final LootModifier modifier = modifierEntry.getValue();
+ // TODO: Would looping through all tables here be faster than doing that for each modifier? To test I guess
+
+
+ // TODO: so about that never-nesting............
+ // fixme: don't think modifying for example tables without any pools or entries would work with this.....
+ // TODO: increment "amountModified" somewhere...
+ // todo. just fucking rewrite this when your brain actually works and can think
+ for (Iterator> it = getRegistryAsWrapper(lootRegistry).streamEntries().iterator(); it.hasNext(); ) {
+ final RegistryEntry.Reference registryEntry = it.next();
+ final RegistryKey key = registryEntry.registryKey();
+
+ final LootTable table = lootRegistry.get(key);
+ if (table == null) throw new IllegalStateException("Loot table with id '%s' is null!".formatted(key));
+
+
+ for (LootPool pool : table.pools) {
+ for (LootPoolEntry entry : pool.entries) {
+ final LootModifierContext context = new LootModifierContext(table, key.getValue(), pool, entry);
+ for (Map.Entry modifierEntry : modifiers.entrySet()) {
+ final LootModifier modifier = modifierEntry.getValue();
+ if (!modifier.testModifies(context)) continue;
+ modifier.apply(context);
+ }
+ }
+ }
+
+ //for (Map.Entry modifierEntry : modifiers.entrySet()) {
+ // final LootModifier modifier = modifierEntry.getValue();
+
+ // for (LootModifierPredicate modifiesPredicate : modifier.modifies()) {
+ // if (modifiesPredicate.requiredContext() == LootModifierContext.REQUIRES_TABLE && !modifiesPredicate.test(tableContext)) continue;
+
+ // for (LootPool pool : table.pools) {
+ // final LootModifierContext poolContext = new LootModifierContext(table, key.getValue(), pool);
+
+ // if (modifiesPredicate.requiredContext() == LootModifierContext.REQUIRES_POOL && !modifiesPredicate.test(poolContext)) continue;
- amountModified += modifier.apply(lootRegistry);
+ // for (LootPoolEntry entry : pool.entries) {
+ // final LootModifierContext entryContext = new LootModifierContext(table, key.getValue(), pool, entry);
- // TODO: try to figure smt out abt this: if (!modifier.modifies().isEmpty()) failedModifiers.put(modifierEntry.getKey(), modifier);
+ // if (modifiesPredicate.requiredContext() == LootModifierContext.REQUIRES_POOL && !modifiesPredicate.test(entryContext)) continue;
+
+ // for (LootModifierAction action : modifier.actions()) {
+ // action.apply(entryContext);
+ // }
+ // }
+ // }
+ // }
+ //}
+
+
+ // todo: modified += apply(table) ? 1 : 0;
}
- LOGGER.info("Modified {} loot tables in {}!", amountModified, stopwatch);
+ //for (Map.Entry modifierEntry : modifiers.entrySet()) {
+ // final LootModifier modifier = modifierEntry.getValue();
+
+ // amountModified += modifier.apply(lootRegistry);
+
+ // // TODO: try to figure smt out abt this: if (!modifier.modifies().isEmpty()) failedModifiers.put(modifierEntry.getKey(), modifier);
+ //}
+
+
+ LOGGER.info("Applied {} modifiers and modified {} loot tables in {}!", modifiers.size(), amountModified, stopwatch);
modifiersApplied(failedModifiers);
}
@@ -64,7 +133,7 @@ private static Map loadModifiers(ResourceManager resou
final Identifier id = entry.getKey();
try {
- LOGGER.debug("Loading load loot table modifier from '%s'".formatted(id));
+ LOGGER.debug("Loading load loot table modifier from '{}'", id);
result.put(
id,
LootModifier.CODEC.decode(registryOps, JsonParser.parseReader(entry.getValue().getReader())).getOrThrow().getFirst()
@@ -84,15 +153,37 @@ private static void modifiersApplied(Map failedModifie
if (failedModifiers.isEmpty()) return;
LOGGER.warn("There were unused modifiers:");
- for (Map.Entry entry : failedModifiers.entrySet()) {
- LOGGER.warn("\tModifier '{}' failed to modify loot table for predicates: ", entry.getKey());
- for (LootTablePredicate predicate : entry.getValue().modifies()) {
- LOGGER.warn("\t\t- {}", predicate);
- }
- }
+ //for (Map.Entry entry : failedModifiers.entrySet()) {
+ // LOGGER.warn("\tModifier '{}' failed to modify loot table for predicates: ", entry.getKey());
+ // for (LootTablePredicate predicate : entry.getValue().modifies()) {
+ // LOGGER.warn("\t\t- {}", predicate);
+ // }
+ //}
}
public static Identifier id(String path) {
return Identifier.of(MOD_ID, path);
}
+
+ /*
+ In 1.21.4, the 'Registry' class extends 'RegistryWrapper' and inherits the 'streamEntries' method from *it*.
+ In 1.20.5, the 'Registry' class *doesn't* extend the 'RegistryWrapper' and implements its own 'streamEntries' method.
+ Compiling on both versions works, because the names of the methods are the same, but they compile to different intermediary names, thus a jar compiled for 1.20.5 doesn't work on 1.21.4 and vice versa.
+ Solution: Turn the 'Registry' into a 'RegistryWrapper' as its 'streamEntries' retains the same intermediary on both versions.
+ If 'Registry' implements 'RegistryWrapper': cast it
+ Else: call 'getReadOnlyWrapper' on the registry (doesn't exist on 1.21.4, otherwise would've used 'registry.getReadOnlyWrapper().streamEntries()')
+ */
+ private static RegistryWrapper getRegistryAsWrapper(@NotNull Registry registry) {
+ //noinspection ConstantValue,RedundantSuppression: On lower versions, Registry doesn't extend RegistryWrapper and thus the 'isAssignableFrom' check can be false. The redundant supression is for the unchecked cast below.
+ if (RegistryWrapper.class.isAssignableFrom(registry.getClass()))
+ //noinspection unchecked,RedundantCast: I swear it casts 🤞
+ return (RegistryWrapper