mirror of
https://github.com/FabricMC/fabric.git
synced 2025-09-07 03:39:18 +00:00
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:
29
fabric-loot-api-v2/README.md
Normal file
29
fabric-loot-api-v2/README.md
Normal 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.
|
7
fabric-loot-api-v2/build.gradle
Normal file
7
fabric-loot-api-v2/build.gradle
Normal file
@@ -0,0 +1,7 @@
|
||||
archivesBaseName = "fabric-loot-api-v2"
|
||||
version = getSubprojectVersion(project)
|
||||
|
||||
moduleDependencies(project, [
|
||||
'fabric-api-base',
|
||||
'fabric-resource-loader-v0'
|
||||
])
|
@@ -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()));
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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.loot;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.loot.LootPool;
|
||||
import net.minecraft.loot.LootTable;
|
||||
import net.minecraft.loot.function.LootFunction;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
@@ -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 |
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.loot",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"LootManagerMixin",
|
||||
"LootPoolAccessor",
|
||||
"LootPoolBuilderMixin",
|
||||
"LootTableAccessor",
|
||||
"LootTableBuilderMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
34
fabric-loot-api-v2/src/main/resources/fabric.mod.json
Normal file
34
fabric-loot-api-v2/src/main/resources/fabric.mod.json
Normal 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"]
|
||||
}
|
||||
}
|
||||
}
|
@@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:diamond"
|
||||
}
|
||||
],
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
16
fabric-loot-api-v2/src/testmod/resources/fabric.mod.json
Normal file
16
fabric-loot-api-v2/src/testmod/resources/fabric.mod.json
Normal 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"
|
||||
]
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user