diff --git a/fabric-loot-api-v2/README.md b/deprecated/fabric-loot-api-v2/README.md similarity index 100% rename from fabric-loot-api-v2/README.md rename to deprecated/fabric-loot-api-v2/README.md diff --git a/deprecated/fabric-loot-api-v2/build.gradle b/deprecated/fabric-loot-api-v2/build.gradle new file mode 100644 index 000000000..f7fd248b6 --- /dev/null +++ b/deprecated/fabric-loot-api-v2/build.gradle @@ -0,0 +1,7 @@ +version = getSubprojectVersion(project) + +moduleDependencies(project, [ + 'fabric-api-base', + 'fabric-resource-loader-v0', + 'fabric-loot-api-v3' +]) diff --git a/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java new file mode 100644 index 000000000..209d0fb73 --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.loot.v2; + +import java.util.Collection; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.loot.LootPool; +import net.minecraft.loot.condition.LootCondition; +import net.minecraft.loot.entry.LootPoolEntry; +import net.minecraft.loot.function.LootFunction; + +/** + * Convenience extensions to {@link LootPool.Builder} + * for adding pre-built objects or collections. + * + *

This interface is automatically injected to {@link LootPool.Builder}. + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder} instead. + */ +@ApiStatus.NonExtendable +@Deprecated +public interface FabricLootPoolBuilder { + /** + * Adds an entry to this builder. + * + * @param entry the added loot entry + * @return this builder + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder#with(LootPoolEntry)} instead. + */ + @Deprecated + default LootPool.Builder with(LootPoolEntry entry) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Adds entries to this builder. + * + * @param entries the added loot entries + * @return this builder + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder#with(LootPoolEntry)} instead. + */ + @Deprecated + default LootPool.Builder with(Collection entries) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Adds a condition to this builder. + * + * @param condition the added condition + * @return this builder + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder#conditionally(LootCondition)} instead. + */ + @Deprecated + default LootPool.Builder conditionally(LootCondition condition) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Adds conditions to this builder. + * + * @param conditions the added conditions + * @return this builder + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder#conditionally(LootCondition)} instead. + */ + @Deprecated + default LootPool.Builder conditionally(Collection conditions) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Applies a function to this builder. + * + * @param function the applied loot function + * @return this builder + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder#apply(LootFunction)} instead. + */ + @Deprecated + default LootPool.Builder apply(LootFunction function) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Applies loot functions to this builder. + * + * @param functions the applied loot functions + * @return this builder + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder#apply(LootFunction)} instead. + */ + @Deprecated + default LootPool.Builder apply(Collection functions) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Creates a builder copy of a loot pool. + * + * @param pool the loot pool + * @return the copied builder + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder#copyOf(LootPool)} instead. + */ + @Deprecated + static LootPool.Builder copyOf(LootPool pool) { + return net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder.copyOf(pool); + } +} diff --git a/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java new file mode 100644 index 000000000..993d9b87e --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.loot.v2; + +import java.util.Collection; +import java.util.function.Consumer; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.loot.LootPool; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.function.LootFunction; + +/** + * Convenience extensions to {@link LootTable.Builder} + * for adding pre-built objects or collections and modifying loot pools. + * + *

This interface is automatically injected to {@link LootTable.Builder}. + * + * @deprecated use {@link net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder} instead. + */ +@ApiStatus.NonExtendable +@Deprecated +public interface FabricLootTableBuilder { + /** + * Adds a loot pool to this builder. + * + * @param pool the added pool + * @return this builder + * @deprecated use {@link net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder#pool(LootPool)} instead. + */ + @Deprecated + default LootTable.Builder pool(LootPool pool) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Applies a loot function to this builder. + * + * @param function the applied function + * @return this builder + * @deprecated use {@link net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder#apply(LootFunction)} instead. + */ + @Deprecated + default LootTable.Builder apply(LootFunction function) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Adds loot pools to this builder. + * + * @param pools the added pools + * @return this builder + * @deprecated use {@link net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder#pools(Collection)} instead. + */ + @Deprecated + default LootTable.Builder pools(Collection pools) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Applies loot functions to this builder. + * + * @param functions the applied functions + * @return this builder + * @deprecated use {@link net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder#apply(Collection)} instead. + */ + @Deprecated + default LootTable.Builder apply(Collection functions) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Modifies all loot pools already present in this builder. + * + *

This method can be used instead of simply adding a new pool + * when you want the loot table to only drop items from one of the loot pool entries + * instead of both. + * + *

Calling this method turns all pools into builders and rebuilds them back into loot pools afterwards, + * so it is more efficient to do all transformations with one {@code modifyPools} call. + * + * @param modifier the modifying function + * @return this builder + * @deprecated use {@link net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder#modifyPools(Consumer)} instead. + */ + @Deprecated + default LootTable.Builder modifyPools(Consumer modifier) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Creates a builder copy of a loot table. + * + * @param table the loot table + * @return the copied builder + * @deprecated use {@link net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder#copyOf(LootTable)} instead. + */ + @Deprecated + static LootTable.Builder copyOf(LootTable table) { + return net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder.copyOf(table); + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java similarity index 90% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java rename to deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java index dd7959779..5c1088d8d 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java +++ b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java @@ -28,7 +28,10 @@ import net.fabricmc.fabric.api.event.EventFactory; /** * Events for manipulating loot tables. + * + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.LootTableEvents} instead. */ +@Deprecated public final class LootTableEvents { private LootTableEvents() { } @@ -36,7 +39,10 @@ public final class LootTableEvents { /** * This event can be used to replace loot tables. * If a loot table is replaced, the iteration will stop for that loot table. + * + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.LootTableEvents#REPLACE} instead. */ + @Deprecated public static final Event REPLACE = EventFactory.createArrayBacked(Replace.class, listeners -> (key, original, source) -> { for (Replace listener : listeners) { @Nullable LootTable replaced = listener.replaceLootTable(key, original, source); @@ -82,7 +88,10 @@ public final class LootTableEvents { * }); * } * + * + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.LootTableEvents#MODIFY} instead. */ + @Deprecated public static final Event MODIFY = EventFactory.createArrayBacked(Modify.class, listeners -> (key, tableBuilder, source) -> { for (Modify listener : listeners) { listener.modifyLootTable(key, tableBuilder, source); @@ -91,13 +100,17 @@ public final class LootTableEvents { /** * This event can be used for post-processing after all loot tables have been loaded and modified by Fabric. + * + * @deprecated Please use {@link net.fabricmc.fabric.api.loot.v3.LootTableEvents#ALL_LOADED} instead. */ + @Deprecated public static final Event ALL_LOADED = EventFactory.createArrayBacked(Loaded.class, listeners -> (resourceManager, lootManager) -> { for (Loaded listener : listeners) { listener.onLootTablesLoaded(resourceManager, lootManager); } }); + @Deprecated public interface Replace { /** * Replaces loot tables. @@ -111,6 +124,7 @@ public final class LootTableEvents { LootTable replaceLootTable(RegistryKey key, LootTable original, LootTableSource source); } + @Deprecated public interface Modify { /** * Called when a loot table is loading to modify loot tables. @@ -122,6 +136,7 @@ public final class LootTableEvents { void modifyLootTable(RegistryKey key, LootTable.Builder tableBuilder, LootTableSource source); } + @Deprecated public interface Loaded { /** * Called when all loot tables have been loaded and {@link LootTableEvents#REPLACE} and {@link LootTableEvents#MODIFY} have been invoked. diff --git a/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java new file mode 100644 index 000000000..4bbe90f38 --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.loot.v2; + +/** + * Describes where a loot table has been loaded from. + * @deprecated Use {@link net.fabricmc.fabric.api.loot.v3.LootTableSource} instead. + */ +@Deprecated +public enum LootTableSource { + /** + * A loot table loaded from the default data pack. + */ + VANILLA(true), + + /** + * A loot table loaded from mods' bundled resources. + * + *

This includes the additional builtin data packs registered by mods + * with Fabric Resource Loader. + */ + MOD(true), + + /** + * A loot table loaded from an external data pack. + */ + DATA_PACK(false), + + /** + * A loot table created in {@link LootTableEvents#REPLACE}. + */ + REPLACED(false); + + private final boolean builtin; + + LootTableSource(boolean builtin) { + this.builtin = builtin; + } + + /** + * Returns whether this loot table source is builtin + * and bundled in the vanilla or mod resources. + * + *

{@link #VANILLA} and {@link #MOD} are builtin. + * + * @return {@code true} if builtin, {@code false} otherwise + */ + public boolean isBuiltin() { + return builtin; + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/package-info.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/package-info.java similarity index 100% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/package-info.java rename to deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/package-info.java diff --git a/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/v2/LootInitializer.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/v2/LootInitializer.java new file mode 100644 index 000000000..adcd51932 --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/v2/LootInitializer.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.loot.v2; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.loot.v3.LootTableEvents; +import net.fabricmc.fabric.api.loot.v3.LootTableSource; + +public class LootInitializer implements ModInitializer { + @Override + public void onInitialize() { + // Forward the events to the v2 API. + LootTableEvents.REPLACE.register(((key, original, source, registries) -> net.fabricmc.fabric.api.loot.v2.LootTableEvents.REPLACE.invoker().replaceLootTable(key, original, toV2Source(source)))); + LootTableEvents.MODIFY.register((key, tableBuilder, source, registries) -> net.fabricmc.fabric.api.loot.v2.LootTableEvents.MODIFY.invoker().modifyLootTable(key, tableBuilder, toV2Source(source))); + LootTableEvents.ALL_LOADED.register((resourceManager, lootRegistry) -> net.fabricmc.fabric.api.loot.v2.LootTableEvents.ALL_LOADED.invoker().onLootTablesLoaded(resourceManager, lootRegistry)); + } + + private static net.fabricmc.fabric.api.loot.v2.LootTableSource toV2Source(LootTableSource source) { + return switch (source) { + case VANILLA -> net.fabricmc.fabric.api.loot.v2.LootTableSource.VANILLA; + case MOD -> net.fabricmc.fabric.api.loot.v2.LootTableSource.MOD; + case DATA_PACK -> net.fabricmc.fabric.api.loot.v2.LootTableSource.DATA_PACK; + case REPLACED -> net.fabricmc.fabric.api.loot.v2.LootTableSource.REPLACED; + }; + } +} diff --git a/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/v2/LootPoolBuilderMixin.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/v2/LootPoolBuilderMixin.java new file mode 100644 index 000000000..c45d21c8d --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/v2/LootPoolBuilderMixin.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.loot.v2; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.loot.LootPool; + +import net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder; + +/** + * The v3 module injects all the necessary methods into the target class. + */ +@Mixin(LootPool.Builder.class) +abstract class LootPoolBuilderMixin implements FabricLootPoolBuilder { +} diff --git a/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/v2/LootTableBuilderMixin.java b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/v2/LootTableBuilderMixin.java new file mode 100644 index 000000000..c887fa132 --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/v2/LootTableBuilderMixin.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.loot.v2; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.loot.LootTable; + +import net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder; + +/** + * The v3 module injects all the necessary methods into the target class. + */ +@Mixin(LootTable.Builder.class) +abstract class LootTableBuilderMixin implements FabricLootTableBuilder { +} diff --git a/fabric-loot-api-v2/src/main/resources/assets/fabric-loot-api-v2/icon.png b/deprecated/fabric-loot-api-v2/src/main/resources/assets/fabric-loot-api-v2/icon.png similarity index 100% rename from fabric-loot-api-v2/src/main/resources/assets/fabric-loot-api-v2/icon.png rename to deprecated/fabric-loot-api-v2/src/main/resources/assets/fabric-loot-api-v2/icon.png diff --git a/deprecated/fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json b/deprecated/fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json new file mode 100644 index 000000000..15d28a491 --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.mixin.loot.v2", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "LootPoolBuilderMixin", + "LootTableBuilderMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/deprecated/fabric-loot-api-v2/src/main/resources/fabric.mod.json b/deprecated/fabric-loot-api-v2/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..a7cdc9dd9 --- /dev/null +++ b/deprecated/fabric-loot-api-v2/src/main/resources/fabric.mod.json @@ -0,0 +1,35 @@ +{ + "schemaVersion": 1, + "id": "fabric-loot-api-v2", + "name": "Fabric Loot API (v2)", + "version": "${version}", + "environment": "*", + "license": "Apache-2.0", + "icon": "assets/fabric-loot-api-v2/icon.png", + "contact": { + "homepage": "https://fabricmc.net", + "irc": "irc://irc.esper.net:6667/fabric", + "issues": "https://github.com/FabricMC/fabric/issues", + "sources": "https://github.com/FabricMC/fabric" + }, + "authors": [ + "FabricMC" + ], + "depends": { + "fabricloader": ">=0.15.11", + "fabric-api-base": "*", + "fabric-resource-loader-v0": "*" + }, + "description": "Hooks for manipulating loot tables.", + "entrypoints": { + "main": [ + "net.fabricmc.fabric.impl.loot.v2.LootInitializer" + ] + }, + "mixins": [ + "fabric-loot-api-v2.mixins.json" + ], + "custom": { + "fabric-api:module-lifecycle": "deprecated" + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/ReloadableRegistriesMixin.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/ReloadableRegistriesMixin.java deleted file mode 100644 index aaedc21da..000000000 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/ReloadableRegistriesMixin.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.fabric.mixin.loot; - -import com.llamalad7.mixinextras.sugar.Local; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import net.minecraft.loot.LootDataType; -import net.minecraft.loot.LootTable; -import net.minecraft.registry.MutableRegistry; -import net.minecraft.registry.Registry; -import net.minecraft.registry.RegistryKey; -import net.minecraft.registry.RegistryKeys; -import net.minecraft.registry.RegistryOps; -import net.minecraft.registry.ReloadableRegistries; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder; -import net.fabricmc.fabric.api.loot.v2.LootTableEvents; -import net.fabricmc.fabric.api.loot.v2.LootTableSource; -import net.fabricmc.fabric.impl.loot.LootUtil; - -/** - * Implements the events from {@link LootTableEvents}. - */ -@Mixin(ReloadableRegistries.class) -abstract class ReloadableRegistriesMixin { - @ModifyArg(method = "method_58286", at = @At(value = "INVOKE", target = "Lnet/minecraft/registry/MutableRegistry;add(Lnet/minecraft/registry/RegistryKey;Ljava/lang/Object;Lnet/minecraft/registry/entry/RegistryEntryInfo;)Lnet/minecraft/registry/entry/RegistryEntry$Reference;"), index = 1) - private static Object modifyLootTable(Object value, @Local(argsOnly = true) Identifier id) { - if (!(value instanceof LootTable table)) return value; - - if (table == LootTable.EMPTY) { - // This is a special table and cannot be modified. - return value; - } - - RegistryKey key = RegistryKey.of(RegistryKeys.LOOT_TABLE, id); - // Populated inside JsonDataLoaderMixin - LootTableSource source = LootUtil.SOURCES.get().getOrDefault(id, LootTableSource.DATA_PACK); - // Invoke the REPLACE event for the current loot table. - LootTable replacement = LootTableEvents.REPLACE.invoker().replaceLootTable(key, table, source); - - if (replacement != null) { - // Set the loot table to MODIFY to be the replacement loot table. - // The MODIFY event will also see it as a replaced loot table via the source. - table = replacement; - source = LootTableSource.REPLACED; - } - - // Turn the current table into a modifiable builder and invoke the MODIFY event. - LootTable.Builder builder = FabricLootTableBuilder.copyOf(table); - LootTableEvents.MODIFY.invoker().modifyLootTable(key, builder, source); - - return builder.build(); - } - - @SuppressWarnings("unchecked") - @Inject(method = "method_58279", at = @At("RETURN")) - private static void onLootTablesLoaded(LootDataType lootDataType, ResourceManager resourceManager, RegistryOps registryOps, CallbackInfoReturnable cir) { - if (lootDataType != LootDataType.LOOT_TABLES) return; - - LootTableEvents.ALL_LOADED.invoker().onLootTablesLoaded(resourceManager, (Registry) cir.getReturnValue()); - LootUtil.SOURCES.remove(); - } -} diff --git a/fabric-loot-api-v3/README.md b/fabric-loot-api-v3/README.md new file mode 100644 index 000000000..f108708af --- /dev/null +++ b/fabric-loot-api-v3/README.md @@ -0,0 +1,29 @@ +# Fabric Loot API (v3) + +This module includes APIs for modifying and creating loot tables. + +## [Loot table events](src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableEvents.java) + +This class provides two events for modifying loot tables. + +`LootTableEvents.REPLACE` runs first and lets you replace loot tables completely. + +`LootTableEvents.MODIFY` runs after and lets you modify loot tables, including the ones created in `REPLACE`, +by adding new loot pools or loot functions to them. + +### Loot table sources + +Both events have access to a [loot table source](src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableSource.java) +that you can use to check where a loot table is loaded from. + +For example, you can use this to check if a loot table is from a user data pack and +not modify the user-provided data in your event. + +## Enhanced loot table and loot pool builders + +`LootTable.Builder` and `LootPool.Builder` implement +injected interfaces ([`FabricLootTableBuilder`](src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootTableBuilder.java) +and [`FabricLootPoolBuilder`](src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootPoolBuilder.java)) +which have additional methods for dealing with already-built objects and collections of objects. + +Those interfaces also have `copyOf` methods for creating copies of existing loot tables/pools as builders. diff --git a/fabric-loot-api-v2/build.gradle b/fabric-loot-api-v3/build.gradle similarity index 100% rename from fabric-loot-api-v2/build.gradle rename to fabric-loot-api-v3/build.gradle diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootPoolBuilder.java similarity index 98% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootPoolBuilder.java index 359d816a2..9c4ef5c1d 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootPoolBuilder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.loot.v2; +package net.fabricmc.fabric.api.loot.v3; import java.util.Collection; diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootTableBuilder.java similarity index 98% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootTableBuilder.java index d966a3642..d42bedda2 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/FabricLootTableBuilder.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.loot.v2; +package net.fabricmc.fabric.api.loot.v3; import java.util.Collection; import java.util.function.Consumer; diff --git a/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableEvents.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableEvents.java new file mode 100644 index 000000000..a8768d190 --- /dev/null +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableEvents.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.loot.v3; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.loot.LootTable; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.resource.ResourceManager; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * Events for manipulating loot tables. + */ +public final class LootTableEvents { + private LootTableEvents() { + } + + /** + * This event can be used to replace loot tables. + * If a loot table is replaced, the iteration will stop for that loot table. + */ + public static final Event REPLACE = EventFactory.createArrayBacked(Replace.class, listeners -> (key, original, source, registries) -> { + for (Replace listener : listeners) { + @Nullable LootTable replaced = listener.replaceLootTable(key, original, source, registries); + + if (replaced != null) { + return replaced; + } + } + + return null; + }); + + /** + * This event can be used to modify loot tables. + * The main use case is to add items to vanilla or mod loot tables (e.g. modded seeds to grass). + * + *

You can also modify loot tables that are created by {@link #REPLACE}. + * They have the loot table source {@link LootTableSource#REPLACED}. + * + *

Example: adding diamonds to the cobblestone loot table

+ * We'll add a new diamond {@linkplain net.minecraft.loot.LootPool loot pool} to the cobblestone loot table + * that will be dropped alongside the original cobblestone loot pool. + * + *

If you want only one of the items to drop, you can use + * {@link FabricLootTableBuilder#modifyPools(java.util.function.Consumer)} to add the new item to + * the original loot pool instead. + * {@snippet : + * LootTableEvents.MODIFY.register((key, tableBuilder, source, registries) -> { + * // If the loot table is for the cobblestone block and it is not overridden by a user: + * if (Blocks.COBBLESTONE.getLootTableKey() == key && source.isBuiltin()) { + * // Create a new loot pool that will hold the diamonds. + * LootPool.Builder pool = LootPool.builder() + * // Add diamonds... + * .with(ItemEntry.builder(Items.DIAMOND)) + * // ...only if the block would survive a potential explosion. + * .conditionally(SurvivesExplosionLootCondition.builder()); + * + * // Add the loot pool to the loot table + * tableBuilder.pool(pool); + * } + * }); + * } + */ + public static final Event MODIFY = EventFactory.createArrayBacked(Modify.class, listeners -> (key, tableBuilder, source, registries) -> { + for (Modify listener : listeners) { + listener.modifyLootTable(key, tableBuilder, source, registries); + } + }); + + /** + * This event can be used for post-processing after all loot tables have been loaded and modified by Fabric. + */ + public static final Event ALL_LOADED = EventFactory.createArrayBacked(Loaded.class, listeners -> (resourceManager, lootManager) -> { + for (Loaded listener : listeners) { + listener.onLootTablesLoaded(resourceManager, lootManager); + } + }); + + @FunctionalInterface + public interface Replace { + /** + * Replaces loot tables. + * + * @param key the loot table key + * @param original the original loot table + * @param source the source of the original loot table + * @param registries the registry wrapper lookup + * @return the new loot table, or null if it wasn't replaced + */ + @Nullable + LootTable replaceLootTable(RegistryKey key, LootTable original, LootTableSource source, RegistryWrapper.WrapperLookup registries); + } + + @FunctionalInterface + public interface Modify { + /** + * Called when a loot table is loading to modify loot tables. + * + * @param key the loot table key + * @param tableBuilder a builder of the loot table being loaded + * @param source the source of the loot table + * @param registries the registry wrapper lookup + */ + void modifyLootTable(RegistryKey key, LootTable.Builder tableBuilder, LootTableSource source, RegistryWrapper.WrapperLookup registries); + } + + @FunctionalInterface + public interface Loaded { + /** + * Called when all loot tables have been loaded and {@link LootTableEvents#REPLACE} and {@link LootTableEvents#MODIFY} have been invoked. + * + * @param resourceManager the server resource manager + * @param lootRegistry the loot registry + */ + void onLootTablesLoaded(ResourceManager resourceManager, Registry lootRegistry); + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableSource.java similarity index 97% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableSource.java index c2b48a4d8..6e2af8915 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/LootTableSource.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.loot.v2; +package net.fabricmc.fabric.api.loot.v3; /** * Describes where a loot table has been loaded from. diff --git a/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/package-info.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/package-info.java new file mode 100644 index 000000000..50687772f --- /dev/null +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/api/loot/v3/package-info.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The Fabric Loot API for manipulating and creating loot tables. + * + *

Events

+ * {@link net.fabricmc.fabric.api.loot.v3.LootTableEvents} has events to modify existing loot tables, + * or outright replace them with a new loot table. + * + *

You can also check where loot tables are coming from in those events with + * {@link net.fabricmc.fabric.api.loot.v3.LootTableSource}. This is useful when you only want to modify + * loot tables from mods or vanilla, but not user-created data packs. + * + *

Extended loot table and pool builders

+ * This API has injected interfaces to add useful methods to + * {@linkplain net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder loot table} and + * {@linkplain net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder loot pool} builders. + * They let you add pre-built objects instead of builders, and collections of objects to the builder + * with one method call. + */ +package net.fabricmc.fabric.api.loot.v3; diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java similarity index 97% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java index 2dfa5cf47..0f4543d4e 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java @@ -23,7 +23,7 @@ import net.minecraft.resource.Resource; import net.minecraft.resource.ResourcePackSource; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.loot.v2.LootTableSource; +import net.fabricmc.fabric.api.loot.v3.LootTableSource; import net.fabricmc.fabric.impl.resource.loader.BuiltinModResourcePackSource; import net.fabricmc.fabric.impl.resource.loader.FabricResource; import net.fabricmc.fabric.impl.resource.loader.ModResourcePackCreator; diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/JsonDataLoaderMixin.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/JsonDataLoaderMixin.java similarity index 100% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/JsonDataLoaderMixin.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/JsonDataLoaderMixin.java diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java similarity index 91% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java index f681f0f75..c855bd63a 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java @@ -27,8 +27,10 @@ import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.function.LootFunction; import net.minecraft.loot.provider.number.LootNumberProvider; +import net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder; + /** - * Accesses loot pool fields for {@link net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder#copyOf(LootPool)}. + * Accesses loot pool fields for {@link FabricLootPoolBuilder#copyOf(LootPool)}. * These are normally available in the transitive access widener module. */ @Mixin(LootPool.class) diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java similarity index 97% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java index d0326b7de..65e068113 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java @@ -29,7 +29,7 @@ import net.minecraft.loot.condition.LootCondition; import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.function.LootFunction; -import net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder; +import net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder; /** * The implementation of the injected interface {@link FabricLootPoolBuilder}. diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java similarity index 89% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java index 4e8993eed..ac53818e1 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java @@ -27,8 +27,10 @@ import net.minecraft.loot.LootTable; import net.minecraft.loot.function.LootFunction; import net.minecraft.util.Identifier; +import net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder; + /** - * Accesses loot table fields for {@link net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder#copyOf(LootTable)}. + * Accesses loot table fields for {@link FabricLootTableBuilder#copyOf(LootTable)}. * These are normally available in the transitive access widener module. */ @Mixin(LootTable.class) diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java similarity index 95% rename from fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java rename to fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java index 91b5ed703..de6613703 100644 --- a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java @@ -32,8 +32,8 @@ import net.minecraft.loot.LootPool; import net.minecraft.loot.LootTable; import net.minecraft.loot.function.LootFunction; -import net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder; -import net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder; +import net.fabricmc.fabric.api.loot.v3.FabricLootPoolBuilder; +import net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder; /** * The implementation of the injected interface {@link FabricLootTableBuilder}. diff --git a/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/ReloadableRegistriesMixin.java b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/ReloadableRegistriesMixin.java new file mode 100644 index 000000000..a280f685b --- /dev/null +++ b/fabric-loot-api-v3/src/main/java/net/fabricmc/fabric/mixin/loot/ReloadableRegistriesMixin.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.loot; + +import java.util.List; +import java.util.Optional; +import java.util.WeakHashMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Consumer; +import java.util.function.Function; + +import com.google.gson.JsonElement; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.serialization.DynamicOps; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Coerce; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.loot.LootDataType; +import net.minecraft.loot.LootTable; +import net.minecraft.registry.CombinedDynamicRegistries; +import net.minecraft.registry.MutableRegistry; +import net.minecraft.registry.Registry; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.RegistryOps; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.ReloadableRegistries; +import net.minecraft.registry.ServerDynamicRegistryType; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.loot.v3.FabricLootTableBuilder; +import net.fabricmc.fabric.api.loot.v3.LootTableEvents; +import net.fabricmc.fabric.api.loot.v3.LootTableSource; +import net.fabricmc.fabric.impl.loot.LootUtil; + +/** + * Implements the events from {@link LootTableEvents}. + */ +@Mixin(ReloadableRegistries.class) +abstract class ReloadableRegistriesMixin { + /** + * Due to possible cross-thread handling, this uses WeakHashMap instead of ThreadLocal. + */ + @Unique + private static final WeakHashMap, RegistryWrapper.WrapperLookup> WRAPPERS = new WeakHashMap<>(); + + @WrapOperation(method = "reload", at = @At(value = "INVOKE", target = "Lnet/minecraft/registry/ReloadableRegistries$ReloadableWrapperLookup;getOps(Lcom/mojang/serialization/DynamicOps;)Lnet/minecraft/registry/RegistryOps;")) + private static RegistryOps storeOps(@Coerce RegistryWrapper.WrapperLookup registries, DynamicOps ops, Operation> original) { + RegistryOps created = original.call(registries, ops); + WRAPPERS.put(created, registries); + return created; + } + + @WrapOperation(method = "reload", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenApplyAsync(Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) + private static CompletableFuture> removeOps(CompletableFuture>> future, Function>, ? extends CombinedDynamicRegistries> fn, Executor executor, Operation>> original, @Local RegistryOps ops) { + return original.call(future.thenApply(v -> { + WRAPPERS.remove(ops); + return v; + }), fn, executor); + } + + @WrapOperation(method = "method_58278", at = @At(value = "INVOKE", target = "Ljava/util/Optional;ifPresent(Ljava/util/function/Consumer;)V")) + private static void modifyLootTable(Optional optionalTable, Consumer action, Operation original, @Local(argsOnly = true) Identifier id, @Local(argsOnly = true) RegistryOps ops) { + original.call(optionalTable.map(table -> modifyLootTable(table, id, ops)), action); + } + + @Unique + private static T modifyLootTable(T value, Identifier id, RegistryOps ops) { + if (!(value instanceof LootTable table)) return value; + + if (table == LootTable.EMPTY) { + // This is a special table and cannot be modified. + return value; + } + + RegistryKey key = RegistryKey.of(RegistryKeys.LOOT_TABLE, id); + // Populated above. + RegistryWrapper.WrapperLookup registries = WRAPPERS.get(ops); + // Populated inside JsonDataLoaderMixin + LootTableSource source = LootUtil.SOURCES.get().getOrDefault(id, LootTableSource.DATA_PACK); + // Invoke the REPLACE event for the current loot table. + LootTable replacement = LootTableEvents.REPLACE.invoker().replaceLootTable(key, table, source, registries); + + if (replacement != null) { + // Set the loot table to MODIFY to be the replacement loot table. + // The MODIFY event will also see it as a replaced loot table via the source. + table = replacement; + source = LootTableSource.REPLACED; + } + + // Turn the current table into a modifiable builder and invoke the MODIFY event. + LootTable.Builder builder = FabricLootTableBuilder.copyOf(table); + LootTableEvents.MODIFY.invoker().modifyLootTable(key, builder, source, registries); + + return (T) builder.build(); + } + + @SuppressWarnings("unchecked") + @Inject(method = "method_58279", at = @At("RETURN")) + private static void onLootTablesLoaded(LootDataType lootDataType, ResourceManager resourceManager, RegistryOps registryOps, CallbackInfoReturnable> cir) { + if (lootDataType != LootDataType.LOOT_TABLES) return; + + LootTableEvents.ALL_LOADED.invoker().onLootTablesLoaded(resourceManager, (Registry) cir.getReturnValue()); + LootUtil.SOURCES.remove(); + } +} diff --git a/fabric-loot-api-v3/src/main/resources/assets/fabric-loot-api-v3/icon.png b/fabric-loot-api-v3/src/main/resources/assets/fabric-loot-api-v3/icon.png new file mode 100644 index 000000000..2931efbf6 Binary files /dev/null and b/fabric-loot-api-v3/src/main/resources/assets/fabric-loot-api-v3/icon.png differ diff --git a/fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json b/fabric-loot-api-v3/src/main/resources/fabric-loot-api-v3.mixins.json similarity index 100% rename from fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json rename to fabric-loot-api-v3/src/main/resources/fabric-loot-api-v3.mixins.json diff --git a/fabric-loot-api-v2/src/main/resources/fabric.mod.json b/fabric-loot-api-v3/src/main/resources/fabric.mod.json similarity index 77% rename from fabric-loot-api-v2/src/main/resources/fabric.mod.json rename to fabric-loot-api-v3/src/main/resources/fabric.mod.json index 9f766e642..d7cb6d194 100644 --- a/fabric-loot-api-v2/src/main/resources/fabric.mod.json +++ b/fabric-loot-api-v3/src/main/resources/fabric.mod.json @@ -1,11 +1,11 @@ { "schemaVersion": 1, - "id": "fabric-loot-api-v2", - "name": "Fabric Loot API (v2)", + "id": "fabric-loot-api-v3", + "name": "Fabric Loot API (v3)", "version": "${version}", "environment": "*", "license": "Apache-2.0", - "icon": "assets/fabric-loot-api-v2/icon.png", + "icon": "assets/fabric-loot-api-v3/icon.png", "contact": { "homepage": "https://fabricmc.net", "irc": "irc://irc.esper.net:6667/fabric", @@ -22,13 +22,13 @@ }, "description": "Hooks for manipulating loot tables.", "mixins": [ - "fabric-loot-api-v2.mixins.json" + "fabric-loot-api-v3.mixins.json" ], "custom": { "fabric-api:module-lifecycle": "stable", "loom:injected_interfaces": { - "net/minecraft/class_52\u0024class_53": ["net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder"], - "net/minecraft/class_55\u0024class_56": ["net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder"] + "net/minecraft/class_52\u0024class_53": ["net/fabricmc/fabric/api/loot/v3/FabricLootTableBuilder"], + "net/minecraft/class_55\u0024class_56": ["net/fabricmc/fabric/api/loot/v3/FabricLootPoolBuilder"] } } } diff --git a/fabric-loot-api-v2/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java b/fabric-loot-api-v3/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java similarity index 73% rename from fabric-loot-api-v2/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java rename to fabric-loot-api-v3/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java index 354c25b74..292206ab5 100644 --- a/fabric-loot-api-v2/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java +++ b/fabric-loot-api-v3/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java @@ -16,18 +16,27 @@ package net.fabricmc.fabric.test.loot; +import java.util.Optional; + import net.minecraft.block.Blocks; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.EntityType; import net.minecraft.item.Items; import net.minecraft.loot.LootPool; import net.minecraft.loot.LootTable; import net.minecraft.loot.condition.SurvivesExplosionLootCondition; import net.minecraft.loot.entry.ItemEntry; +import net.minecraft.loot.function.SetEnchantmentsLootFunction; import net.minecraft.loot.function.SetNameLootFunction; +import net.minecraft.loot.provider.number.ConstantLootNumberProvider; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.text.Text; import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.loot.v2.LootTableEvents; -import net.fabricmc.fabric.api.loot.v2.LootTableSource; +import net.fabricmc.fabric.api.loot.v3.LootTableEvents; +import net.fabricmc.fabric.api.loot.v3.LootTableSource; public class LootTest implements ModInitializer { @Override @@ -35,7 +44,7 @@ public class LootTest implements ModInitializer { // Test loot table load event // The LootTable.Builder LootPool.Builder methods here should use // prebuilt entries and pools to test the injected methods. - LootTableEvents.REPLACE.register((key, original, source) -> { + LootTableEvents.REPLACE.register((key, original, source, registries) -> { if (Blocks.BLACK_WOOL.getLootTableKey() == key) { if (source != LootTableSource.VANILLA) { throw new AssertionError("black wool loot table should have LootTableSource.VANILLA, got " + source); @@ -53,7 +62,7 @@ public class LootTest implements ModInitializer { }); // Test that the event is stopped when the loot table is replaced - LootTableEvents.REPLACE.register((key, original, source) -> { + LootTableEvents.REPLACE.register((key, original, source, registries) -> { if (Blocks.BLACK_WOOL.getLootTableKey() == key) { throw new AssertionError("Event should have been stopped from replaced loot table"); } @@ -61,7 +70,7 @@ public class LootTest implements ModInitializer { return null; }); - LootTableEvents.MODIFY.register((key, tableBuilder, source) -> { + LootTableEvents.MODIFY.register((key, tableBuilder, source, registries) -> { if (Blocks.BLACK_WOOL.getLootTableKey() == key && source != LootTableSource.REPLACED) { throw new AssertionError("black wool loot table should have LootTableSource.REPLACED, got " + source); } @@ -93,6 +102,18 @@ public class LootTest implements ModInitializer { } }); + LootTableEvents.MODIFY.register((key, tableBuilder, source, registries) -> { + if (EntityType.SALMON.getLootTableId() == key) { + Optional> lure = registries.getOptionalWrapper(RegistryKeys.ENCHANTMENT).flatMap(registry -> registry.getOptional(Enchantments.LURE)); + + lure.ifPresent((lureEnchantment) -> tableBuilder.pool(LootPool.builder().with( + ItemEntry.builder(Items.FISHING_ROD) + ).apply( + new SetEnchantmentsLootFunction.Builder().enchantment(lureEnchantment, ConstantLootNumberProvider.create(1)) + ))); + } + }); + LootTableEvents.ALL_LOADED.register((resourceManager, lootRegistry) -> { LootTable blackWoolTable = lootRegistry.get(Blocks.BLACK_WOOL.getLootTableKey()); diff --git a/fabric-loot-api-v2/src/testmod/resources/data/minecraft/loot_table/blocks/red_wool.json b/fabric-loot-api-v3/src/testmod/resources/data/minecraft/loot_table/blocks/red_wool.json similarity index 100% rename from fabric-loot-api-v2/src/testmod/resources/data/minecraft/loot_table/blocks/red_wool.json rename to fabric-loot-api-v3/src/testmod/resources/data/minecraft/loot_table/blocks/red_wool.json diff --git a/fabric-loot-api-v2/src/testmod/resources/data/minecraft/predicate/match_tool_shears.json b/fabric-loot-api-v3/src/testmod/resources/data/minecraft/predicate/match_tool_shears.json similarity index 100% rename from fabric-loot-api-v2/src/testmod/resources/data/minecraft/predicate/match_tool_shears.json rename to fabric-loot-api-v3/src/testmod/resources/data/minecraft/predicate/match_tool_shears.json diff --git a/fabric-loot-api-v2/src/testmod/resources/fabric.mod.json b/fabric-loot-api-v3/src/testmod/resources/fabric.mod.json similarity index 63% rename from fabric-loot-api-v2/src/testmod/resources/fabric.mod.json rename to fabric-loot-api-v3/src/testmod/resources/fabric.mod.json index 1057a5106..91f69500b 100644 --- a/fabric-loot-api-v2/src/testmod/resources/fabric.mod.json +++ b/fabric-loot-api-v3/src/testmod/resources/fabric.mod.json @@ -1,12 +1,12 @@ { "schemaVersion": 1, - "id": "fabric-loot-api-v2-testmod", - "name": "Fabric Loot Table API (v2) Test Mod", + "id": "fabric-loot-api-v3-testmod", + "name": "Fabric Loot Table API (v3) Test Mod", "version": "1.0.0", "environment": "*", "license": "Apache-2.0", "depends": { - "fabric-loot-api-v2": "*" + "fabric-loot-api-v3": "*" }, "entrypoints": { "main": [ diff --git a/gradle.properties b/gradle.properties index a39525177..a128b3685 100644 --- a/gradle.properties +++ b/gradle.properties @@ -36,6 +36,7 @@ fabric-key-binding-api-v1-version=1.0.47 fabric-keybindings-v0-version=0.2.45 fabric-lifecycle-events-v1-version=2.3.11 fabric-loot-api-v2-version=3.0.11 +fabric-loot-api-v3-version=1.0.0 fabric-message-api-v1-version=6.0.13 fabric-model-loading-api-v1-version=2.0.0 fabric-networking-api-v1-version=4.2.0 diff --git a/settings.gradle b/settings.gradle index cef611adc..30f7ff72c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -37,7 +37,7 @@ include 'fabric-item-api-v1' include 'fabric-item-group-api-v1' include 'fabric-key-binding-api-v1' include 'fabric-lifecycle-events-v1' -include 'fabric-loot-api-v2' +include 'fabric-loot-api-v3' include 'fabric-message-api-v1' include 'fabric-model-loading-api-v1' include 'fabric-networking-api-v1' @@ -62,6 +62,7 @@ include 'deprecated:fabric-command-api-v1' include 'deprecated:fabric-commands-v0' include 'deprecated:fabric-convention-tags-v1' include 'deprecated:fabric-keybindings-v0' +include 'deprecated:fabric-loot-api-v2' include 'deprecated:fabric-renderer-registries-v1' include 'deprecated:fabric-rendering-data-attachment-v1' include 'deprecated:fabric-rendering-v0'