mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-08 21:14:41 -04:00
Fully port to 24w12a (#3664)
* Bump yarn * Apply yarn update * Sync map decorations type registry * Remove Mining Level API * Port loot API * whoops * Rename LootManagerMixin * Fix javadoc * Fix registerGiftLootTable * RegistryKey is traditionally compared using identity * Fix wrong loot source being used
This commit is contained in:
parent
e9d2a72b4f
commit
9b3069f652
39 changed files with 199 additions and 786 deletions
fabric-content-registries-v0/src
main/java/net/fabricmc/fabric
api/registry
mixin/content/registry
testmod/java/net/fabricmc/fabric/test/content/registry
fabric-data-generation-api-v1/src
main/java/net/fabricmc/fabric
api/datagen/v1/provider
impl/datagen/loot
testmod/java/net/fabricmc/fabric/test/datagen
fabric-item-api-v1/src/testmod/java/net/fabricmc/fabric/test/item
fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle
fabric-loot-api-v2/src
main
java/net/fabricmc/fabric
api/loot/v2
impl/loot
mixin/loot
resources
testmod/java/net/fabricmc/fabric/test/loot
fabric-mining-level-api-v1
build.gradle
src
main
java/net/fabricmc/fabric
api/mininglevel/v1
impl/mininglevel
mixin/mininglevel
resources
testmod
java/net/fabricmc/fabric/test/mininglevel
resources
fabric-object-builder-api-v1/src/client/java/net/fabricmc/fabric/api/object/builder/v1/client/model
fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/impl/registry/sync
gradle.propertiessettings.gradle
|
@ -27,6 +27,9 @@ import org.slf4j.LoggerFactory;
|
|||
import net.minecraft.entity.passive.VillagerEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemConvertible;
|
||||
import net.minecraft.loot.LootTable;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.village.VillagerProfession;
|
||||
|
||||
|
@ -79,15 +82,23 @@ public final class VillagerInteractionRegistries {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #registerGiftLootTable(VillagerProfession, RegistryKey)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void registerGiftLootTable(VillagerProfession profession, Identifier lootTable) {
|
||||
registerGiftLootTable(profession, RegistryKey.of(RegistryKeys.LOOT_TABLE, lootTable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a hero of the village gifts loot table to a profession.
|
||||
* @param profession the profession to modify
|
||||
* @param lootTable the loot table to associate with the profession
|
||||
*/
|
||||
public static void registerGiftLootTable(VillagerProfession profession, Identifier lootTable) {
|
||||
public static void registerGiftLootTable(VillagerProfession profession, RegistryKey<LootTable> lootTable) {
|
||||
Objects.requireNonNull(profession, "Profession cannot be null!");
|
||||
Objects.requireNonNull(lootTable, "Loot table identifier cannot be null!");
|
||||
Identifier oldValue = GiveGiftsToHeroTaskAccessor.fabric_getGifts().put(profession, lootTable);
|
||||
RegistryKey<LootTable> oldValue = GiveGiftsToHeroTaskAccessor.fabric_getGifts().put(profession, lootTable);
|
||||
|
||||
if (oldValue != null) {
|
||||
LOGGER.info("Overriding previous gift loot table of {} profession, was: {}, now: {}", profession.id(), oldValue, lootTable);
|
||||
|
|
|
@ -22,13 +22,14 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.entity.ai.brain.task.GiveGiftsToHeroTask;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.loot.LootTable;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.village.VillagerProfession;
|
||||
|
||||
@Mixin(GiveGiftsToHeroTask.class)
|
||||
public interface GiveGiftsToHeroTaskAccessor {
|
||||
@Accessor("GIFTS")
|
||||
static Map<VillagerProfession, Identifier> fabric_getGifts() {
|
||||
static Map<VillagerProfession, RegistryKey<LootTable>> fabric_getGifts() {
|
||||
throw new AssertionError("Untransformed @Accessor");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ import net.minecraft.potion.Potions;
|
|||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.registry.tag.BlockTags;
|
||||
import net.minecraft.registry.tag.ItemTags;
|
||||
|
@ -137,7 +139,7 @@ public final class ContentRegistryTest implements ModInitializer {
|
|||
|
||||
VillagerInteractionRegistries.registerCollectable(Items.OAK_SAPLING);
|
||||
|
||||
VillagerInteractionRegistries.registerGiftLootTable(VillagerProfession.NITWIT, new Identifier("fake_loot_table"));
|
||||
VillagerInteractionRegistries.registerGiftLootTable(VillagerProfession.NITWIT, RegistryKey.of(RegistryKeys.LOOT_TABLE, new Identifier("fake_loot_table")));
|
||||
|
||||
Registry.register(Registries.BLOCK, TEST_EVENT_ID, new TestEventBlock(AbstractBlock.Settings.copy(Blocks.STONE)));
|
||||
SculkSensorFrequencyRegistry.register(TEST_EVENT.registryKey(), 2);
|
||||
|
|
|
@ -79,7 +79,7 @@ public abstract class FabricBlockLootTableProvider extends BlockLootTableGenerat
|
|||
for (Map.Entry<RegistryKey<LootTable>, LootTable.Builder> entry : lootTables.entrySet()) {
|
||||
RegistryKey<LootTable> registryKey = entry.getKey();
|
||||
|
||||
if (registryKey.equals(LootTables.EMPTY)) {
|
||||
if (registryKey == LootTables.EMPTY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public final class FabricLootTableProviderImpl {
|
|||
final List<CompletableFuture<?>> futures = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<Identifier, LootTable> entry : builders.entrySet()) {
|
||||
JsonObject tableJson = (JsonObject) Util.getResult(LootTable.field_50021.encodeStart(ops, entry.getValue()), IllegalStateException::new);
|
||||
JsonObject tableJson = (JsonObject) Util.getResult(LootTable.CODEC.encodeStart(ops, entry.getValue()), IllegalStateException::new);
|
||||
ConditionJsonProvider.write(tableJson, conditionMap.remove(entry.getKey()));
|
||||
futures.add(DataProvider.writeToPath(writer, tableJson, getOutputPath(fabricDataOutput, entry.getKey())));
|
||||
}
|
||||
|
|
|
@ -435,7 +435,7 @@ public class DataGeneratorTestEntrypoint implements DataGeneratorEntrypoint {
|
|||
|
||||
private static class TestPredicateProvider extends FabricCodecDataProvider<LootCondition> {
|
||||
private TestPredicateProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
|
||||
super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, "predicates", LootConditionTypes.field_50031);
|
||||
super(dataOutput, registriesFuture, DataOutput.OutputType.DATA_PACK, "predicates", LootConditionTypes.CODEC);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -76,7 +76,7 @@ public class UpdatingItem extends Item {
|
|||
}
|
||||
|
||||
@Override
|
||||
public float method_58404(ItemStack stack, BlockState state) {
|
||||
return isEnabled(stack) ? 20 : super.method_58404(stack, state);
|
||||
public float getMiningSpeed(ItemStack stack, BlockState state) {
|
||||
return isEnabled(stack) ? 20 : super.getMiningSpeed(stack, state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ 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.class_9383;
|
||||
import net.minecraft.registry.ReloadableRegistries;
|
||||
import net.minecraft.server.DataPackContents;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents;
|
||||
|
@ -32,10 +32,10 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents;
|
|||
public class DataPackContentsMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private class_9383.class_9385 field_49921;
|
||||
private ReloadableRegistries.Lookup reloadableRegistries;
|
||||
|
||||
@Inject(method = "refresh", at = @At("TAIL"))
|
||||
private void hookRefresh(CallbackInfo ci) {
|
||||
CommonLifecycleEvents.TAGS_LOADED.invoker().onTagsLoaded(field_49921.method_58289(), false);
|
||||
CommonLifecycleEvents.TAGS_LOADED.invoker().onTagsLoaded(this.reloadableRegistries.getRegistryManager(), false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,10 @@ 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.registry.Registry;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
@ -37,9 +37,9 @@ 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) -> {
|
||||
public static final Event<Replace> REPLACE = EventFactory.createArrayBacked(Replace.class, listeners -> (key, original, source) -> {
|
||||
for (Replace listener : listeners) {
|
||||
@Nullable LootTable replaced = listener.replaceLootTable(resourceManager, lootManager, id, original, source);
|
||||
@Nullable LootTable replaced = listener.replaceLootTable(key, original, source);
|
||||
|
||||
if (replaced != null) {
|
||||
return replaced;
|
||||
|
@ -66,9 +66,9 @@ public final class LootTableEvents {
|
|||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* LootTableEvents.MODIFY.register((resourceManager, lootManager, id, tableBuilder, source) -> {
|
||||
* LootTableEvents.MODIFY.register((key, 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()) {
|
||||
* if (Blocks.COBBLESTONE.getLootTableId() == key && source.isBuiltin()) {
|
||||
* // Create a new loot pool that will hold the diamonds.
|
||||
* LootPool.Builder pool = LootPool.builder()
|
||||
* // Add diamonds...
|
||||
|
@ -83,9 +83,9 @@ public final class LootTableEvents {
|
|||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static final Event<Modify> MODIFY = EventFactory.createArrayBacked(Modify.class, listeners -> (resourceManager, lootManager, id, tableBuilder, source) -> {
|
||||
public static final Event<Modify> MODIFY = EventFactory.createArrayBacked(Modify.class, listeners -> (key, tableBuilder, source) -> {
|
||||
for (Modify listener : listeners) {
|
||||
listener.modifyLootTable(resourceManager, lootManager, id, tableBuilder, source);
|
||||
listener.modifyLootTable(key, tableBuilder, source);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -102,28 +102,24 @@ public final class LootTableEvents {
|
|||
/**
|
||||
* Replaces loot tables.
|
||||
*
|
||||
* @param resourceManager the server resource manager
|
||||
* @param lootManager the loot manager
|
||||
* @param id the loot table ID
|
||||
* @param key the loot table key
|
||||
* @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);
|
||||
LootTable replaceLootTable(RegistryKey<LootTable> key, 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 key the loot table key
|
||||
* @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);
|
||||
void modifyLootTable(RegistryKey<LootTable> key, LootTable.Builder tableBuilder, LootTableSource source);
|
||||
}
|
||||
|
||||
public interface Loaded {
|
||||
|
@ -131,8 +127,8 @@ public final class LootTableEvents {
|
|||
* Called when all loot tables have been loaded and {@link LootTableEvents#REPLACE} and {@link LootTableEvents#MODIFY} have been invoked.
|
||||
*
|
||||
* @param resourceManager the server resource manager
|
||||
* @param lootManager the loot manager
|
||||
* @param lootRegistry the loot registry
|
||||
*/
|
||||
void onLootTablesLoaded(ResourceManager resourceManager, LootManager lootManager);
|
||||
void onLootTablesLoaded(ResourceManager resourceManager, Registry<LootTable> lootRegistry);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.loot;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.resource.Resource;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
|
@ -27,11 +29,9 @@ 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);
|
||||
public static final ThreadLocal<Map<Identifier, LootTableSource>> SOURCES = ThreadLocal.withInitial(HashMap::new);
|
||||
|
||||
public static LootTableSource determineSource(Resource resource) {
|
||||
if (resource != null) {
|
||||
ResourcePackSource packSource = ((FabricResource) resource).getFabricPackSource();
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.loot.LootDataType;
|
||||
import net.minecraft.resource.JsonDataLoader;
|
||||
import net.minecraft.resource.Resource;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.loot.LootUtil;
|
||||
|
||||
@Mixin(JsonDataLoader.class)
|
||||
public class JsonDataLoaderMixin {
|
||||
@Inject(method = "load", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/resource/ResourceFinder;toResourceId(Lnet/minecraft/util/Identifier;)Lnet/minecraft/util/Identifier;", shift = At.Shift.AFTER))
|
||||
private static void fillSourceMap(ResourceManager manager, String dataType, Gson gson, Map<Identifier, JsonElement> results, CallbackInfo ci, @Local Map.Entry<Identifier, Resource> entry, @Local(ordinal = 1) Identifier id) {
|
||||
if (!LootDataType.LOOT_TABLES.directory().equals(dataType)) return;
|
||||
|
||||
LootUtil.SOURCES.get().put(id, LootUtil.determineSource(entry.getValue()));
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.loot;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
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.loot.LootDataKey;
|
||||
import net.minecraft.loot.LootManager;
|
||||
import net.minecraft.loot.LootTable;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.ResourceReloader;
|
||||
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<LootDataKey<?>, ?> keyToValue;
|
||||
|
||||
@Inject(method = "reload", at = @At("RETURN"), cancellable = true)
|
||||
private void reload(ResourceReloader.Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor, CallbackInfoReturnable<CompletableFuture<Void>> cir) {
|
||||
//noinspection DataFlowIssue
|
||||
LootManager lootManager = (LootManager) (Object) this;
|
||||
cir.setReturnValue(cir.getReturnValue().thenRun(() -> applyLootTableEvents(manager, lootManager)));
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void applyLootTableEvents(ResourceManager resourceManager, LootManager lootManager) {
|
||||
// The builder for the new LootManager.tables map with modified loot tables.
|
||||
// We're using an immutable map to match vanilla.
|
||||
ImmutableMap.Builder<LootDataKey<?>, Object> newTables = ImmutableMap.builder();
|
||||
|
||||
this.keyToValue.forEach((dataKey, entry) -> {
|
||||
if (dataKey == LootManager.EMPTY_LOOT_TABLE) {
|
||||
// This is a special table and cannot be modified.
|
||||
// Vanilla also warns about that.
|
||||
newTables.put(dataKey, entry);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(entry instanceof LootTable table)) {
|
||||
// We only want to modify loot tables
|
||||
newTables.put(dataKey, entry);
|
||||
return;
|
||||
}
|
||||
|
||||
LootTableSource source = LootUtil.determineSource(dataKey.id(), resourceManager);
|
||||
// Invoke the REPLACE event for the current loot table.
|
||||
LootTable replacement = LootTableEvents.REPLACE.invoker().replaceLootTable(resourceManager, lootManager, dataKey.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, dataKey.id(), builder, source);
|
||||
|
||||
// Turn the builder back into a loot table and store it in the new table.
|
||||
newTables.put(dataKey, builder.build());
|
||||
});
|
||||
|
||||
this.keyToValue = newTables.build();
|
||||
LootTableEvents.ALL_LOADED.invoker().onLootTablesLoaded(resourceManager, lootManager);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.loot;
|
||||
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.loot.LootDataType;
|
||||
import net.minecraft.loot.LootTable;
|
||||
import net.minecraft.registry.MutableRegistry;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.RegistryOps;
|
||||
import net.minecraft.registry.ReloadableRegistries;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.loot.v2.FabricLootTableBuilder;
|
||||
import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
|
||||
import net.fabricmc.fabric.api.loot.v2.LootTableSource;
|
||||
import net.fabricmc.fabric.impl.loot.LootUtil;
|
||||
|
||||
/**
|
||||
* Implements the events from {@link LootTableEvents}.
|
||||
*/
|
||||
@Mixin(ReloadableRegistries.class)
|
||||
abstract class ReloadableRegistriesMixin {
|
||||
@ModifyArg(method = "method_58286", at = @At(value = "INVOKE", target = "Lnet/minecraft/registry/MutableRegistry;add(Lnet/minecraft/registry/RegistryKey;Ljava/lang/Object;Lnet/minecraft/registry/entry/RegistryEntryInfo;)Lnet/minecraft/registry/entry/RegistryEntry$Reference;"), index = 1)
|
||||
private static Object modifyLootTable(Object value, @Local(argsOnly = true) Identifier id) {
|
||||
if (!(value instanceof LootTable table)) return value;
|
||||
|
||||
if (table == LootTable.EMPTY) {
|
||||
// This is a special table and cannot be modified.
|
||||
return value;
|
||||
}
|
||||
|
||||
RegistryKey<LootTable> key = RegistryKey.of(RegistryKeys.LOOT_TABLE, id);
|
||||
// Populated inside JsonDataLoaderMixin
|
||||
LootTableSource source = LootUtil.SOURCES.get().getOrDefault(id, LootTableSource.DATA_PACK);
|
||||
// Invoke the REPLACE event for the current loot table.
|
||||
LootTable replacement = LootTableEvents.REPLACE.invoker().replaceLootTable(key, table, source);
|
||||
|
||||
if (replacement != null) {
|
||||
// Set the loot table to MODIFY to be the replacement loot table.
|
||||
// The MODIFY event will also see it as a replaced loot table via the source.
|
||||
table = replacement;
|
||||
source = LootTableSource.REPLACED;
|
||||
}
|
||||
|
||||
// Turn the current table into a modifiable builder and invoke the MODIFY event.
|
||||
LootTable.Builder builder = FabricLootTableBuilder.copyOf(table);
|
||||
LootTableEvents.MODIFY.invoker().modifyLootTable(key, builder, source);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Inject(method = "method_58279", at = @At("RETURN"))
|
||||
private static void onLootTablesLoaded(LootDataType lootDataType, ResourceManager resourceManager, RegistryOps registryOps, CallbackInfoReturnable<MutableRegistry> cir) {
|
||||
if (lootDataType != LootDataType.LOOT_TABLES) return;
|
||||
|
||||
LootTableEvents.ALL_LOADED.invoker().onLootTablesLoaded(resourceManager, (Registry<LootTable>) cir.getReturnValue());
|
||||
LootUtil.SOURCES.remove();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,8 @@
|
|||
"package": "net.fabricmc.fabric.mixin.loot",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"LootManagerMixin",
|
||||
"JsonDataLoaderMixin",
|
||||
"ReloadableRegistriesMixin",
|
||||
"LootPoolAccessor",
|
||||
"LootPoolBuilderMixin",
|
||||
"LootTableAccessor",
|
||||
|
|
|
@ -35,10 +35,10 @@ public class LootTest implements ModInitializer {
|
|||
// Test loot table load event
|
||||
// The LootTable.Builder LootPool.Builder methods here should use
|
||||
// prebuilt entries and pools to test the injected methods.
|
||||
LootTableEvents.REPLACE.register((resourceManager, lootManager, id, original, source) -> {
|
||||
if (Blocks.BLACK_WOOL.getLootTableId().equals(id)) {
|
||||
LootTableEvents.REPLACE.register((key, original, source) -> {
|
||||
if (Blocks.BLACK_WOOL.getLootTableId() == key) {
|
||||
if (source != LootTableSource.VANILLA) {
|
||||
throw new AssertionError("black wool loot table should have LootTableSource.VANILLA");
|
||||
throw new AssertionError("black wool loot table should have LootTableSource.VANILLA, got " + source);
|
||||
}
|
||||
|
||||
// Replace black wool drops with an iron ingot
|
||||
|
@ -53,22 +53,22 @@ public class LootTest implements ModInitializer {
|
|||
});
|
||||
|
||||
// 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)) {
|
||||
LootTableEvents.REPLACE.register((key, original, source) -> {
|
||||
if (Blocks.BLACK_WOOL.getLootTableId() == key) {
|
||||
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");
|
||||
LootTableEvents.MODIFY.register((key, tableBuilder, source) -> {
|
||||
if (Blocks.BLACK_WOOL.getLootTableId() == key && source != LootTableSource.REPLACED) {
|
||||
throw new AssertionError("black wool loot table should have LootTableSource.REPLACED, got " + source);
|
||||
}
|
||||
|
||||
if (Blocks.WHITE_WOOL.getLootTableId().equals(id)) {
|
||||
if (Blocks.WHITE_WOOL.getLootTableId() == key) {
|
||||
if (source != LootTableSource.VANILLA) {
|
||||
throw new AssertionError("white wool loot table should have LootTableSource.VANILLA");
|
||||
throw new AssertionError("white wool loot table should have LootTableSource.VANILLA, got " + source);
|
||||
}
|
||||
|
||||
// Add gold ingot with custom name to white wool drops
|
||||
|
@ -82,19 +82,19 @@ public class LootTest implements ModInitializer {
|
|||
}
|
||||
|
||||
// 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");
|
||||
if (Blocks.RED_WOOL.getLootTableId() == key && source != LootTableSource.MOD) {
|
||||
throw new AssertionError("red wool loot table should have LootTableSource.MOD, got " + source);
|
||||
}
|
||||
|
||||
// Modify yellow wool to drop *either* yellow wool or emeralds by adding
|
||||
// emeralds to the same loot pool.
|
||||
if (Blocks.YELLOW_WOOL.getLootTableId().equals(id)) {
|
||||
if (Blocks.YELLOW_WOOL.getLootTableId() == key) {
|
||||
tableBuilder.modifyPools(poolBuilder -> poolBuilder.with(ItemEntry.builder(Items.EMERALD)));
|
||||
}
|
||||
});
|
||||
|
||||
LootTableEvents.ALL_LOADED.register((resourceManager, lootManager) -> {
|
||||
LootTable blackWoolTable = lootManager.getLootTable(Blocks.BLACK_WOOL.getLootTableId());
|
||||
LootTableEvents.ALL_LOADED.register((resourceManager, lootRegistry) -> {
|
||||
LootTable blackWoolTable = lootRegistry.get(Blocks.BLACK_WOOL.getLootTableId());
|
||||
|
||||
if (blackWoolTable == LootTable.EMPTY) {
|
||||
throw new AssertionError("black wool loot table should not be empty");
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
version = getSubprojectVersion(project)
|
||||
|
||||
moduleDependencies(project, [
|
||||
'fabric-api-base',
|
||||
'fabric-lifecycle-events-v1',
|
||||
'fabric-resource-loader-v0'
|
||||
])
|
||||
|
||||
testDependencies(project, [
|
||||
':fabric-lifecycle-events-v1'
|
||||
])
|
|
@ -1,51 +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.api.mininglevel.v1;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
/**
|
||||
* Defines additional {@code mineable} tags for vanilla tools not covered by vanilla.
|
||||
*
|
||||
* <p>{@code mineable} tags specify which tools are able to break a block effectively and drop it.
|
||||
* Fabric API defines two additional {@code mineable} tags: {@link #SWORD_MINEABLE #fabric:mineable/sword}
|
||||
* and {@link #SHEARS_MINEABLE #fabric:mineable/shears}.
|
||||
*/
|
||||
public final class FabricMineableTags {
|
||||
/**
|
||||
* Blocks in this tag ({@code #fabric:mineable/sword}) can be effectively mined with swords.
|
||||
*
|
||||
* <p>As swords have materials and mining levels, the mining level tags described in
|
||||
* {@link MiningLevelManager} also apply.
|
||||
*/
|
||||
public static final TagKey<Block> SWORD_MINEABLE = register("mineable/sword");
|
||||
|
||||
/**
|
||||
* Blocks in this tag ({@code #fabric:mineable/shears}) can be effectively mined with shears.
|
||||
*/
|
||||
public static final TagKey<Block> SHEARS_MINEABLE = register("mineable/shears");
|
||||
|
||||
private FabricMineableTags() {
|
||||
}
|
||||
|
||||
private static TagKey<Block> register(String id) {
|
||||
return TagKey.of(RegistryKeys.BLOCK, new Identifier("fabric", id));
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.mininglevel.v1;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.registry.RegistryKeys;
|
||||
import net.minecraft.registry.tag.BlockTags;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.mininglevel.MiningLevelManagerImpl;
|
||||
|
||||
/**
|
||||
* Provides access to block mining levels.
|
||||
*
|
||||
* <h2>Mining level tags</h2>
|
||||
* {@code MiningLevelManager} supports the vanilla minimum mining level tags:
|
||||
* {@link net.minecraft.registry.tag.BlockTags#NEEDS_STONE_TOOL #needs_stone_tool},
|
||||
* {@link net.minecraft.registry.tag.BlockTags#NEEDS_IRON_TOOL #needs_iron_tool} and
|
||||
* {@link net.minecraft.registry.tag.BlockTags#NEEDS_DIAMOND_TOOL #needs_diamond_tool}.
|
||||
* In addition to them, you can use dynamic mining level tags for any mining level (such as wood, netherite
|
||||
* or a custom one). The dynamic tags are checked automatically.
|
||||
*
|
||||
* <p>Dynamic mining level tags are in the format {@code #fabric:needs_tool_level_N}, where {@code N}
|
||||
* is the wanted tool level as an integer. For example, a mining level tag for netherite (mining level 4) would be
|
||||
* {@code #fabric:needs_tool_level_4}.
|
||||
*/
|
||||
public final class MiningLevelManager {
|
||||
private MiningLevelManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tool mining level required to effectively mine and drop a block state.
|
||||
*
|
||||
* <p>Note: this method does not take into account tool-specific mining levels declared
|
||||
* with the tool attribute API.
|
||||
*
|
||||
* <p>The default mining level of blocks not modified with mining level tags
|
||||
* is -1 (the hand mining level).
|
||||
*
|
||||
* @param state the block state
|
||||
* @return the mining level of the block state
|
||||
*/
|
||||
public static int getRequiredMiningLevel(BlockState state) {
|
||||
return MiningLevelManagerImpl.getRequiredMiningLevel(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mining level block tag corresponding to a given integer mining level.
|
||||
* More precisely, return the corresponding vanilla tag ({@code #minecraft:needs_x_tool}) for levels 1 to 3,
|
||||
* and the Fabric tag ({@code #fabric:needs_tool_level_N}) for levels above 3.
|
||||
*
|
||||
* @param miningLevel the integer mining level
|
||||
* @return the corresponding mining level block tag
|
||||
* @throws IllegalArgumentException if a negative or zero mining level is passed
|
||||
*/
|
||||
public static TagKey<Block> getBlockTag(int miningLevel) {
|
||||
if (miningLevel <= 0) {
|
||||
throw new IllegalArgumentException("Mining level tags only exist for mining levels > 0, received: " + miningLevel);
|
||||
}
|
||||
|
||||
return switch (miningLevel) {
|
||||
case 1 -> BlockTags.NEEDS_STONE_TOOL;
|
||||
case 2 -> BlockTags.NEEDS_IRON_TOOL;
|
||||
case 3 -> BlockTags.NEEDS_DIAMOND_TOOL;
|
||||
default -> TagKey.of(RegistryKeys.BLOCK, new Identifier("fabric", "needs_tool_level_" + miningLevel));
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,81 +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.impl.mininglevel;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.registry.tag.BlockTags;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents;
|
||||
import net.fabricmc.yarn.constants.MiningLevels;
|
||||
|
||||
public final class MiningLevelManagerImpl {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("fabric-mining-level-api-v1/MiningLevelManagerImpl");
|
||||
private static final String TOOL_TAG_NAMESPACE = "fabric";
|
||||
private static final Pattern TOOL_TAG_PATTERN = Pattern.compile("^needs_tool_level_([0-9]+)$");
|
||||
|
||||
// A cache of block state mining levels. Cleared when tags are updated.
|
||||
private static final ThreadLocal<Reference2IntMap<BlockState>> CACHE = ThreadLocal.withInitial(Reference2IntOpenHashMap::new);
|
||||
|
||||
static {
|
||||
CommonLifecycleEvents.TAGS_LOADED.register((registries, client) -> CACHE.get().clear());
|
||||
}
|
||||
|
||||
public static int getRequiredMiningLevel(BlockState state) {
|
||||
return CACHE.get().computeIfAbsent(state, s -> {
|
||||
int miningLevel = MiningLevels.HAND;
|
||||
|
||||
// Handle #fabric:needs_tool_level_N
|
||||
for (TagKey<Block> tagId : state.streamTags().toList()) {
|
||||
if (!tagId.id().getNamespace().equals(TOOL_TAG_NAMESPACE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Matcher matcher = TOOL_TAG_PATTERN.matcher(tagId.id().getPath());
|
||||
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
int tagMiningLevel = Integer.parseInt(matcher.group(1));
|
||||
miningLevel = Math.max(miningLevel, tagMiningLevel);
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.error("Could not read mining level from tag #{}", tagId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle vanilla tags
|
||||
if (state.isIn(BlockTags.NEEDS_DIAMOND_TOOL)) {
|
||||
miningLevel = Math.max(miningLevel, MiningLevels.DIAMOND);
|
||||
} else if (state.isIn(BlockTags.NEEDS_IRON_TOOL)) {
|
||||
miningLevel = Math.max(miningLevel, MiningLevels.IRON);
|
||||
} else if (state.isIn(BlockTags.NEEDS_STONE_TOOL)) {
|
||||
miningLevel = Math.max(miningLevel, MiningLevels.STONE);
|
||||
}
|
||||
|
||||
return miningLevel;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,38 +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.mininglevel;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.MiningToolItem;
|
||||
|
||||
import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager;
|
||||
|
||||
@Mixin(MiningToolItem.class)
|
||||
abstract class MiningToolItemMixin {
|
||||
@Inject(method = "isSuitableFor", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/item/ToolMaterial;getMiningLevel()I"), cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void fabric$onIsSuitableFor(BlockState state, CallbackInfoReturnable<Boolean> info, int toolMiningLevel) {
|
||||
if (toolMiningLevel < MiningLevelManager.getRequiredMiningLevel(state)) {
|
||||
info.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +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.mininglevel;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ShearsItem;
|
||||
|
||||
import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags;
|
||||
|
||||
/**
|
||||
* Adds support for {@link FabricMineableTags#SHEARS_MINEABLE}.
|
||||
*/
|
||||
@Mixin(ShearsItem.class)
|
||||
abstract class ShearsItemMixin {
|
||||
@Inject(method = "isSuitableFor", at = @At("HEAD"), cancellable = true)
|
||||
private void fabric$onIsSuitableFor(BlockState state, CallbackInfoReturnable<Boolean> info) {
|
||||
if (state.isIn(FabricMineableTags.SHEARS_MINEABLE)) {
|
||||
info.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "getMiningSpeedMultiplier", at = @At("RETURN"), cancellable = true)
|
||||
private void fabric$onGetMiningSpeedMultiplier(ItemStack stack, BlockState state, CallbackInfoReturnable<Float> info) {
|
||||
if (info.getReturnValueF() == 1.0f) { // if not caught by vanilla checks
|
||||
if (state.isIn(FabricMineableTags.SHEARS_MINEABLE)) { // mimics MiningToolItem.getMiningSpeedMultiplier
|
||||
// In vanilla 1.17, shears have three special mining speed multiplier values:
|
||||
// - cobweb and leaves return 15.0
|
||||
// - wool returns 5.0
|
||||
// - vines and glow lichen return 2.0
|
||||
// As the most "neutral" option out of these three,
|
||||
// we'll use 5.0 as it's not extremely fast nor extremely slow.
|
||||
info.setReturnValue(5.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,61 +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.mininglevel;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.SwordItem;
|
||||
import net.minecraft.item.ToolItem;
|
||||
import net.minecraft.item.ToolMaterial;
|
||||
|
||||
import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags;
|
||||
import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager;
|
||||
|
||||
/**
|
||||
* Adds support for {@link FabricMineableTags#SWORD_MINEABLE}.
|
||||
*/
|
||||
@Mixin(SwordItem.class)
|
||||
abstract class SwordItemMixin extends ToolItem {
|
||||
private SwordItemMixin(ToolMaterial material, Settings settings) {
|
||||
super(material, settings);
|
||||
}
|
||||
|
||||
@Inject(method = "isSuitableFor", at = @At("HEAD"), cancellable = true)
|
||||
private void fabric$onIsSuitableFor(BlockState state, CallbackInfoReturnable<Boolean> info) {
|
||||
if (state.isIn(FabricMineableTags.SWORD_MINEABLE)) {
|
||||
int miningLevel = getMaterial().getMiningLevel();
|
||||
|
||||
if (miningLevel >= MiningLevelManager.getRequiredMiningLevel(state)) {
|
||||
info.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "getMiningSpeedMultiplier", at = @At("RETURN"), cancellable = true)
|
||||
private void fabric$onGetMiningSpeedMultiplier(ItemStack stack, BlockState state, CallbackInfoReturnable<Float> info) {
|
||||
if (info.getReturnValueF() == 1.0f) { // if not caught by vanilla checks
|
||||
if (state.isIn(FabricMineableTags.SWORD_MINEABLE)) { // mimics MiningToolItem.getMiningSpeedMultiplier
|
||||
info.setReturnValue(getMaterial().getMiningSpeedMultiplier());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Before ![]() (image error) Size: 1.5 KiB |
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.mininglevel",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"MiningToolItemMixin",
|
||||
"ShearsItemMixin",
|
||||
"SwordItemMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-mining-level-api-v1",
|
||||
"name": "Fabric Mining Level API (v1)",
|
||||
"version": "${version}",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "assets/fabric-mining-level-api-v1/icon.png",
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net",
|
||||
"irc": "irc://irc.esper.net:6667/fabric",
|
||||
"issues": "https://github.com/FabricMC/fabric/issues",
|
||||
"sources": "https://github.com/FabricMC/fabric"
|
||||
},
|
||||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.15.6",
|
||||
"fabric-api-base": "*",
|
||||
"fabric-lifecycle-events-v1": "*",
|
||||
"fabric-resource-loader-v0": "*"
|
||||
},
|
||||
"description": "Adds support for custom mining levels.",
|
||||
"mixins": [
|
||||
"fabric-mining-level-api-v1.mixins.json"
|
||||
],
|
||||
"custom": {
|
||||
"fabric-api:module-lifecycle": "stable"
|
||||
}
|
||||
}
|
|
@ -1,135 +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.test.mininglevel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
|
||||
// This test must pass without the tool attribute API present.
|
||||
// It has its own handlers for mining levels, which might "hide" this module
|
||||
// not working on its own.
|
||||
public final class MiningLevelTest implements ModInitializer {
|
||||
private static final String ID = "fabric-mining-level-api-v1-testmod";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MiningLevelTest.class);
|
||||
|
||||
/// Tagged blocks
|
||||
// sword + dynamic mining level tag
|
||||
public static final Block NEEDS_NETHERITE_SWORD = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
// sword + vanilla mining level tag
|
||||
public static final Block NEEDS_STONE_SWORD = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
// any sword
|
||||
public static final Block NEEDS_ANY_SWORD = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
// shears
|
||||
public static final Block NEEDS_SHEARS = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
// vanilla mineable tag + dynamic mining level tag
|
||||
public static final Block NEEDS_NETHERITE_PICKAXE = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
// vanilla mineable tag, requires tool (this type of block doesn't exist in vanilla)
|
||||
public static final Block NEEDS_AXE = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
// vanilla mineable tag, requires tool (this type of block doesn't exist in vanilla)
|
||||
public static final Block NEEDS_HOE = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
// vanilla mineable tag, requires tool (this type of block doesn't exist in vanilla)
|
||||
public static final Block NEEDS_SHOVEL = new Block(AbstractBlock.Settings.create().strength(2, 3).requiresTool());
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
register("needs_netherite_sword", NEEDS_NETHERITE_SWORD);
|
||||
register("needs_stone_sword", NEEDS_STONE_SWORD);
|
||||
register("needs_any_sword", NEEDS_ANY_SWORD);
|
||||
register("needs_shears", NEEDS_SHEARS);
|
||||
register("needs_netherite_pickaxe", NEEDS_NETHERITE_PICKAXE);
|
||||
register("needs_axe", NEEDS_AXE);
|
||||
register("needs_hoe", NEEDS_HOE);
|
||||
register("needs_shovel", NEEDS_SHOVEL);
|
||||
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> test());
|
||||
}
|
||||
|
||||
private static void register(String id, Block block) {
|
||||
Identifier identifier = new Identifier(ID, id);
|
||||
Registry.register(Registries.BLOCK, identifier, block);
|
||||
Registry.register(Registries.ITEM, identifier, new BlockItem(block, new Item.Settings()));
|
||||
}
|
||||
|
||||
private static void test() {
|
||||
List<AssertionError> errors = new ArrayList<>();
|
||||
test(errors, () -> checkMiningLevel(NEEDS_NETHERITE_SWORD, List.of(Items.NETHERITE_SWORD), List.of(Items.NETHERITE_PICKAXE, Items.STONE_SWORD)));
|
||||
test(errors, () -> checkMiningLevel(NEEDS_STONE_SWORD, List.of(Items.STONE_SWORD, Items.IRON_SWORD), List.of(Items.STONE_PICKAXE, Items.WOODEN_SWORD)));
|
||||
test(errors, () -> checkMiningLevel(NEEDS_ANY_SWORD, List.of(Items.WOODEN_SWORD), List.of()));
|
||||
test(errors, () -> checkMiningLevel(NEEDS_SHEARS, List.of(Items.SHEARS), List.of()));
|
||||
test(errors, () -> checkMiningLevel(NEEDS_NETHERITE_PICKAXE, List.of(Items.NETHERITE_PICKAXE), List.of(Items.DIAMOND_PICKAXE, Items.NETHERITE_AXE)));
|
||||
test(errors, () -> checkMiningLevel(Blocks.STONE, List.of(Items.WOODEN_PICKAXE), List.of(Items.STICK)));
|
||||
test(errors, () -> checkMiningLevel(NEEDS_AXE, List.of(Items.WOODEN_AXE), List.of(Items.STICK)));
|
||||
test(errors, () -> checkMiningLevel(NEEDS_HOE, List.of(Items.WOODEN_HOE), List.of(Items.STICK)));
|
||||
test(errors, () -> checkMiningLevel(NEEDS_SHOVEL, List.of(Items.WOODEN_SHOVEL), List.of(Items.STICK)));
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
LOGGER.info("Mining level tests passed!");
|
||||
} else {
|
||||
AssertionError error = new AssertionError("Mining level tests failed!");
|
||||
errors.forEach(error::addSuppressed);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private static void test(List<AssertionError> errors, Runnable runnable) {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (AssertionError e) {
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkMiningLevel(Block block, List<Item> successfulItems, List<Item> failingItems) {
|
||||
BlockState state = block.getDefaultState();
|
||||
|
||||
for (Item success : successfulItems) {
|
||||
ItemStack successStack = new ItemStack(success);
|
||||
|
||||
if (!successStack.isSuitableFor(state)) {
|
||||
throw new AssertionError(success + " is not suitable for " + block);
|
||||
}
|
||||
|
||||
if (successStack.getMiningSpeedMultiplier(state) == 1f) {
|
||||
throw new AssertionError(success + " returns default mining speed for " + block);
|
||||
}
|
||||
}
|
||||
|
||||
for (Item failing : failingItems) {
|
||||
if (new ItemStack(failing).isSuitableFor(state)) {
|
||||
throw new AssertionError(failing + " is suitable for " + block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_shears"
|
||||
]
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_netherite_sword",
|
||||
"fabric-mining-level-api-v1-testmod:needs_stone_sword",
|
||||
"fabric-mining-level-api-v1-testmod:needs_any_sword"
|
||||
]
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_netherite_pickaxe",
|
||||
"fabric-mining-level-api-v1-testmod:needs_netherite_sword"
|
||||
]
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_axe"
|
||||
]
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_hoe"
|
||||
]
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_netherite_pickaxe"
|
||||
]
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_shovel"
|
||||
]
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-mining-level-api-v1-testmod:needs_stone_sword"
|
||||
]
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-mining-level-api-v1-testmod",
|
||||
"name": "Fabric Mining Level API (v1) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-mining-level-api-v1": "*",
|
||||
"fabric-lifecycle-events-v1": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.mininglevel.MiningLevelTest"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ import net.fabricmc.fabric.mixin.object.builder.client.ModelPredicateProviderReg
|
|||
* Allows registering model predicate providers for item models.
|
||||
*
|
||||
* <p>A registered model predicate providers for an item can be retrieved through
|
||||
* {@link net.minecraft.client.item.ModelPredicateProviderRegistry#get(Item, Identifier)}.</p>
|
||||
* {@link net.minecraft.client.item.ModelPredicateProviderRegistry#get(net.minecraft.item.ItemStack, Identifier)}.</p>
|
||||
*
|
||||
* @see net.minecraft.client.item.ModelPredicateProviderRegistry
|
||||
* @deprecated Replaced by access wideners for {@link net.minecraft.client.item.ModelPredicateProviderRegistry}
|
||||
|
|
|
@ -208,5 +208,9 @@ public class FabricRegistryInit implements ModInitializer {
|
|||
// Synced by rawID.
|
||||
RegistryAttributeHolder.get(Registries.DATA_COMPONENT_TYPE)
|
||||
.addAttribute(RegistryAttribute.SYNCED);
|
||||
|
||||
// Synced by rawID.
|
||||
RegistryAttributeHolder.get(Registries.MAP_DECORATION_TYPE)
|
||||
.addAttribute(RegistryAttribute.SYNCED);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ fabric.loom.multiProjectOptimisation=true
|
|||
|
||||
version=0.96.12
|
||||
minecraft_version=24w12a
|
||||
yarn_version=+build.2
|
||||
yarn_version=+build.5
|
||||
loader_version=0.15.6
|
||||
installer_version=0.11.1
|
||||
|
||||
|
@ -38,7 +38,6 @@ fabric-keybindings-v0-version=0.2.41
|
|||
fabric-lifecycle-events-v1-version=2.3.1
|
||||
fabric-loot-api-v2-version=2.1.13
|
||||
fabric-message-api-v1-version=6.0.8
|
||||
fabric-mining-level-api-v1-version=2.1.69
|
||||
fabric-model-loading-api-v1-version=1.0.10
|
||||
fabric-models-v0-version=0.4.9
|
||||
fabric-networking-api-v1-version=4.0.5
|
||||
|
|
|
@ -37,9 +37,8 @@ include 'fabric-item-api-v1'
|
|||
include 'fabric-item-group-api-v1'
|
||||
include 'fabric-key-binding-api-v1'
|
||||
include 'fabric-lifecycle-events-v1'
|
||||
//include 'fabric-loot-api-v2'
|
||||
include 'fabric-loot-api-v2'
|
||||
include 'fabric-message-api-v1'
|
||||
//include 'fabric-mining-level-api-v1'
|
||||
include 'fabric-model-loading-api-v1'
|
||||
include 'fabric-networking-api-v1'
|
||||
include 'fabric-object-builder-api-v1'
|
||||
|
|
Loading…
Add table
Reference in a new issue