From e74782790561f00ac1576f7b20ddc599088998db Mon Sep 17 00:00:00 2001 From: Juuxel <6596629+Juuxel@users.noreply.github.com> Date: Tue, 31 May 2022 14:12:10 +0300 Subject: [PATCH] Loot table API v2, iteration 2 (#1241) * Improve loot table API Alternative to #629. - Deprecates all classes and methods that use outdated Yarn names. - Adds FabricLootTable and FabricLootTableBuilder to replace the LootSupplier naming variants. - Deprecates LootEntryTypeRegistry and LootJsonParser as their functionality is exposed in vanilla now. - Adds methods to FabricLootPoolBuilder for working with collections as builder parameters. - FabricLootPool and FabricLootTable/Supplier now return immutable lists instead of modifiable fixed-size ones. Still WIP: LootTableLoadingCallback uses the deprecated FabricLootSupplier. Update fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootTableBuilder.java Co-authored-by: i509VCB Fix compilation Create loot table API v2 Move incorrect classes and revert unnecessary change Add test for replacing loot tables Document FabricLootPools builder() -> create() Add accessor for LootPool.bonusRolls Add loot pool builder method for bonus rolls Use Blocks.DIRT.getLootTableId() instead of raw string in v1 loot test mod Make links in deprecation docs cleaner Make FabricLootPoolBuilder.copyFrom(pool, true) also copy bonus rolls ...and mention it in the javadoc Remove copyFrom from v2 builders It seems like a maintainability mess if Mojang ever decides to extend loot tables, and the chosen boolean flags are arbitrary. It also doesn't really have use cases apart from the internal use in the copyOf methods, and even then users can replicate its functionality with the other API methods. Rename 'supplier' to 'table' in LootManagerMixin Add 'stable' lifecycle to loot-table-api-v2, deprecate v1 Add internal comment for implementors about updates Cancel all remaining callbacks when a loot table is replaced Remove unused shadowed logger from LootManagerMixin Migrate subproject versioning to new system Start the AW migration Update test mod * Use interface injection * Fix some issues * Remove outdated bonusRolls test from LootTest It's a vanilla feature now. * Create transitive access widener module * Replace LootTableLoadingCallback with two events * Use friendlier exception message * Add resource source tracking * Add loot table sources * Add resource pack source for DefaultResourcePack$1 (anon resource) * Add license header * Make FabricResource an internal API in resource loader * Remove my TAW module * Add loot table-related TAWs * Run CI * Fix LootUtil.determineSource giving null values * Clarify LootUtil comment * Rename loot-table-api => loot-api + minor comment changes * Add README * Fix mixin file name * Use ImmutableMap.Builder instead of HashMap.computeIfAbsent in loot event impl * Prefix accessor methods with fabric_ to prevent conflicts with loot v1 * Document mixins * Document mixins more extensively * Improve NRMMixin comments * Change weird wording in FabricResourceImpl * Minor updates - Support new built-in mod respack source - Fix ResourceMixin comment - Add more docs to LootTableEvents.MODIFY - Add package-info * Add license header --- fabric-loot-api-v2/README.md | 29 +++++ fabric-loot-api-v2/build.gradle | 7 ++ .../api/loot/v2/FabricLootPoolBuilder.java | 114 +++++++++++++++++ .../api/loot/v2/FabricLootTableBuilder.java | 94 ++++++++++++++ .../fabric/api/loot/v2/LootTableEvents.java | 109 ++++++++++++++++ .../fabric/api/loot/v2/LootTableSource.java | 63 ++++++++++ .../fabric/api/loot/v2/package-info.java | 35 ++++++ .../fabricmc/fabric/impl/loot/LootUtil.java | 57 +++++++++ .../fabric/mixin/loot/LootManagerMixin.java | 87 +++++++++++++ .../fabric/mixin/loot/LootPoolAccessor.java | 33 +++-- .../mixin/loot/LootPoolBuilderMixin.java | 93 ++++++++++++++ .../fabric/mixin/loot/LootTableAccessor.java | 21 ++-- .../mixin/loot/LootTableBuilderMixin.java | 76 ++++++++++++ .../assets/fabric-loot-api-v2/icon.png | Bin 0 -> 1579 bytes .../resources/fabric-loot-api-v2.mixins.json | 15 +++ .../src/main/resources/fabric.mod.json | 34 +++++ .../fabricmc/fabric/test/loot/LootTest.java | 90 ++++++++++++++ .../loot_tables/blocks/red_wool.json | 19 +++ .../src/testmod/resources/fabric.mod.json | 16 +++ fabric-loot-tables-v1/build.gradle | 7 +- .../fabric/api/loot/v1/FabricLootPool.java | 5 +- .../api/loot/v1/FabricLootPoolBuilder.java | 28 +++-- .../api/loot/v1/FabricLootSupplier.java | 9 +- .../loot/v1/FabricLootSupplierBuilder.java | 24 ++-- .../api/loot/v1/LootEntryTypeRegistry.java | 4 +- .../fabric/api/loot/v1/LootJsonParser.java | 27 ++-- .../v1/event/LootTableLoadingCallback.java | 4 + .../loot/table/BufferingLootTableBuilder.java | 116 ++++++++++++++++++ .../loot/table/LootEntryTypeRegistryImpl.java | 6 +- .../impl/loot/table/LootTablesV1Init.java | 67 ++++++++++ .../mixin/loot/table/MixinLootManager.java | 60 --------- .../mixin/loot/table/MixinLootPool.java | 26 ++-- .../mixin/loot/table/MixinLootSupplier.java | 17 +-- .../fabric-loot-tables-v1.mixins.json | 4 - .../src/main/resources/fabric.mod.json | 8 +- .../loot/{LootTest.java => LootV1Test.java} | 20 ++- .../src/testmod/resources/fabric.mod.json | 2 +- .../impl/resource/loader/FabricResource.java | 41 +++++++ .../resource/loader/FabricResourceImpl.java | 29 +++++ .../resource/loader/GroupResourcePack.java | 4 +- .../loader/ResourcePackSourceTracker.java | 56 +++++++++ .../DefaultResourcePackResourceMixin.java | 36 ++++++ .../loader/NamespaceResourceManagerMixin.java | 31 +++++ .../resource/loader/ResourceImplMixin.java | 50 ++++++++ .../mixin/resource/loader/ResourceMixin.java | 19 ++- .../loader/ResourcePackProfileMixin.java | 49 ++++++++ .../fabric-resource-loader-v0.mixins.json | 4 + ...ransitive-access-wideners-v1.accesswidener | 9 ++ .../template.accesswidener | 9 ++ gradle.properties | 1 + settings.gradle | 1 + 51 files changed, 1590 insertions(+), 175 deletions(-) create mode 100644 fabric-loot-api-v2/README.md create mode 100644 fabric-loot-api-v2/build.gradle create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/package-info.java create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootManagerMixin.java rename fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolBuilderHooks.java => fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java (57%) create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java rename fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootSupplierBuilderHooks.java => fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java (66%) create mode 100644 fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java create mode 100644 fabric-loot-api-v2/src/main/resources/assets/fabric-loot-api-v2/icon.png create mode 100644 fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json create mode 100644 fabric-loot-api-v2/src/main/resources/fabric.mod.json create mode 100644 fabric-loot-api-v2/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java create mode 100644 fabric-loot-api-v2/src/testmod/resources/data/minecraft/loot_tables/blocks/red_wool.json create mode 100644 fabric-loot-api-v2/src/testmod/resources/fabric.mod.json create mode 100644 fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/BufferingLootTableBuilder.java create mode 100644 fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootTablesV1Init.java delete mode 100644 fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootManager.java rename fabric-loot-tables-v1/src/testmod/java/net/fabricmc/fabric/test/loot/{LootTest.java => LootV1Test.java} (83%) create mode 100644 fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResource.java create mode 100644 fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResourceImpl.java create mode 100644 fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ResourcePackSourceTracker.java create mode 100644 fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/DefaultResourcePackResourceMixin.java create mode 100644 fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceImplMixin.java rename fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolEntryTypesAccessor.java => fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceMixin.java (54%) create mode 100644 fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourcePackProfileMixin.java diff --git a/fabric-loot-api-v2/README.md b/fabric-loot-api-v2/README.md new file mode 100644 index 000000000..6003689ef --- /dev/null +++ b/fabric-loot-api-v2/README.md @@ -0,0 +1,29 @@ +# Fabric Loot API (v2) + +This module includes APIs for modifying and creating loot tables. + +## [Loot table events](src/main/java/net/fabricmc/fabric/api/loot/v2/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/v2/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/v2/FabricLootTableBuilder.java) +and [`FabricLootPoolBuilder`](src/main/java/net/fabricmc/fabric/api/loot/v2/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-v2/build.gradle new file mode 100644 index 000000000..5bda00956 --- /dev/null +++ b/fabric-loot-api-v2/build.gradle @@ -0,0 +1,7 @@ +archivesBaseName = "fabric-loot-api-v2" +version = getSubprojectVersion(project) + +moduleDependencies(project, [ + 'fabric-api-base', + 'fabric-resource-loader-v0' +]) diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java new file mode 100644 index 000000000..90d3db90d --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootPoolBuilder.java @@ -0,0 +1,114 @@ +/* + * 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.List; + +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; + +import net.fabricmc.fabric.mixin.loot.LootPoolAccessor; + +/** + * Convenience extensions to {@link LootPool.Builder} + * for adding pre-built objects or collections. + * + *

This interface is automatically injected to {@link LootPool.Builder}. + */ +@ApiStatus.NonExtendable +public interface FabricLootPoolBuilder { + /** + * Adds an entry to this builder. + * + * @param entry the added loot entry + * @return this builder + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + static LootPool.Builder copyOf(LootPool pool) { + LootPoolAccessor accessor = (LootPoolAccessor) pool; + return LootPool.builder() + .rolls(accessor.fabric_getRolls()) + .bonusRolls(accessor.fabric_getBonusRolls()) + .with(List.of(accessor.fabric_getEntries())) + .conditionally(List.of(accessor.fabric_getConditions())) + .apply(List.of(accessor.fabric_getFunctions())); + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java new file mode 100644 index 000000000..62b743ee0 --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/FabricLootTableBuilder.java @@ -0,0 +1,94 @@ +/* + * 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.List; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.loot.LootPool; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.function.LootFunction; + +import net.fabricmc.fabric.mixin.loot.LootTableAccessor; + +/** + * Convenience extensions to {@link LootTable.Builder} + * for adding pre-built objects or collections. + * + *

This interface is automatically injected to {@link LootTable.Builder}. + */ +@ApiStatus.NonExtendable +public interface FabricLootTableBuilder { + /** + * Adds a loot pool to this builder. + * + * @param pool the added pool + * @return this builder + */ + 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 + */ + 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 + */ + 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 + */ + default LootTable.Builder apply(Collection functions) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + + /** + * Creates a builder copy of a loot table. + * + * @param table the loot table + * @return the copied builder + */ + static LootTable.Builder copyOf(LootTable table) { + LootTable.Builder builder = LootTable.builder(); + LootTableAccessor accessor = (LootTableAccessor) table; + + builder.type(table.getType()); + builder.pools(List.of(accessor.fabric_getPools())); + builder.apply(List.of(accessor.fabric_getFunctions())); + + return builder; + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java new file mode 100644 index 000000000..6e861058b --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableEvents.java @@ -0,0 +1,109 @@ +/* + * 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 org.jetbrains.annotations.Nullable; + +import net.minecraft.loot.LootManager; +import net.minecraft.loot.LootTable; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + +/** + * Events for manipulating loot tables. + */ +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. + */ + public static final Event REPLACE = EventFactory.createArrayBacked(Replace.class, listeners -> (resourceManager, lootManager, id, original, source) -> { + for (Replace listener : listeners) { + @Nullable LootTable replaced = listener.replaceLootTable(resourceManager, lootManager, id, original, source); + + 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

+ *
+	 * {@code
+	 * LootTableEvents.MODIFY.register((resourceManager, lootManager, id, tableBuilder, source) -> {
+	 *     // If the loot table is for the cobblestone block and it is not overridden by a user:
+	 *     if (Blocks.COBBLESTONE.getLootTableId().equals(id) && 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 -> (resourceManager, lootManager, id, tableBuilder, source) -> { + for (Modify listener : listeners) { + listener.modifyLootTable(resourceManager, lootManager, id, tableBuilder, source); + } + }); + + public interface Replace { + /** + * Replaces loot tables. + * + * @param resourceManager the server resource manager + * @param lootManager the loot manager + * @param id the loot table ID + * @param original the original loot table + * @param source the source of the original loot table + * @return the new loot table, or null if it wasn't replaced + */ + @Nullable + LootTable replaceLootTable(ResourceManager resourceManager, LootManager lootManager, Identifier id, LootTable original, LootTableSource source); + } + + public interface Modify { + /** + * Called when a loot table is loading to modify loot tables. + * + * @param resourceManager the server resource manager + * @param lootManager the loot manager + * @param id the loot table ID + * @param tableBuilder a builder of the loot table being loaded + * @param source the source of the loot table + */ + void modifyLootTable(ResourceManager resourceManager, LootManager lootManager, Identifier id, LootTable.Builder tableBuilder, LootTableSource source); + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java new file mode 100644 index 000000000..c2b48a4d8 --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/LootTableSource.java @@ -0,0 +1,63 @@ +/* + * 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. + */ +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/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/package-info.java new file mode 100644 index 000000000..c1cd4106c --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/api/loot/v2/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.v2.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.v2.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.v2.FabricLootTableBuilder loot table} and + * {@linkplain net.fabricmc.fabric.api.loot.v2.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.v2; diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java new file mode 100644 index 000000000..05013020f --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/impl/loot/LootUtil.java @@ -0,0 +1,57 @@ +/* + * 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; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourcePackSource; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.loot.v2.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; + +public final class LootUtil { + public static final Logger LOGGER = LoggerFactory.getLogger("fabric-loot-api-v2"); + + public static LootTableSource determineSource(Identifier lootTableId, ResourceManager resourceManager) { + Identifier resourceId = new Identifier(lootTableId.getNamespace(), "loot_tables/%s.json".formatted(lootTableId.getPath())); + + try (Resource resource = resourceManager.getResource(resourceId)) { + ResourcePackSource packSource = ((FabricResource) resource).getFabricPackSource(); + + if (packSource == ResourcePackSource.PACK_SOURCE_BUILTIN) { + return LootTableSource.VANILLA; + } else if (packSource == ModResourcePackCreator.RESOURCE_PACK_SOURCE || packSource instanceof BuiltinModResourcePackSource) { + return LootTableSource.MOD; + } + } catch (IOException e) { + LOGGER.error("Could not open resource for loot table {} to check its source", lootTableId, e); + } + + // If not builtin or mod, assume external data pack. + // It might also be a virtual loot table injected via mixin instead of being loaded + // from a resource, but we can't determine that here. + return LootTableSource.DATA_PACK; + } +} diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootManagerMixin.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootManagerMixin.java new file mode 100644 index 000000000..10dc732c4 --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootManagerMixin.java @@ -0,0 +1,87 @@ +/* + * 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.Map; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.loot.LootManager; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.LootTables; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; + +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(LootManager.class) +abstract class LootManagerMixin { + @Shadow + private Map tables; + + @Inject(method = "apply", at = @At("RETURN")) + private void apply(Map jsonMap, ResourceManager resourceManager, Profiler profiler, CallbackInfo info) { + // The builder for the new LootManager.tables map with modified loot tables. + // We're using an immutable map to match vanilla. + ImmutableMap.Builder newTables = ImmutableMap.builder(); + + tables.forEach((id, table) -> { + if (id.equals(LootTables.EMPTY)) { + // This is a special table and cannot be modified. + // Vanilla also warns about that. + return; + } + + // noinspection ConstantConditions + LootManager lootManager = (LootManager) (Object) this; + LootTableSource source = LootUtil.determineSource(id, resourceManager); + + // Invoke the REPLACE event for the current loot table. + LootTable replacement = LootTableEvents.REPLACE.invoker().replaceLootTable(resourceManager, lootManager, id, 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(resourceManager, lootManager, id, builder, source); + + // Turn the builder back into a loot table and store it in the new table. + newTables.put(id, builder.build()); + }); + + // Finally, store the new loot table map in the field. + tables = newTables.build(); + } +} diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolBuilderHooks.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java similarity index 57% rename from fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolBuilderHooks.java rename to fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java index 30085cec3..dc7841e11 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolBuilderHooks.java +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolAccessor.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.mixin.loot.table; - -import java.util.List; +package net.fabricmc.fabric.mixin.loot; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -25,13 +23,26 @@ import net.minecraft.loot.LootPool; import net.minecraft.loot.condition.LootCondition; import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.function.LootFunction; +import net.minecraft.loot.provider.number.LootNumberProvider; -@Mixin(LootPool.Builder.class) -public interface LootPoolBuilderHooks { - @Accessor - List getEntries(); - @Accessor - List getConditions(); - @Accessor - List getFunctions(); +/** + * Accesses loot pool fields for {@link net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder#copyOf(LootPool)}. + * These are normally available in the transitive access widener module. + */ +@Mixin(LootPool.class) +public interface LootPoolAccessor { + @Accessor("rolls") + LootNumberProvider fabric_getRolls(); + + @Accessor("bonusRolls") + LootNumberProvider fabric_getBonusRolls(); + + @Accessor("entries") + LootPoolEntry[] fabric_getEntries(); + + @Accessor("conditions") + LootCondition[] fabric_getConditions(); + + @Accessor("functions") + LootFunction[] fabric_getFunctions(); } diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java new file mode 100644 index 000000000..d1124fac8 --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootPoolBuilderMixin.java @@ -0,0 +1,93 @@ +/* + * 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.Collection; +import java.util.List; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import net.minecraft.loot.LootPool; +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; + +/** + * The implementation of the injected interface {@link FabricLootPoolBuilder}. + * Simply implements the new methods by adding the relevant objects inside the lists. + */ +@Mixin(LootPool.Builder.class) +abstract class LootPoolBuilderMixin implements FabricLootPoolBuilder { + @Shadow + @Final + private List entries; + + @Shadow + @Final + private List conditions; + + @Shadow + @Final + private List functions; + + @Unique + private LootPool.Builder self() { + // noinspection ConstantConditions + return (LootPool.Builder) (Object) this; + } + + @Override + public LootPool.Builder with(LootPoolEntry entry) { + this.entries.add(entry); + return self(); + } + + @Override + public LootPool.Builder with(Collection entries) { + this.entries.addAll(entries); + return self(); + } + + @Override + public LootPool.Builder conditionally(LootCondition condition) { + this.conditions.add(condition); + return self(); + } + + @Override + public LootPool.Builder conditionally(Collection conditions) { + this.conditions.addAll(conditions); + return self(); + } + + @Override + public LootPool.Builder apply(LootFunction function) { + this.functions.add(function); + return self(); + } + + @Override + public LootPool.Builder apply(Collection functions) { + this.functions.addAll(functions); + return self(); + } +} diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootSupplierBuilderHooks.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java similarity index 66% rename from fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootSupplierBuilderHooks.java rename to fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java index ad07efbcb..b9d8c95c4 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootSupplierBuilderHooks.java +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableAccessor.java @@ -14,9 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.mixin.loot.table; - -import java.util.List; +package net.fabricmc.fabric.mixin.loot; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -25,10 +23,15 @@ import net.minecraft.loot.LootPool; import net.minecraft.loot.LootTable; import net.minecraft.loot.function.LootFunction; -@Mixin(LootTable.Builder.class) -public interface LootSupplierBuilderHooks { - @Accessor - List getPools(); - @Accessor - List getFunctions(); +/** + * Accesses loot table fields for {@link net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder#copyOf(LootTable)}. + * These are normally available in the transitive access widener module. + */ +@Mixin(LootTable.class) +public interface LootTableAccessor { + @Accessor("pools") + LootPool[] fabric_getPools(); + + @Accessor("functions") + LootFunction[] fabric_getFunctions(); } diff --git a/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java new file mode 100644 index 000000000..f4f60e37b --- /dev/null +++ b/fabric-loot-api-v2/src/main/java/net/fabricmc/fabric/mixin/loot/LootTableBuilderMixin.java @@ -0,0 +1,76 @@ +/* + * 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.Collection; +import java.util.List; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +import net.minecraft.loot.LootPool; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.function.LootFunction; + +import net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder; + +/** + * The implementation of the injected interface {@link FabricLootTableBuilder}. + * Simply implements the new methods by adding the relevant objects inside the lists. + */ +@Mixin(LootTable.Builder.class) +abstract class LootTableBuilderMixin implements FabricLootTableBuilder { + @Shadow + @Final + private List pools; + + @Shadow + @Final + private List functions; + + @Unique + private LootTable.Builder self() { + // noinspection ConstantConditions + return (LootTable.Builder) (Object) this; + } + + @Override + public LootTable.Builder pool(LootPool pool) { + this.pools.add(pool); + return self(); + } + + @Override + public LootTable.Builder apply(LootFunction function) { + this.functions.add(function); + return self(); + } + + @Override + public LootTable.Builder pools(Collection pools) { + this.pools.addAll(pools); + return self(); + } + + @Override + public LootTable.Builder apply(Collection functions) { + this.functions.addAll(functions); + return self(); + } +} diff --git a/fabric-loot-api-v2/src/main/resources/assets/fabric-loot-api-v2/icon.png b/fabric-loot-api-v2/src/main/resources/assets/fabric-loot-api-v2/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2931efbf610873c0084debb8690902b0103d27fe GIT binary patch literal 1579 zcmbVMTWB0r7@iGm)TAXsYw<=rnU=;v=W=GRbL=!tc4Brl6GO7t2vVJ$IlDV#XU;e? z+r2ymsZdMQqAyaFLLUo;RumtE8Z@?uf_*4nP^4;o6fOFoSkN+o1$K?f2nE9_*b5G-l)AV)k5Qhb^- zU{V4ZnTKgnmXdpcB*Kg!W(1hvM2N&RO30x1u~eI9meGQGe@_?PDQq%q1CiV$8~M7 z?MQ_mOdqCh^a65Sv|ntwSXjV5se1;VK1|Kr8G7TQoQL&*ctt{L{fClG}xPK5k^yK3%T69N6J=>3jBqc zDNvZsrJ-yOXI^^mWf1cmY^XST)CVzIGjvEPENowmy}ax zvJ8_(Cf#+H-dBlH53`_u-~6BVAMz|(g?jCVdBWNZ(+A}(pFV7>S3QgPiQcMaflkIC z-3Ti|VT~{au*vq0ts9O&m$p&Gl=L6+q6_m$IcVq}o~+Pl{g>1esQp4%wp~|*zk1n` zZ7T6Toc4`y88s}riCP|ZXrJ?FLz@^KTcyqLjey zu95Yz%F&S{<0~f)Iomek?+hQ%MhCu%T^zsg>C_L`1`Br`xNY&))k9yTQb$JC>)w_f zpU(^tu^Q)y%W~lVz`jz;_ jF?g&s@Y=Qe&c#kW|JbvqK0Y=Rw)4XDoVqsk_>;c_`@;F@ literal 0 HcmV?d00001 diff --git a/fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json b/fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json new file mode 100644 index 000000000..c70ccf809 --- /dev/null +++ b/fabric-loot-api-v2/src/main/resources/fabric-loot-api-v2.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.mixin.loot", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "LootManagerMixin", + "LootPoolAccessor", + "LootPoolBuilderMixin", + "LootTableAccessor", + "LootTableBuilderMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric-loot-api-v2/src/main/resources/fabric.mod.json b/fabric-loot-api-v2/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..6d73a269f --- /dev/null +++ b/fabric-loot-api-v2/src/main/resources/fabric.mod.json @@ -0,0 +1,34 @@ +{ + "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.4.0", + "fabric-api-base": "*", + "fabric-resource-loader-v0": "*" + }, + "description": "Hooks for manipulating loot tables.", + "mixins": [ + "fabric-loot-api-v2.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"] + } + } +} diff --git a/fabric-loot-api-v2/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java b/fabric-loot-api-v2/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java new file mode 100644 index 000000000..fa916ceef --- /dev/null +++ b/fabric-loot-api-v2/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java @@ -0,0 +1,90 @@ +/* + * 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.test.loot; + +import net.minecraft.block.Blocks; +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.SetNameLootFunction; +import net.minecraft.text.LiteralText; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.loot.v2.LootTableEvents; +import net.fabricmc.fabric.api.loot.v2.LootTableSource; + +public class LootTest implements ModInitializer { + @Override + public void onInitialize() { + // 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((resourceManager, lootManager, id, original, source) -> { + if (Blocks.BLACK_WOOL.getLootTableId().equals(id)) { + if (source != LootTableSource.VANILLA) { + throw new AssertionError("black wool loot table should have LootTableSource.VANILLA"); + } + + // Replace black wool drops with an iron ingot + LootPool pool = LootPool.builder() + .with(ItemEntry.builder(Items.IRON_INGOT).build()) + .build(); + + return LootTable.builder().pool(pool).build(); + } + + return null; + }); + + // Test that the event is stopped when the loot table is replaced + LootTableEvents.REPLACE.register((resourceManager, lootManager, id, original, source) -> { + if (Blocks.BLACK_WOOL.getLootTableId().equals(id)) { + throw new AssertionError("Event should have been stopped from replaced loot table"); + } + + return null; + }); + + LootTableEvents.MODIFY.register((resourceManager, lootManager, id, tableBuilder, source) -> { + if (Blocks.BLACK_WOOL.getLootTableId().equals(id) && source != LootTableSource.REPLACED) { + throw new AssertionError("black wool loot table should have LootTableSource.REPLACED"); + } + + if (Blocks.WHITE_WOOL.getLootTableId().equals(id)) { + if (source != LootTableSource.VANILLA) { + throw new AssertionError("white wool loot table should have LootTableSource.VANILLA"); + } + + // Add gold ingot with custom name to white wool drops + LootPool pool = LootPool.builder() + .with(ItemEntry.builder(Items.GOLD_INGOT).build()) + .conditionally(SurvivesExplosionLootCondition.builder().build()) + .apply(SetNameLootFunction.builder(new LiteralText("Gold from White Wool")).build()) + .build(); + + tableBuilder.pool(pool); + } + + // We modify red wool to drop diamonds in the test mod resources. + if (Blocks.RED_WOOL.getLootTableId().equals(id) && source != LootTableSource.MOD) { + throw new AssertionError("red wool loot table should have LootTableSource.MOD"); + } + }); + } +} diff --git a/fabric-loot-api-v2/src/testmod/resources/data/minecraft/loot_tables/blocks/red_wool.json b/fabric-loot-api-v2/src/testmod/resources/data/minecraft/loot_tables/blocks/red_wool.json new file mode 100644 index 000000000..33e614e16 --- /dev/null +++ b/fabric-loot-api-v2/src/testmod/resources/data/minecraft/loot_tables/blocks/red_wool.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:diamond" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} diff --git a/fabric-loot-api-v2/src/testmod/resources/fabric.mod.json b/fabric-loot-api-v2/src/testmod/resources/fabric.mod.json new file mode 100644 index 000000000..1057a5106 --- /dev/null +++ b/fabric-loot-api-v2/src/testmod/resources/fabric.mod.json @@ -0,0 +1,16 @@ +{ + "schemaVersion": 1, + "id": "fabric-loot-api-v2-testmod", + "name": "Fabric Loot Table API (v2) Test Mod", + "version": "1.0.0", + "environment": "*", + "license": "Apache-2.0", + "depends": { + "fabric-loot-api-v2": "*" + }, + "entrypoints": { + "main": [ + "net.fabricmc.fabric.test.loot.LootTest" + ] + } +} diff --git a/fabric-loot-tables-v1/build.gradle b/fabric-loot-tables-v1/build.gradle index 9303f46c4..f9a445261 100644 --- a/fabric-loot-tables-v1/build.gradle +++ b/fabric-loot-tables-v1/build.gradle @@ -2,5 +2,10 @@ archivesBaseName = "fabric-loot-tables-v1" version = getSubprojectVersion(project) moduleDependencies(project, [ - 'fabric-api-base' + 'fabric-api-base', + 'fabric-loot-api-v2' ]) + +dependencies { + testmodRuntimeOnly(project(path: ':fabric-resource-loader-v0', configuration: 'namedElements')) +} diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPool.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPool.java index 3cb664229..e310bdb03 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPool.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPool.java @@ -19,15 +19,18 @@ package net.fabricmc.fabric.api.loot.v1; import java.util.List; import net.minecraft.loot.LootPool; -import net.minecraft.loot.provider.number.LootNumberProvider; import net.minecraft.loot.condition.LootCondition; import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.function.LootFunction; +import net.minecraft.loot.provider.number.LootNumberProvider; /** * An interface implemented by all {@code net.minecraft.loot.LootPool} instances when * Fabric API is present. Contains accessors for various fields. + * + * @deprecated Replaced with transitive access wideners in Fabric Transitive Access Wideners (v1). */ +@Deprecated public interface FabricLootPool { default LootPool asVanilla() { return (LootPool) this; diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPoolBuilder.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPoolBuilder.java index 81744e41c..7f85a0baa 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPoolBuilder.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootPoolBuilder.java @@ -22,17 +22,21 @@ import net.minecraft.loot.provider.number.LootNumberProvider; import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.function.LootFunction; -import net.fabricmc.fabric.mixin.loot.table.LootPoolBuilderHooks; - +/** + * @deprecated Replaced with {@link net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder}. + */ +@Deprecated public class FabricLootPoolBuilder extends LootPool.Builder { - private final LootPoolBuilderHooks extended = (LootPoolBuilderHooks) this; - private FabricLootPoolBuilder() { } private FabricLootPoolBuilder(LootPool pool) { copyFrom(pool, true); } + private net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder asV2() { + return (net.fabricmc.fabric.api.loot.v2.FabricLootPoolBuilder) this; + } + @Override public FabricLootPoolBuilder rolls(LootNumberProvider range) { super.rolls(range); @@ -58,17 +62,17 @@ public class FabricLootPoolBuilder extends LootPool.Builder { } public FabricLootPoolBuilder withEntry(LootPoolEntry entry) { - extended.getEntries().add(entry); + asV2().with(entry); return this; } public FabricLootPoolBuilder withCondition(LootCondition condition) { - extended.getConditions().add(condition); + asV2().conditionally(condition); return this; } public FabricLootPoolBuilder withFunction(LootFunction function) { - extended.getFunctions().add(function); + asV2().apply(function); return this; } @@ -89,13 +93,13 @@ public class FabricLootPoolBuilder extends LootPool.Builder { *

If {@code copyRolls} is true, the {@link FabricLootPool#getRolls rolls} of the pool are also copied. */ public FabricLootPoolBuilder copyFrom(LootPool pool, boolean copyRolls) { - FabricLootPool extendedPool = (FabricLootPool) pool; - extended.getConditions().addAll(extendedPool.getConditions()); - extended.getFunctions().addAll(extendedPool.getFunctions()); - extended.getEntries().addAll(extendedPool.getEntries()); + FabricLootPool extended = (FabricLootPool) pool; + asV2().with(extended.getEntries()); + asV2().conditionally(extended.getConditions()); + asV2().apply(extended.getFunctions()); if (copyRolls) { - rolls(extendedPool.getRolls()); + rolls(extended.getRolls()); } return this; diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplier.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplier.java index d3188e0c4..4890d1cc0 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplier.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplier.java @@ -24,9 +24,12 @@ import net.minecraft.loot.context.LootContextType; import net.minecraft.loot.function.LootFunction; /** - * An interface implemented by all {@code net.minecraft.loot.LootSupplier} instances when + * An interface implemented by all {@link LootTable} instances when * Fabric API is present. Contains accessors for various fields. + * + * @deprecated Replaced with transitive access wideners in Fabric Transitive Access Wideners (v1). */ +@Deprecated public interface FabricLootSupplier { default LootTable asVanilla() { return (LootTable) this; @@ -34,5 +37,7 @@ public interface FabricLootSupplier { List getPools(); List getFunctions(); - LootContextType getType(); + default LootContextType getType() { + return asVanilla().getType(); // Vanilla has this now + } } diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplierBuilder.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplierBuilder.java index 56d2971a8..657ce56a2 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplierBuilder.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/FabricLootSupplierBuilder.java @@ -23,17 +23,23 @@ import net.minecraft.loot.LootTable; import net.minecraft.loot.context.LootContextType; import net.minecraft.loot.function.LootFunction; -import net.fabricmc.fabric.mixin.loot.table.LootSupplierBuilderHooks; +import net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder; +/** + * @deprecated Replaced with {@link FabricLootTableBuilder}. + */ +@Deprecated public class FabricLootSupplierBuilder extends LootTable.Builder { - private final LootSupplierBuilderHooks extended = (LootSupplierBuilderHooks) this; - protected FabricLootSupplierBuilder() { } private FabricLootSupplierBuilder(LootTable supplier) { copyFrom(supplier, true); } + private FabricLootTableBuilder asV2() { + return (FabricLootTableBuilder) this; + } + @Override public FabricLootSupplierBuilder pool(LootPool.Builder pool) { super.pool(pool); @@ -53,22 +59,22 @@ public class FabricLootSupplierBuilder extends LootTable.Builder { } public FabricLootSupplierBuilder withPool(LootPool pool) { - extended.getPools().add(pool); + asV2().pool(pool); return this; } public FabricLootSupplierBuilder withFunction(LootFunction function) { - extended.getFunctions().add(function); + asV2().apply(function); return this; } public FabricLootSupplierBuilder withPools(Collection pools) { - pools.forEach(this::withPool); + asV2().pools(pools); return this; } public FabricLootSupplierBuilder withFunctions(Collection functions) { - functions.forEach(this::withFunction); + asV2().apply(functions); return this; } @@ -86,8 +92,8 @@ public class FabricLootSupplierBuilder extends LootTable.Builder { */ public FabricLootSupplierBuilder copyFrom(LootTable supplier, boolean copyType) { FabricLootSupplier extendedSupplier = (FabricLootSupplier) supplier; - extended.getPools().addAll(extendedSupplier.getPools()); - extended.getFunctions().addAll(extendedSupplier.getFunctions()); + asV2().pools(extendedSupplier.getPools()); + asV2().apply(extendedSupplier.getFunctions()); if (copyType) { type(extendedSupplier.getType()); diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootEntryTypeRegistry.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootEntryTypeRegistry.java index c3077123e..c2ad6a0a5 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootEntryTypeRegistry.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootEntryTypeRegistry.java @@ -23,11 +23,13 @@ import net.minecraft.util.JsonSerializer; import net.fabricmc.fabric.impl.loot.table.LootEntryTypeRegistryImpl; /** - * Fabric's extensions to {@code net.minecraft.loot.entry.LootEntries} for registering + * Fabric's extensions to {@link net.minecraft.loot.entry.LootPoolEntryTypes} for registering * custom loot entry types. * * @see #register + * @deprecated Use {@link net.minecraft.util.registry.Registry#LOOT_POOL_ENTRY_TYPE} from vanilla instead. */ +@Deprecated public interface LootEntryTypeRegistry { LootEntryTypeRegistry INSTANCE = new LootEntryTypeRegistryImpl(); diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootJsonParser.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootJsonParser.java index 5ecb06322..86246980e 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootJsonParser.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/LootJsonParser.java @@ -17,37 +17,26 @@ package net.fabricmc.fabric.api.loot.v1; import java.io.Reader; -import java.lang.reflect.Field; -import java.util.stream.Stream; import com.google.gson.Gson; +import net.minecraft.loot.LootGsons; import net.minecraft.util.JsonHelper; -import net.minecraft.util.Lazy; -import net.minecraft.loot.LootManager; +/** + * @deprecated Use {@link LootGsons#getTableGsonBuilder()} from vanilla instead. + */ +@Deprecated public final class LootJsonParser { - /* Reading this from LootManager to access all serializers from vanilla. */ - private static final Lazy GSON = new Lazy<>(() -> { - try { - Field gsonField = Stream.of(LootManager.class.getDeclaredFields()) - .filter(field -> field.getType() == Gson.class) - .findFirst() - .orElseThrow(() -> new RuntimeException("Gson not found in LootManager!")); - gsonField.setAccessible(true); - return (Gson) gsonField.get(null); - } catch (Exception e) { - throw new RuntimeException("Exception while getting Gson instance from LootManager", e); - } - }); + private static final Gson GSON = LootGsons.getTableGsonBuilder().create(); private LootJsonParser() { } public static T read(Reader json, Class c) { - return JsonHelper.deserialize(GSON.get(), json, c); + return JsonHelper.deserialize(GSON, json, c); } public static T read(String json, Class c) { - return JsonHelper.deserialize(GSON.get(), json, c); + return JsonHelper.deserialize(GSON, json, c); } } diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/event/LootTableLoadingCallback.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/event/LootTableLoadingCallback.java index 360efd54a..764c94ada 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/event/LootTableLoadingCallback.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/api/loot/v1/event/LootTableLoadingCallback.java @@ -28,9 +28,13 @@ import net.fabricmc.fabric.api.loot.v1.FabricLootSupplierBuilder; /** * An event handler that is called when loot tables are loaded. * Use {@link #EVENT} to register instances. + * + * @deprecated Replaced with {@link net.fabricmc.fabric.api.loot.v2.LootTableEvents}. */ +@Deprecated @FunctionalInterface public interface LootTableLoadingCallback { + @Deprecated @FunctionalInterface interface LootTableSetter { void set(LootTable supplier); diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/BufferingLootTableBuilder.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/BufferingLootTableBuilder.java new file mode 100644 index 000000000..3e6ddd659 --- /dev/null +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/BufferingLootTableBuilder.java @@ -0,0 +1,116 @@ +/* + * 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.table; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; + +import net.minecraft.loot.LootPool; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.context.LootContextType; +import net.minecraft.loot.function.LootFunction; + +import net.fabricmc.fabric.api.loot.v1.FabricLootSupplier; +import net.fabricmc.fabric.api.loot.v1.FabricLootSupplierBuilder; +import net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder; + +/** + * A {@link FabricLootSupplierBuilder} that caches all methods so they can be applied to a v2 {@link FabricLootTableBuilder}. + * Used for hooking {@code LootTableLoadingCallback} to the two different {@link net.fabricmc.fabric.api.loot.v2.LootTableEvents}. + */ +public class BufferingLootTableBuilder extends FabricLootSupplierBuilder { + private final List> modifications = new ArrayList<>(); + + private FabricLootSupplierBuilder addAction(Consumer action) { + modifications.add(action); + return this; + } + + private FabricLootSupplierBuilder addV2Action(Consumer action) { + return addAction(builder -> action.accept((FabricLootTableBuilder) builder)); + } + + @Override + public FabricLootSupplierBuilder pool(LootPool.Builder pool) { + super.pool(pool); + return addAction(builder -> builder.pool(pool)); + } + + @Override + public FabricLootSupplierBuilder type(LootContextType type) { + super.type(type); + return addAction(builder -> builder.type(type)); + } + + @Override + public FabricLootSupplierBuilder apply(LootFunction.Builder function) { + super.apply(function); + return addAction(builder -> builder.apply(function)); + } + + @Override + public FabricLootSupplierBuilder withPool(LootPool pool) { + super.withPool(pool); + return addV2Action(builder -> builder.pool(pool)); + } + + @Override + public FabricLootSupplierBuilder withFunction(LootFunction function) { + super.withFunction(function); + return addV2Action(builder -> builder.apply(function)); + } + + @Override + public FabricLootSupplierBuilder withPools(Collection pools) { + super.withPools(pools); + return addV2Action(builder -> builder.pools(pools)); + } + + @Override + public FabricLootSupplierBuilder withFunctions(Collection functions) { + super.withFunctions(functions); + return addV2Action(builder -> builder.apply(functions)); + } + + @Override + public FabricLootSupplierBuilder copyFrom(LootTable supplier, boolean copyType) { + super.copyFrom(supplier, copyType); + return addV2Action(builder -> { + FabricLootSupplier extended = (FabricLootSupplier) supplier; + builder.pools(extended.getPools()); + builder.apply(extended.getFunctions()); + + if (copyType) { + ((LootTable.Builder) builder).type(supplier.getType()); + } + }); + } + + public void init(LootTable original) { + super.type(original.getType()); + super.withPools(((FabricLootSupplier) original).getPools()); + super.withFunctions(((FabricLootSupplier) original).getFunctions()); + } + + public void applyTo(LootTable.Builder builder) { + for (Consumer modification : modifications) { + modification.accept(builder); + } + } +} diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootEntryTypeRegistryImpl.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootEntryTypeRegistryImpl.java index e4594a3d3..af5effdfa 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootEntryTypeRegistryImpl.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootEntryTypeRegistryImpl.java @@ -17,16 +17,16 @@ package net.fabricmc.fabric.impl.loot.table; import net.minecraft.loot.entry.LootPoolEntry; +import net.minecraft.loot.entry.LootPoolEntryType; import net.minecraft.util.Identifier; import net.minecraft.util.JsonSerializer; - -import net.fabricmc.fabric.mixin.loot.table.LootPoolEntryTypesAccessor; +import net.minecraft.util.registry.Registry; public final class LootEntryTypeRegistryImpl implements net.fabricmc.fabric.api.loot.v1.LootEntryTypeRegistry { public LootEntryTypeRegistryImpl() { } @Override public void register(Identifier id, JsonSerializer serializer) { - LootPoolEntryTypesAccessor.register(id.toString(), serializer); + Registry.register(Registry.LOOT_POOL_ENTRY_TYPE, id, new LootPoolEntryType(serializer)); } } diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootTablesV1Init.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootTablesV1Init.java new file mode 100644 index 000000000..d8c262e2c --- /dev/null +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/impl/loot/table/LootTablesV1Init.java @@ -0,0 +1,67 @@ +/* + * 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.table; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.loot.LootTable; +import net.minecraft.util.Identifier; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback; +import net.fabricmc.fabric.api.loot.v2.LootTableEvents; + +public final class LootTablesV1Init implements ModInitializer { + private static final ThreadLocal> BUFFERS = ThreadLocal.withInitial(HashMap::new); + + @Override + public void onInitialize() { + LootTableEvents.REPLACE.register((resourceManager, lootManager, id, original, source) -> { + BufferingLootTableBuilder builder = new BufferingLootTableBuilder(); + builder.init(original); + BUFFERS.get().put(id, builder); + + LootTable[] result = new LootTable[1]; + LootTableLoadingCallback.EVENT.invoker().onLootTableLoading( + resourceManager, + lootManager, + id, + builder, + table -> result[0] = table + ); + + return result[0]; + }); + + LootTableEvents.MODIFY.register((resourceManager, lootManager, id, tableBuilder, source) -> { + Map buffers = BUFFERS.get(); + + if (buffers.containsKey(id)) { + try { + buffers.get(id).applyTo(tableBuilder); + } finally { + buffers.remove(id); + + if (buffers.isEmpty()) { + BUFFERS.remove(); + } + } + } + }); + } +} diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootManager.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootManager.java deleted file mode 100644 index 16881e34e..000000000 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootManager.java +++ /dev/null @@ -1,60 +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.table; - -import java.util.HashMap; -import java.util.Map; - -import com.google.common.collect.ImmutableMap; -import com.google.gson.JsonObject; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; -import net.minecraft.util.profiler.Profiler; -import net.minecraft.loot.LootManager; -import net.minecraft.loot.LootTable; - -import net.fabricmc.fabric.api.loot.v1.FabricLootSupplierBuilder; -import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback; - -@Mixin(LootManager.class) -public class MixinLootManager { - @Shadow private Map tables; - - @Inject(method = "apply", at = @At("RETURN")) - private void apply(Map objectMap, ResourceManager manager, Profiler profiler, CallbackInfo info) { - Map newSuppliers = new HashMap<>(); - - tables.forEach((id, supplier) -> { - FabricLootSupplierBuilder builder = FabricLootSupplierBuilder.of(supplier); - - //noinspection ConstantConditions - LootTableLoadingCallback.EVENT.invoker().onLootTableLoading( - manager, (LootManager) (Object) this, id, builder, (s) -> newSuppliers.put(id, s) - ); - - newSuppliers.computeIfAbsent(id, (i) -> builder.build()); - }); - - tables = ImmutableMap.copyOf(newSuppliers); - } -} diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootPool.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootPool.java index 1d58e9d69..055336395 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootPool.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootPool.java @@ -16,19 +16,18 @@ package net.fabricmc.fabric.mixin.loot.table; -import java.util.Arrays; import java.util.List; +import com.google.common.collect.ImmutableList; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.gen.Accessor; import net.minecraft.loot.LootPool; -import net.minecraft.loot.provider.number.LootNumberProvider; import net.minecraft.loot.condition.LootCondition; 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.v1.FabricLootPool; @@ -36,32 +35,37 @@ import net.fabricmc.fabric.api.loot.v1.FabricLootPool; public abstract class MixinLootPool implements FabricLootPool { @Shadow @Final - private LootPoolEntry[] entries; + LootPoolEntry[] entries; @Shadow @Final - private LootCondition[] conditions; + LootCondition[] conditions; @Shadow @Final - private LootFunction[] functions; + LootFunction[] functions; + + @Shadow + @Final + LootNumberProvider rolls; @Override public List getEntries() { - return Arrays.asList(entries); + return ImmutableList.copyOf(entries); } @Override public List getConditions() { - return Arrays.asList(conditions); + return ImmutableList.copyOf(conditions); } @Override public List getFunctions() { - return Arrays.asList(functions); + return ImmutableList.copyOf(functions); } - @Accessor @Override - public abstract LootNumberProvider getRolls(); + public LootNumberProvider getRolls() { + return rolls; + } } diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootSupplier.java b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootSupplier.java index 584994f4e..10cb2fa90 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootSupplier.java +++ b/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/MixinLootSupplier.java @@ -16,17 +16,15 @@ package net.fabricmc.fabric.mixin.loot.table; -import java.util.Arrays; import java.util.List; +import com.google.common.collect.ImmutableList; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.gen.Accessor; import net.minecraft.loot.LootPool; import net.minecraft.loot.LootTable; -import net.minecraft.loot.context.LootContextType; import net.minecraft.loot.function.LootFunction; import net.fabricmc.fabric.api.loot.v1.FabricLootSupplier; @@ -35,22 +33,19 @@ import net.fabricmc.fabric.api.loot.v1.FabricLootSupplier; public abstract class MixinLootSupplier implements FabricLootSupplier { @Shadow @Final - private LootPool[] pools; + LootPool[] pools; + @Shadow @Final - private LootFunction[] functions; + LootFunction[] functions; @Override public List getPools() { - return Arrays.asList(pools); + return ImmutableList.copyOf(pools); } @Override public List getFunctions() { - return Arrays.asList(functions); + return ImmutableList.copyOf(functions); } - - @Accessor - @Override - public abstract LootContextType getType(); } diff --git a/fabric-loot-tables-v1/src/main/resources/fabric-loot-tables-v1.mixins.json b/fabric-loot-tables-v1/src/main/resources/fabric-loot-tables-v1.mixins.json index 064f4c5bd..9b813056e 100644 --- a/fabric-loot-tables-v1/src/main/resources/fabric-loot-tables-v1.mixins.json +++ b/fabric-loot-tables-v1/src/main/resources/fabric-loot-tables-v1.mixins.json @@ -3,10 +3,6 @@ "package": "net.fabricmc.fabric.mixin.loot.table", "compatibilityLevel": "JAVA_16", "mixins": [ - "LootPoolBuilderHooks", - "LootPoolEntryTypesAccessor", - "LootSupplierBuilderHooks", - "MixinLootManager", "MixinLootPool", "MixinLootSupplier" ], diff --git a/fabric-loot-tables-v1/src/main/resources/fabric.mod.json b/fabric-loot-tables-v1/src/main/resources/fabric.mod.json index ecd00ec3c..453c93cd3 100644 --- a/fabric-loot-tables-v1/src/main/resources/fabric.mod.json +++ b/fabric-loot-tables-v1/src/main/resources/fabric.mod.json @@ -17,13 +17,17 @@ ], "depends": { "fabricloader": ">=0.4.0", - "fabric-api-base": "*" + "fabric-api-base": "*", + "fabric-loot-api-v2": "*" + }, + "entrypoints": { + "main": ["net.fabricmc.fabric.impl.loot.table.LootTablesV1Init"] }, "description": "Hooks for manipulating loot tables.", "mixins": [ "fabric-loot-tables-v1.mixins.json" ], "custom": { - "fabric-api:module-lifecycle": "stable" + "fabric-api:module-lifecycle": "deprecated" } } diff --git a/fabric-loot-tables-v1/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java b/fabric-loot-tables-v1/src/testmod/java/net/fabricmc/fabric/test/loot/LootV1Test.java similarity index 83% rename from fabric-loot-tables-v1/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java rename to fabric-loot-tables-v1/src/testmod/java/net/fabricmc/fabric/test/loot/LootV1Test.java index 945f43f1b..e87b06a37 100644 --- a/fabric-loot-tables-v1/src/testmod/java/net/fabricmc/fabric/test/loot/LootTest.java +++ b/fabric-loot-tables-v1/src/testmod/java/net/fabricmc/fabric/test/loot/LootV1Test.java @@ -20,28 +20,31 @@ import com.google.gson.Gson; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; -import org.slf4j.LoggerFactory; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import net.minecraft.block.Blocks; import net.minecraft.item.Items; -import net.minecraft.loot.provider.number.ConstantLootNumberProvider; import net.minecraft.loot.LootGsons; import net.minecraft.loot.LootPool; +import net.minecraft.loot.LootTable; import net.minecraft.loot.condition.LootCondition; import net.minecraft.loot.condition.SurvivesExplosionLootCondition; import net.minecraft.loot.entry.ItemEntry; import net.minecraft.loot.entry.LootPoolEntry; import net.minecraft.loot.entry.TagEntry; +import net.minecraft.loot.provider.number.ConstantLootNumberProvider; import net.minecraft.util.Identifier; import net.minecraft.util.JsonHelper; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.loot.v1.FabricLootPoolBuilder; +import net.fabricmc.fabric.api.loot.v1.FabricLootSupplierBuilder; import net.fabricmc.fabric.api.loot.v1.LootEntryTypeRegistry; import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback; -public class LootTest implements ModInitializer { - private static final Logger LOGGER = LoggerFactory.getLogger(LootTest.class); +public class LootV1Test implements ModInitializer { + private static final Logger LOGGER = LoggerFactory.getLogger(LootV1Test.class); private static final Gson LOOT_GSON = LootGsons.getTableGsonBuilder().create(); private static final String LOOT_ENTRY_JSON = "{\"type\":\"minecraft:item\",\"name\":\"minecraft:apple\"}"; @@ -53,7 +56,9 @@ public class LootTest implements ModInitializer { // Test loot table load event LootTableLoadingCallback.EVENT.register((resourceManager, manager, id, supplier, setter) -> { - if ("minecraft:blocks/dirt".equals(id.toString())) { + // Add feathers and apples to dirt (only one drops at the time since they're in the same pool), + // and replace grass block drops with wheat + if (Blocks.DIRT.getLootTableId().equals(id)) { LootPoolEntry entryFromString = LOOT_GSON.fromJson(LOOT_ENTRY_JSON, LootPoolEntry.class); LootPool pool = FabricLootPoolBuilder.builder() @@ -64,6 +69,11 @@ public class LootTest implements ModInitializer { .build(); supplier.withPool(pool); + } else if (Blocks.GRASS_BLOCK.getLootTableId().equals(id)) { + LootTable table = FabricLootSupplierBuilder.builder() + .pool(FabricLootPoolBuilder.builder().with(ItemEntry.builder(Items.WHEAT))) + .build(); + setter.set(table); } }); } diff --git a/fabric-loot-tables-v1/src/testmod/resources/fabric.mod.json b/fabric-loot-tables-v1/src/testmod/resources/fabric.mod.json index 46cf8eabc..4a2f37cfb 100644 --- a/fabric-loot-tables-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-loot-tables-v1/src/testmod/resources/fabric.mod.json @@ -10,7 +10,7 @@ }, "entrypoints": { "main": [ - "net.fabricmc.fabric.test.loot.LootTest" + "net.fabricmc.fabric.test.loot.LootV1Test" ] } } diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResource.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResource.java new file mode 100644 index 000000000..a937b11b9 --- /dev/null +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResource.java @@ -0,0 +1,41 @@ +/* + * 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.resource.loader; + +import org.slf4j.LoggerFactory; + +import net.minecraft.resource.ResourcePackSource; + +/** + * Extensions to {@link net.minecraft.resource.Resource}. + * Automatically implemented there via a mixin. + * Currently, this is only for use in other Fabric API modules. + */ +public interface FabricResource { + /** + * Gets the resource pack source of this resource. + * The source is used to separate vanilla/mod resources from user resources in Fabric API. + * + *

Custom {@link net.minecraft.resource.Resource} implementations should override this method. + * + * @return the resource pack source + */ + default ResourcePackSource getFabricPackSource() { + LoggerFactory.getLogger(FabricResource.class).error("Unknown Resource implementation {}, returning PACK_SOURCE_NONE as the source", getClass().getName()); + return ResourcePackSource.PACK_SOURCE_NONE; + } +} diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResourceImpl.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResourceImpl.java new file mode 100644 index 000000000..4efb25e1c --- /dev/null +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/FabricResourceImpl.java @@ -0,0 +1,29 @@ +/* + * 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.resource.loader; + +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourcePackSource; + +/** + * An extended version of {@link FabricResource} that supports + * setting the pack resource. Only for use from within this module. + * Note that not all resources are instances of this interface. + */ +public interface FabricResourceImpl extends Resource, FabricResource { + void setFabricPackSource(ResourcePackSource packSource); +} diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/GroupResourcePack.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/GroupResourcePack.java index bfb449b2c..877936f91 100644 --- a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/GroupResourcePack.java +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/GroupResourcePack.java @@ -130,7 +130,9 @@ public abstract class GroupResourcePack implements ResourcePack { for (ModResourcePack pack : packs) { if (pack.contains(manager.getType(), id)) { InputStream metadataInputStream = pack.contains(manager.getType(), metadataId) ? manager.fabric$accessor_open(metadataId, pack) : null; - resources.add(new ResourceImpl(pack.getName(), id, manager.fabric$accessor_open(id, pack), metadataInputStream)); + ResourceImpl resource = new ResourceImpl(pack.getName(), id, manager.fabric$accessor_open(id, pack), metadataInputStream); + ((FabricResourceImpl) resource).setFabricPackSource(ModResourcePackCreator.RESOURCE_PACK_SOURCE); + resources.add(resource); } } } diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ResourcePackSourceTracker.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ResourcePackSourceTracker.java new file mode 100644 index 000000000..87132ac74 --- /dev/null +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/impl/resource/loader/ResourcePackSourceTracker.java @@ -0,0 +1,56 @@ +/* + * 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.resource.loader; + +import java.util.WeakHashMap; + +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.ResourcePackSource; + +/** + * Tracks the sources of resource packs in a global weak hash map. + * {@link ResourcePack} doesn't hold a reference to its {@link ResourcePackSource} + * so we store the source in the map when the resource packs are created. + * See {@link net.fabricmc.fabric.mixin.resource.loader.ResourcePackProfileMixin ResourcePackProfileMixin}. + * + *

The sources are later read for use in {@link FabricResource} and {@link FabricResourceImpl}. + * See {@link net.fabricmc.fabric.mixin.resource.loader.NamespaceResourceManagerMixin NamespaceResourceManagerMixin}. + */ +public final class ResourcePackSourceTracker { + // Use a weak hash map so that if resource packs would be deleted, this won't keep them alive. + private static final WeakHashMap SOURCES = new WeakHashMap<>(); + + /** + * Gets the source of a pack. + * + * @param pack the resource pack + * @return the source, or {@link ResourcePackSource#PACK_SOURCE_NONE} if not tracked + */ + public static ResourcePackSource getSource(ResourcePack pack) { + return SOURCES.getOrDefault(pack, ResourcePackSource.PACK_SOURCE_NONE); + } + + /** + * Sets the source of a pack. + * + * @param pack the resource pack + * @param source the source + */ + public static void setSource(ResourcePack pack, ResourcePackSource source) { + SOURCES.put(pack, source); + } +} diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/DefaultResourcePackResourceMixin.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/DefaultResourcePackResourceMixin.java new file mode 100644 index 000000000..5f0f12d30 --- /dev/null +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/DefaultResourcePackResourceMixin.java @@ -0,0 +1,36 @@ +/* + * 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.resource.loader; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.resource.ResourcePackSource; + +import net.fabricmc.fabric.impl.resource.loader.FabricResource; + +/** + * Implements {@link FabricResource} for the anonymous resource implementation + * in {@link net.minecraft.resource.DefaultResourcePack#getResource}. + */ +@Mixin(targets = "net/minecraft/resource/DefaultResourcePack$1") +abstract class DefaultResourcePackResourceMixin implements FabricResource { + @Override + public ResourcePackSource getFabricPackSource() { + // The default resource pack only contains built-in vanilla resources. + return ResourcePackSource.PACK_SOURCE_BUILTIN; + } +} diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/NamespaceResourceManagerMixin.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/NamespaceResourceManagerMixin.java index 3daf64904..12ec3714d 100644 --- a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/NamespaceResourceManagerMixin.java +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/NamespaceResourceManagerMixin.java @@ -17,6 +17,7 @@ package net.fabricmc.fabric.mixin.resource.loader; import java.io.IOException; +import java.util.Iterator; import java.util.List; import org.spongepowered.asm.mixin.Mixin; @@ -32,7 +33,9 @@ import net.minecraft.resource.ResourcePack; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; +import net.fabricmc.fabric.impl.resource.loader.FabricResourceImpl; import net.fabricmc.fabric.impl.resource.loader.GroupResourcePack; +import net.fabricmc.fabric.impl.resource.loader.ResourcePackSourceTracker; @Mixin(NamespaceResourceManager.class) public class NamespaceResourceManagerMixin { @@ -66,4 +69,32 @@ public class NamespaceResourceManagerMixin { return pack.contains(type, id); } + + /* The two injectors below set the resource pack sources (see FabricResourceImpl) + * for resources created in NamespaceResourceManager.getAllResources and NamespaceResourceManager.getResource. + * + * Since (in 1.18.2) ResourceImpl doesn't hold a reference to its resource pack, + * we have to get the source from the resource pack when the resource is created. + * These are the main creation sites for resources in 1.18.2 + * along with DefaultResourcePack.getResource and Fabric API's GroupResourcePack, + * which also either track the source similarly or provide other types of Resource instances + * that have a different FabricResource implementation. + */ + + @Inject(method = "getAllResources", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", remap = false, shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) + private void trackSourceOnGetAllResources(Identifier id, CallbackInfoReturnable> cir, List resources, Identifier metadataPath, Iterator packs, ResourcePack resourcePack) { + // After the created resource has been added, read it from the list and set its source + // to match the tracked source of its resource pack. + if (resources.get(resources.size() - 1) instanceof FabricResourceImpl resource) { + resource.setFabricPackSource(ResourcePackSourceTracker.getSource(resourcePack)); + } + } + + @Inject(method = "getResource", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD) + private void trackSourceOnGetResource(Identifier id, CallbackInfoReturnable cir, ResourcePack metaResourcePack, Identifier metadataPath, int i, ResourcePack resourcePack) { + // Set the resource's source to match the tracked source of its resource pack. + if (cir.getReturnValue() instanceof FabricResourceImpl resource) { + resource.setFabricPackSource(ResourcePackSourceTracker.getSource(resourcePack)); + } + } } diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceImplMixin.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceImplMixin.java new file mode 100644 index 000000000..dd0d039db --- /dev/null +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceImplMixin.java @@ -0,0 +1,50 @@ +/* + * 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.resource.loader; + +import java.util.Objects; + +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import net.minecraft.resource.ResourceImpl; +import net.minecraft.resource.ResourcePackSource; + +import net.fabricmc.fabric.impl.resource.loader.FabricResourceImpl; + +/** + * Implements {@link FabricResourceImpl} (resource source getter/setter) + * for vanilla's basic {@link ResourceImpl} used for most game resources. + * + * @see NamespaceResourceManagerMixin the usage site for this mixin + */ +@Mixin(ResourceImpl.class) +abstract class ResourceImplMixin implements FabricResourceImpl { + @Unique + private @Nullable ResourcePackSource fabric_packSource; + + @Override + public ResourcePackSource getFabricPackSource() { + return Objects.requireNonNullElse(fabric_packSource, ResourcePackSource.PACK_SOURCE_NONE); + } + + @Override + public void setFabricPackSource(ResourcePackSource packSource) { + this.fabric_packSource = packSource; + } +} diff --git a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolEntryTypesAccessor.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceMixin.java similarity index 54% rename from fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolEntryTypesAccessor.java rename to fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceMixin.java index 9264ca0a9..3b929a5fc 100644 --- a/fabric-loot-tables-v1/src/main/java/net/fabricmc/fabric/mixin/loot/table/LootPoolEntryTypesAccessor.java +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourceMixin.java @@ -14,20 +14,15 @@ * limitations under the License. */ -package net.fabricmc.fabric.mixin.loot.table; +package net.fabricmc.fabric.mixin.resource.loader; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; -import net.minecraft.loot.entry.LootPoolEntry; -import net.minecraft.loot.entry.LootPoolEntryType; -import net.minecraft.loot.entry.LootPoolEntryTypes; -import net.minecraft.util.JsonSerializer; +import net.minecraft.resource.Resource; -@Mixin(LootPoolEntryTypes.class) -public interface LootPoolEntryTypesAccessor { - @Invoker("register") - static LootPoolEntryType register(String id, JsonSerializer serializer) { - throw new UnsupportedOperationException("Mixin dummy"); - } +import net.fabricmc.fabric.impl.resource.loader.FabricResource; + +// Add FabricResource to Resource's superinterfaces. +@Mixin(Resource.class) +interface ResourceMixin extends FabricResource { } diff --git a/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourcePackProfileMixin.java b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourcePackProfileMixin.java new file mode 100644 index 000000000..05f8c413a --- /dev/null +++ b/fabric-resource-loader-v0/src/main/java/net/fabricmc/fabric/mixin/resource/loader/ResourcePackProfileMixin.java @@ -0,0 +1,49 @@ +/* + * 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.resource.loader; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.resource.ResourcePack; +import net.minecraft.resource.ResourcePackProfile; +import net.minecraft.resource.ResourcePackSource; + +import net.fabricmc.fabric.impl.resource.loader.ResourcePackSourceTracker; + +/** + * Implements resource pack source tracking (for {@link net.fabricmc.fabric.impl.resource.loader.FabricResource}). + * {@link ResourcePack} doesn't hold a reference to its {@link ResourcePackSource} + * so we store the source in a global tracker when the resource packs are created. + * + * @see ResourcePackSourceTracker + */ +@Mixin(ResourcePackProfile.class) +abstract class ResourcePackProfileMixin { + @Shadow + @Final + private ResourcePackSource source; + + @Inject(method = "createResourcePack", at = @At("RETURN")) + private void onCreateResourcePack(CallbackInfoReturnable info) { + ResourcePackSourceTracker.setSource(info.getReturnValue(), source); + } +} diff --git a/fabric-resource-loader-v0/src/main/resources/fabric-resource-loader-v0.mixins.json b/fabric-resource-loader-v0/src/main/resources/fabric-resource-loader-v0.mixins.json index feff26275..fef2a712b 100644 --- a/fabric-resource-loader-v0/src/main/resources/fabric-resource-loader-v0.mixins.json +++ b/fabric-resource-loader-v0/src/main/resources/fabric-resource-loader-v0.mixins.json @@ -5,14 +5,18 @@ "mixins": [ "FileResourcePackProviderAccessor", "DefaultResourcePackMixin", + "DefaultResourcePackResourceMixin", "KeyedResourceReloadListenerMixin", "LifecycledResourceManagerImplMixin", "MinecraftServerMixin", "NamespaceResourceManagerAccessor", "NamespaceResourceManagerMixin", "ReloadableResourceManagerImplMixin", + "ResourceImplMixin", + "ResourceMixin", "ResourcePackManagerMixin", "ResourcePackManagerAccessor", + "ResourcePackProfileMixin", "SimpleResourceReloadMixin" ], "client": [ diff --git a/fabric-transitive-access-wideners-v1/src/main/resources/fabric-transitive-access-wideners-v1.accesswidener b/fabric-transitive-access-wideners-v1/src/main/resources/fabric-transitive-access-wideners-v1.accesswidener index 5b0188121..16c277af4 100644 --- a/fabric-transitive-access-wideners-v1/src/main/resources/fabric-transitive-access-wideners-v1.accesswidener +++ b/fabric-transitive-access-wideners-v1/src/main/resources/fabric-transitive-access-wideners-v1.accesswidener @@ -15,6 +15,15 @@ transitive-accessible method net/minecraft/screen/ScreenHandlerType (Lnet transitive-accessible class net/minecraft/client/gui/screen/ingame/HandledScreens$Provider transitive-accessible method net/minecraft/client/gui/screen/ingame/HandledScreens register (Lnet/minecraft/screen/ScreenHandlerType;Lnet/minecraft/client/gui/screen/ingame/HandledScreens$Provider;)V +# Data contained in loot tables and pools +transitive-accessible field net/minecraft/loot/LootPool entries [Lnet/minecraft/loot/entry/LootPoolEntry; +transitive-accessible field net/minecraft/loot/LootPool conditions [Lnet/minecraft/loot/condition/LootCondition; +transitive-accessible field net/minecraft/loot/LootPool functions [Lnet/minecraft/loot/function/LootFunction; +transitive-accessible field net/minecraft/loot/LootPool rolls Lnet/minecraft/loot/provider/number/LootNumberProvider; +transitive-accessible field net/minecraft/loot/LootPool bonusRolls Lnet/minecraft/loot/provider/number/LootNumberProvider; +transitive-accessible field net/minecraft/loot/LootTable pools [Lnet/minecraft/loot/LootPool; +transitive-accessible field net/minecraft/loot/LootTable functions [Lnet/minecraft/loot/function/LootFunction; + ### Generated access wideners below # Constructors of non-abstract block classes transitive-accessible method net/minecraft/block/AirBlock (Lnet/minecraft/block/AbstractBlock$Settings;)V diff --git a/fabric-transitive-access-wideners-v1/template.accesswidener b/fabric-transitive-access-wideners-v1/template.accesswidener index 257dcd183..afb4b6371 100644 --- a/fabric-transitive-access-wideners-v1/template.accesswidener +++ b/fabric-transitive-access-wideners-v1/template.accesswidener @@ -15,4 +15,13 @@ transitive-accessible method net/minecraft/screen/ScreenHandlerType (Lnet transitive-accessible class net/minecraft/client/gui/screen/ingame/HandledScreens$Provider transitive-accessible method net/minecraft/client/gui/screen/ingame/HandledScreens register (Lnet/minecraft/screen/ScreenHandlerType;Lnet/minecraft/client/gui/screen/ingame/HandledScreens$Provider;)V +# Data contained in loot tables and pools +transitive-accessible field net/minecraft/loot/LootPool entries [Lnet/minecraft/loot/entry/LootPoolEntry; +transitive-accessible field net/minecraft/loot/LootPool conditions [Lnet/minecraft/loot/condition/LootCondition; +transitive-accessible field net/minecraft/loot/LootPool functions [Lnet/minecraft/loot/function/LootFunction; +transitive-accessible field net/minecraft/loot/LootPool rolls Lnet/minecraft/loot/provider/number/LootNumberProvider; +transitive-accessible field net/minecraft/loot/LootPool bonusRolls Lnet/minecraft/loot/provider/number/LootNumberProvider; +transitive-accessible field net/minecraft/loot/LootTable pools [Lnet/minecraft/loot/LootPool; +transitive-accessible field net/minecraft/loot/LootTable functions [Lnet/minecraft/loot/function/LootFunction; + ### Generated access wideners below diff --git a/gradle.properties b/gradle.properties index fe26237df..71b7bfc02 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,6 +29,7 @@ fabric-item-groups-v0-version=0.3.12 fabric-key-binding-api-v1-version=1.0.12 fabric-keybindings-v0-version=0.2.10 fabric-lifecycle-events-v1-version=2.0.4 +fabric-loot-api-v2-version=1.0.0 fabric-loot-tables-v1-version=1.0.11 fabric-mining-level-api-v1-version=2.1.1 fabric-models-v0-version=0.3.6 diff --git a/settings.gradle b/settings.gradle index 6028689eb..4c5513d80 100644 --- a/settings.gradle +++ b/settings.gradle @@ -33,6 +33,7 @@ include 'fabric-item-groups-v0' include 'fabric-keybindings-v0' include 'fabric-key-binding-api-v1' include 'fabric-lifecycle-events-v1' +include 'fabric-loot-api-v2' include 'fabric-loot-tables-v1' include 'fabric-mining-level-api-v1' include 'fabric-models-v0'