Loot table API v2

- 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.

  Co-authored-by: i509VCB <i509vcb@gmail.com>
This commit is contained in:
Juuxel 2022-05-31 12:12:10 +01:00 committed by modmuss50
parent 14b3ae007b
commit 9e7660c677
54 changed files with 1573 additions and 184 deletions

View file

@ -0,0 +1,11 @@
archivesBaseName = "fabric-loot-tables-v1"
version = getSubprojectVersion(project)
moduleDependencies(project, [
'fabric-api-base',
'fabric-loot-api-v2'
])
dependencies {
testmodRuntimeOnly(project(path: ':fabric-resource-loader-v0', configuration: 'namedElements'))
}

View file

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

View file

@ -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 {
* <p>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;

View file

@ -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<LootPool> getPools();
List<LootFunction> getFunctions();
LootContextType getType();
default LootContextType getType() {
return asVanilla().getType(); // Vanilla has this now
}
}

View file

@ -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<LootPool> pools) {
pools.forEach(this::withPool);
asV2().pools(pools);
return this;
}
public FabricLootSupplierBuilder withFunctions(Collection<LootFunction> 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());

View file

@ -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();

View file

@ -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> 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> T read(Reader json, Class<T> c) {
return JsonHelper.deserialize(GSON.get(), json, c);
return JsonHelper.deserialize(GSON, json, c);
}
public static <T> T read(String json, Class<T> c) {
return JsonHelper.deserialize(GSON.get(), json, c);
return JsonHelper.deserialize(GSON, json, c);
}
}

View file

@ -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);

View file

@ -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<Consumer<LootTable.Builder>> modifications = new ArrayList<>();
private FabricLootSupplierBuilder addAction(Consumer<LootTable.Builder> action) {
modifications.add(action);
return this;
}
private FabricLootSupplierBuilder addV2Action(Consumer<FabricLootTableBuilder> 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<LootPool> pools) {
super.withPools(pools);
return addV2Action(builder -> builder.pools(pools));
}
@Override
public FabricLootSupplierBuilder withFunctions(Collection<LootFunction> 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<LootTable.Builder> modification : modifications) {
modification.accept(builder);
}
}
}

View file

@ -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<? extends LootPoolEntry> serializer) {
LootPoolEntryTypesAccessor.register(id.toString(), serializer);
Registry.register(Registry.LOOT_POOL_ENTRY_TYPE, id, new LootPoolEntryType(serializer));
}
}

View file

@ -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<Map<Identifier, BufferingLootTableBuilder>> 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<Identifier, BufferingLootTableBuilder> buffers = BUFFERS.get();
if (buffers.containsKey(id)) {
try {
buffers.get(id).applyTo(tableBuilder);
} finally {
buffers.remove(id);
if (buffers.isEmpty()) {
BUFFERS.remove();
}
}
}
});
}
}

View file

@ -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<LootPoolEntry> getEntries() {
return Arrays.asList(entries);
return ImmutableList.copyOf(entries);
}
@Override
public List<LootCondition> getConditions() {
return Arrays.asList(conditions);
return ImmutableList.copyOf(conditions);
}
@Override
public List<LootFunction> getFunctions() {
return Arrays.asList(functions);
return ImmutableList.copyOf(functions);
}
@Accessor
@Override
public abstract LootNumberProvider getRolls();
public LootNumberProvider getRolls() {
return rolls;
}
}

View file

@ -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<LootPool> getPools() {
return Arrays.asList(pools);
return ImmutableList.copyOf(pools);
}
@Override
public List<LootFunction> getFunctions() {
return Arrays.asList(functions);
return ImmutableList.copyOf(functions);
}
@Accessor
@Override
public abstract LootContextType getType();
}

View file

@ -3,10 +3,6 @@
"package": "net.fabricmc.fabric.mixin.loot.table",
"compatibilityLevel": "JAVA_16",
"mixins": [
"LootPoolBuilderHooks",
"LootPoolEntryTypesAccessor",
"LootSupplierBuilderHooks",
"MixinLootManager",
"MixinLootPool",
"MixinLootSupplier"
],

View file

@ -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"
}
}

View file

@ -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);
}
});
}

View file

@ -10,7 +10,7 @@
},
"entrypoints": {
"main": [
"net.fabricmc.fabric.test.loot.LootTest"
"net.fabricmc.fabric.test.loot.LootV1Test"
]
}
}

View file

@ -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.

View file

@ -0,0 +1,7 @@
archivesBaseName = "fabric-loot-api-v2"
version = getSubprojectVersion(project)
moduleDependencies(project, [
'fabric-api-base',
'fabric-resource-loader-v0'
])

View file

@ -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.
*
* <p>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<? extends LootPoolEntry> 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<? extends LootCondition> 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<? extends LootFunction> 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()));
}
}

View file

@ -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.
*
* <p>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<? extends LootPool> 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<? extends LootFunction> 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;
}
}

View file

@ -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> 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).
*
* <p>You can also modify loot tables that are created by {@link #REPLACE}.
* They have the loot table source {@link LootTableSource#REPLACED}.
*
* <h2>Example: adding diamonds to the cobblestone loot table</h2>
* <pre>
* {@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);
* }
* });
* }
* </pre>
*/
public static final Event<Modify> 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);
}
}

View file

@ -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.
*
* <p>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.
*
* <p>{@link #VANILLA} and {@link #MOD} are builtin.
*
* @return {@code true} if builtin, {@code false} otherwise
*/
public boolean isBuiltin() {
return builtin;
}
}

View file

@ -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.
*
* <h2>Events</h2>
* {@link net.fabricmc.fabric.api.loot.v2.LootTableEvents} has events to modify existing loot tables,
* or outright replace them with a new loot table.
*
* <p>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.
*
* <h2>Extended loot table and pool builders</h2>
* 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;

View file

@ -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.impl.loot;
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 LootTableSource determineSource(Identifier lootTableId, ResourceManager resourceManager) {
Identifier resourceId = new Identifier(lootTableId.getNamespace(), "loot_tables/%s.json".formatted(lootTableId.getPath()));
Resource resource = resourceManager.getResource(resourceId).orElse(null);
if (resource != null) {
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;
}
}
// 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;
}
}

View file

@ -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<Identifier, LootTable> tables;
@Inject(method = "apply", at = @At("RETURN"))
private void apply(Map<Identifier, JsonObject> 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<Identifier, LootTable> 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();
}
}

View file

@ -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<LootPoolEntry> getEntries();
@Accessor
List<LootCondition> getConditions();
@Accessor
List<LootFunction> 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();
}

View file

@ -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<LootPoolEntry> entries;
@Shadow
@Final
private List<LootCondition> conditions;
@Shadow
@Final
private List<LootFunction> 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<? extends LootPoolEntry> 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<? extends LootCondition> 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<? extends LootFunction> functions) {
this.functions.addAll(functions);
return self();
}
}

View file

@ -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<LootPool> getPools();
@Accessor
List<LootFunction> 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();
}

View file

@ -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<LootPool> pools;
@Shadow
@Final
private List<LootFunction> 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<? extends LootPool> pools) {
this.pools.addAll(pools);
return self();
}
@Override
public LootTable.Builder apply(Collection<? extends LootFunction> functions) {
this.functions.addAll(functions);
return self();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,15 @@
{
"required": true,
"package": "net.fabricmc.fabric.mixin.loot",
"compatibilityLevel": "JAVA_8",
"mixins": [
"LootManagerMixin",
"LootPoolAccessor",
"LootPoolBuilderMixin",
"LootTableAccessor",
"LootTableBuilderMixin"
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -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"]
}
}
}

View file

@ -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.Text;
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(Text.literal("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");
}
});
}
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "minecraft:diamond"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -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"
]
}
}

View file

@ -1,6 +0,0 @@
archivesBaseName = "fabric-loot-tables-v1"
version = getSubprojectVersion(project)
moduleDependencies(project, [
'fabric-api-base'
])

View file

@ -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<Identifier, LootTable> tables;
@Inject(method = "apply", at = @At("RETURN"))
private void apply(Map<Identifier, JsonObject> objectMap, ResourceManager manager, Profiler profiler, CallbackInfo info) {
Map<Identifier, LootTable> 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);
}
}

View file

@ -14,20 +14,10 @@
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.loot.table;
package net.fabricmc.fabric.impl.resource.loader;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import net.minecraft.resource.ResourcePackSource;
import net.minecraft.loot.entry.LootPoolEntry;
import net.minecraft.loot.entry.LootPoolEntryType;
import net.minecraft.loot.entry.LootPoolEntryTypes;
import net.minecraft.util.JsonSerializer;
@Mixin(LootPoolEntryTypes.class)
public interface LootPoolEntryTypesAccessor {
@Invoker("register")
static LootPoolEntryType register(String id, JsonSerializer<? extends LootPoolEntry> serializer) {
throw new UnsupportedOperationException("Mixin dummy");
}
public interface FabricNamespaceResourceManagerEntry {
void setFabricPackSource(ResourcePackSource packSource);
}

View file

@ -0,0 +1,43 @@
/*
* 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.
*
* <p>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;
}
void setFabricPackSource(ResourcePackSource packSource);
}

View file

@ -128,7 +128,9 @@ public abstract class GroupResourcePack implements ResourcePack {
for (ModResourcePack pack : packs) {
if (pack.contains(manager.getType(), id)) {
resources.add(((NamespaceResourceManager) manager).new Entry(id, metadataId, pack));
final NamespaceResourceManager.Entry entry = ((NamespaceResourceManager) manager).new Entry(id, metadataId, pack);
((FabricNamespaceResourceManagerEntry) entry).setFabricPackSource(ModResourcePackCreator.RESOURCE_PACK_SOURCE);
resources.add(entry);
}
}
}

View file

@ -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}.
*
* <p>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<ResourcePack, ResourcePackSource> 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);
}
}

View file

@ -0,0 +1,48 @@
/*
* 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.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.resource.NamespaceResourceManager;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourcePackSource;
import net.fabricmc.fabric.impl.resource.loader.FabricNamespaceResourceManagerEntry;
import net.fabricmc.fabric.impl.resource.loader.FabricResource;
@Mixin(NamespaceResourceManager.Entry.class)
public class NamespaceResourceManagerEntryMixin implements FabricNamespaceResourceManagerEntry {
@Unique
private @Nullable ResourcePackSource fabric_packSource;
@Override
public void setFabricPackSource(ResourcePackSource packSource) {
this.fabric_packSource = packSource;
}
@Inject(method = "toReference", at = @At("RETURN"))
public void toReference(CallbackInfoReturnable<Resource> cir) {
Resource resource = cir.getReturnValue();
((FabricResource) resource).setFabricPackSource(fabric_packSource);
}
}

View file

@ -16,7 +16,9 @@
package net.fabricmc.fabric.mixin.resource.loader;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -31,7 +33,10 @@ import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.impl.resource.loader.FabricNamespaceResourceManagerEntry;
import net.fabricmc.fabric.impl.resource.loader.FabricResource;
import net.fabricmc.fabric.impl.resource.loader.GroupResourcePack;
import net.fabricmc.fabric.impl.resource.loader.ResourcePackSourceTracker;
/**
* Patches getAllResources and method_41265 to work with GroupResourcePack.
@ -74,4 +79,31 @@ public class NamespaceResourceManagerMixin {
return entries.add(entry);
}
/* 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<List<Resource>> cir, List<NamespaceResourceManager.Entry> entries, Identifier identifier, String string, Iterator var5, NamespaceResourceManager.FilterablePack filterablePack, 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 (entries.get(entries.size() - 1) instanceof FabricNamespaceResourceManagerEntry entry) {
entry.setFabricPackSource(ResourcePackSourceTracker.getSource(resourcePack));
}
}
@Inject(method = "getResource", at = @At(value = "RETURN", ordinal = 1), locals = LocalCapture.CAPTURE_FAILHARD)
private void trackSourceOnGetResource(Identifier identifier, CallbackInfoReturnable<Optional<Resource>> cir, int i, NamespaceResourceManager.FilterablePack filterablePack, ResourcePack resourcePack) {
// Set the resource's source to match the tracked source of its resource pack.
if (cir.getReturnValue().orElseThrow() instanceof FabricResource resource) {
resource.setFabricPackSource(ResourcePackSourceTracker.getSource(resourcePack));
}
}
}

View file

@ -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.Resource;
import net.minecraft.resource.ResourcePackSource;
import net.fabricmc.fabric.impl.resource.loader.FabricResource;
/**
* Implements {@link FabricResource} (resource source getter/setter)
* for vanilla's basic {@link Resource} used for most game resources.
*
* @see NamespaceResourceManagerMixin the usage site for this mixin
*/
@Mixin(Resource.class)
class ResourceMixin implements FabricResource {
@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;
}
}

View file

@ -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<ResourcePack> info) {
ResourcePackSourceTracker.setSource(info.getReturnValue(), source);
}
}

View file

@ -3,3 +3,4 @@ accessWidener v2 named
accessible method net/minecraft/resource/NamespaceResourceManager$Entry <init> (Lnet/minecraft/resource/NamespaceResourceManager;Lnet/minecraft/util/Identifier;Lnet/minecraft/util/Identifier;Lnet/minecraft/resource/ResourcePack;)V
accessible field net/minecraft/resource/NamespaceResourceManager$Entry id Lnet/minecraft/util/Identifier;
accessible field net/minecraft/resource/NamespaceResourceManager$Entry pack Lnet/minecraft/resource/ResourcePack;
accessible class net/minecraft/resource/NamespaceResourceManager$FilterablePack

View file

@ -10,10 +10,13 @@
"MainMixin",
"MinecraftServerMixin",
"NamespaceResourceManagerAccessor",
"NamespaceResourceManagerEntryMixin",
"NamespaceResourceManagerMixin",
"ReloadableResourceManagerImplMixin",
"ResourcePackManagerAccessor",
"ResourceMixin",
"ResourcePackManagerMixin",
"ResourcePackManagerAccessor",
"ResourcePackProfileMixin",
"SimpleResourceReloadMixin",
"TestServerMixin"
],

View file

@ -15,6 +15,15 @@ transitive-accessible method net/minecraft/screen/ScreenHandlerType <init> (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 <init> (Lnet/minecraft/block/AbstractBlock$Settings;)V

View file

@ -15,4 +15,13 @@ transitive-accessible method net/minecraft/screen/ScreenHandlerType <init> (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

View file

@ -30,6 +30,7 @@ fabric-item-groups-v0-version=0.3.21
fabric-key-binding-api-v1-version=1.0.17
fabric-keybindings-v0-version=0.2.15
fabric-lifecycle-events-v1-version=2.0.8
fabric-loot-api-v2-version=1.0.0
fabric-loot-tables-v1-version=1.0.15
fabric-mining-level-api-v1-version=2.1.5
fabric-models-v0-version=0.3.14

View file

@ -29,7 +29,7 @@ include 'fabric-item-api-v1'
include 'fabric-item-groups-v0'
include 'fabric-key-binding-api-v1'
include 'fabric-lifecycle-events-v1'
include 'fabric-loot-tables-v1'
include 'fabric-loot-api-v2'
include 'fabric-mining-level-api-v1'
include 'fabric-models-v0'
include 'fabric-networking-api-v1'
@ -60,3 +60,4 @@ include 'deprecated:fabric-keybindings-v0'
include 'deprecated:fabric-networking-v0'
include 'deprecated:fabric-renderer-registries-v1'
include 'deprecated:fabric-rendering-v0'
include 'deprecated:fabric-loot-tables-v1'