mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 16:27:47 +00:00
Redesign the tool system to rely on the new vanilla tags. (#7970)
Changed: - ToolType is replaced with ToolAction, which can selectively represent which actions are supported by an item. - Added a canPerformAction method to query ToolActions. - Renamed canHarvestBlock to isCorrectToolForDrops to match vanilla. - Added TierSortingRegistry, which can be used to add custom tiers and supports sorting between vanilla or with other mods. How to use: For the breaking system there's 2 methods: - getDestroySpeed decides if an item *can* mine the block fast. Override if you have multiple tags or your item isn't a DiggerItem. - isCorrectToolForDrops decides if an item will get drops. Returning false will also slow down mining, regardless of getDestroySpeed. Override if you have type-dependant tiers or your item isn't a DiggerItem. For the tier system mods can just call `TierSortingRegistry.registerTier(tier, "name", List.of(lesser tiers), List.of(better tiers));` to register their tiers. There's helper methods to query tiers such as TierSortingRegsitry.isCorrectTierForDrops. The ToolActions solve 2 problems: 1. distinguishing which kind of digger an item can be 2. querying if the item can perform specific secondary actions. Any item can override `canPerformAction` to customize which actions it performs.
This commit is contained in:
1 parent
52d7df06da
commit
10b51f257f
34 files changed
+1012
-441
No files matched your search
@@ -56,13 +56,15 @@ import javax.annotation.Nullable;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.ai.attributes.Attribute;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.DefaultAttributes;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.*;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
import net.minecraft.world.level.storage.loot.LootTables;
|
||||
@@ -84,13 +86,6 @@ import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.inventory.AnvilMenu;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.BucketItem;
|
||||
import net.minecraft.world.item.EnchantedBookItem;
|
||||
import net.minecraft.world.item.PotionItem;
|
||||
import net.minecraft.world.item.SpawnEggItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TippedArrowItem;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
@@ -178,7 +173,6 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
import org.apache.logging.log4j.util.TriConsumer;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -193,7 +187,6 @@ import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.dimension.LevelStem;
|
||||
@@ -219,50 +212,12 @@ public class ForgeHooks
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean canHarvestBlock(@Nonnull BlockState state, @Nonnull Player player, @Nonnull BlockGetter world, @Nonnull BlockPos pos)
|
||||
public static boolean isCorrectToolForDrops(@Nonnull BlockState state, @Nonnull Player player)
|
||||
{
|
||||
//state = state.getActualState(world, pos);
|
||||
if (!state.requiresCorrectToolForDrops())
|
||||
return ForgeEventFactory.doPlayerHarvestCheck(player, state, true);
|
||||
|
||||
ItemStack stack = player.getMainHandItem();
|
||||
ToolType tool = state.getHarvestTool();
|
||||
if (stack.isEmpty() || tool == null)
|
||||
return player.hasCorrectToolForDrops(state);
|
||||
|
||||
int toolLevel = stack.getHarvestLevel(tool, player, state);
|
||||
if (toolLevel < 0)
|
||||
return player.hasCorrectToolForDrops(state);
|
||||
|
||||
return ForgeEventFactory.doPlayerHarvestCheck(player, state, toolLevel >= state.getHarvestLevel());
|
||||
}
|
||||
|
||||
public static boolean isToolEffective(LevelReader world, BlockPos pos, @Nonnull ItemStack stack)
|
||||
{
|
||||
BlockState state = world.getBlockState(pos);
|
||||
//state = state.getActualState(world, pos);
|
||||
for (ToolType type : stack.getToolTypes())
|
||||
{
|
||||
if (state.isToolEffective(type))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean toolInit = false;
|
||||
static void initTools()
|
||||
{
|
||||
if (toolInit)
|
||||
return;
|
||||
toolInit = true;
|
||||
|
||||
//This is taken from PickaxeItem, if that changes update here.
|
||||
for (Block block : new Block[]{Blocks.OBSIDIAN, Blocks.CRYING_OBSIDIAN, Blocks.NETHERITE_BLOCK, Blocks.RESPAWN_ANCHOR, Blocks.ANCIENT_DEBRIS})
|
||||
blockToolSetter.accept(block, ToolType.PICKAXE, 3);
|
||||
for (Block block : new Block[]{Blocks.DIAMOND_BLOCK, Blocks.DIAMOND_ORE, Blocks.EMERALD_ORE, Blocks.EMERALD_BLOCK, Blocks.GOLD_BLOCK, Blocks.GOLD_ORE, Blocks.REDSTONE_ORE})
|
||||
blockToolSetter.accept(block, ToolType.PICKAXE, 2);
|
||||
for (Block block : new Block[]{Blocks.IRON_BLOCK, Blocks.IRON_ORE, Blocks.LAPIS_BLOCK, Blocks.LAPIS_ORE})
|
||||
blockToolSetter.accept(block, ToolType.PICKAXE, 1);
|
||||
return player.hasCorrectToolForDrops(state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -898,6 +853,19 @@ public class ForgeHooks
|
||||
return "default";
|
||||
}
|
||||
|
||||
public static Tag<Block> getTagFromVanillaTier(Tiers tier)
|
||||
{
|
||||
return switch(tier)
|
||||
{
|
||||
case WOOD -> Tags.Blocks.NEEDS_WOOD_TOOL;
|
||||
case GOLD -> Tags.Blocks.NEEDS_GOLD_TOOL;
|
||||
case STONE -> BlockTags.NEEDS_STONE_TOOL;
|
||||
case IRON -> BlockTags.NEEDS_IRON_TOOL;
|
||||
case DIAMOND -> BlockTags.NEEDS_DIAMOND_TOOL;
|
||||
case NETHERITE -> Tags.Blocks.NEEDS_NETHERITE_TOOL;
|
||||
};
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BiomeCallbackFunction
|
||||
{
|
||||
@@ -1093,12 +1061,6 @@ public class ForgeHooks
|
||||
return false;
|
||||
}
|
||||
|
||||
private static TriConsumer<Block, ToolType, Integer> blockToolSetter;
|
||||
//Internal use only Modders, this is specifically hidden from you, as you shouldn't be editing other people's blocks.
|
||||
public static void setBlockToolSetter(TriConsumer<Block, ToolType, Integer> setter)
|
||||
{
|
||||
blockToolSetter = setter;
|
||||
}
|
||||
|
||||
private static final DummyBlockReader DUMMY_WORLD = new DummyBlockReader();
|
||||
private static class DummyBlockReader implements BlockGetter {
|
||||
|
||||
@@ -140,5 +140,11 @@ public class ForgeInternalHandler
|
||||
throw new IllegalStateException("Can not retrieve LootModifierManager until resources have loaded once.");
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void resourceReloadListeners(AddReloadListenerEvent event)
|
||||
{
|
||||
event.addListener(TierSortingRegistry.getReloadListener());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,6 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
|
||||
|
||||
MinecraftForge.EVENT_BUS.addListener(VillagerTradingManager::loadTrades);
|
||||
MinecraftForge.EVENT_BUS.register(MinecraftForge.INTERNAL_HANDLER);
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
BiomeDictionary.init();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import net.minecraft.tags.Tag;
|
||||
import net.minecraft.world.item.Tier;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Helper class to define a custom tier
|
||||
*/
|
||||
@SuppressWarnings("ClassCanBeRecord") // can't make it a record because the method names will be obfuscated
|
||||
public final class ForgeTier implements Tier
|
||||
{
|
||||
private final int level;
|
||||
private final int uses;
|
||||
private final float speed;
|
||||
private final float attackDamageBonus;
|
||||
private final int enchantmentValue;
|
||||
@Nonnull
|
||||
private final Tag<Block> tag;
|
||||
@Nonnull
|
||||
private final Supplier<Ingredient> repairIngredient;
|
||||
|
||||
public ForgeTier(int level, int uses, float speed, float attackDamageBonus, int enchantmentValue,
|
||||
@Nonnull Tag<Block> tag, @Nonnull Supplier<Ingredient> repairIngredient)
|
||||
{
|
||||
this.level = level;
|
||||
this.uses = uses;
|
||||
this.speed = speed;
|
||||
this.attackDamageBonus = attackDamageBonus;
|
||||
this.enchantmentValue = enchantmentValue;
|
||||
this.tag = tag;
|
||||
this.repairIngredient = repairIngredient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUses()
|
||||
{
|
||||
return this.uses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSpeed()
|
||||
{
|
||||
return this.speed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAttackDamageBonus()
|
||||
{
|
||||
return this.attackDamageBonus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel()
|
||||
{
|
||||
return this.level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEnchantmentValue()
|
||||
{
|
||||
return this.enchantmentValue;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Tag<Block> getTag()
|
||||
{
|
||||
return this.tag;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Ingredient getRepairIngredient()
|
||||
{
|
||||
return this.repairIngredient.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "ForgeTier[" +
|
||||
"level=" + level + ", " +
|
||||
"uses=" + uses + ", " +
|
||||
"speed=" + speed + ", " +
|
||||
"attackDamageBonus=" + attackDamageBonus + ", " +
|
||||
"enchantmentValue=" + enchantmentValue + ", " +
|
||||
"tag=" + tag + ", " +
|
||||
"repairIngredient=" + repairIngredient + ']';
|
||||
}
|
||||
}
|
||||
@@ -51,12 +51,9 @@ public class MinecraftForge
|
||||
LOGGER.info(FORGE,"MinecraftForge v{} Initialized", ForgeVersion.getVersion());
|
||||
|
||||
UsernameCache.load();
|
||||
ForgeHooks.initTools();
|
||||
TierSortingRegistry.init();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
public static void preloadCrashClasses(ASMDataTable table, String modID, Set<String> classes)
|
||||
{
|
||||
|
||||
@@ -129,6 +129,10 @@ public class Tags
|
||||
public static final IOptionalNamedTag<Block> STORAGE_BLOCKS_QUARTZ = tag("storage_blocks/quartz");
|
||||
public static final IOptionalNamedTag<Block> STORAGE_BLOCKS_REDSTONE = tag("storage_blocks/redstone");
|
||||
|
||||
public static final IOptionalNamedTag<Block> NEEDS_WOOD_TOOL = tag("needs_wood_tool");
|
||||
public static final IOptionalNamedTag<Block> NEEDS_GOLD_TOOL = tag("needs_gold_tool");
|
||||
public static final IOptionalNamedTag<Block> NEEDS_NETHERITE_TOOL = tag("needs_netherite_tool");
|
||||
|
||||
private static IOptionalNamedTag<Block> tag(String name)
|
||||
{
|
||||
return BlockTags.createOptional(new ResourceLocation("forge", name));
|
||||
|
||||
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.google.common.graph.ElementOrder;
|
||||
import com.google.common.graph.GraphBuilder;
|
||||
import com.google.common.graph.MutableGraph;
|
||||
import com.google.gson.*;
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.server.packs.resources.Resource;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.server.packs.resources.SimplePreparableReloadListener;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.tags.Tag;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.item.DiggerItem;
|
||||
import net.minecraft.world.item.Tier;
|
||||
import net.minecraft.world.item.Tiers;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||
import net.minecraftforge.fml.loading.toposort.TopologicalSort;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkDirection;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkRegistry;
|
||||
import net.minecraftforge.fmllegacy.network.PacketDistributor;
|
||||
import net.minecraftforge.fmllegacy.network.simple.SimpleChannel;
|
||||
import net.minecraftforge.fmllegacy.server.ServerLifecycleHooks;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TierSortingRegistry
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
/**
|
||||
* Registers a tier into the tier sorting registry.
|
||||
* @param tier The tier to register
|
||||
* @param name The name to use internally for dependency resolution
|
||||
* @param after List of tiers to place this tier after (the tiers in the list will be considered lesser tiers)
|
||||
* @param before List of tiers to place this tier before (the tiers in the list will be considered better tiers)
|
||||
*/
|
||||
public static synchronized Tier registerTier(Tier tier, ResourceLocation name, List<Object> after, List<Object> before)
|
||||
{
|
||||
if (tiers.containsKey(name))
|
||||
throw new IllegalStateException("Duplicate tier name " + name);
|
||||
|
||||
processTier(tier, name, after, before);
|
||||
|
||||
hasCustomTiers = true;
|
||||
return tier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of tiers in the order defined by the dependencies.
|
||||
* This list will remain valid
|
||||
* @return An unmodifiable list of tiers ordered lesser to greater
|
||||
*/
|
||||
public static List<Tier> getSortedTiers()
|
||||
{
|
||||
return sortedTiersUnmodifiable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tier associated with a name, if registered into the sorting system.
|
||||
* @param name The name to look up
|
||||
* @return The tier, or null if not registered
|
||||
*/
|
||||
@Nullable
|
||||
public static Tier byName(ResourceLocation name)
|
||||
{
|
||||
return tiers.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name associated with a tier, if the tier is registered into the sorting system.
|
||||
* @param tier The tier to look up
|
||||
* @return The name for the tier, or null if not registered
|
||||
*/
|
||||
@Nullable
|
||||
public static ResourceLocation getName(Tier tier)
|
||||
{
|
||||
return tiers.inverse().get(tier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries if a tier should be evaluated using the sorting system, by calling isCorrectTierForDrops
|
||||
* @param tier The tier to query
|
||||
* @return True if isCorrectTierForDrops should be called for the tier
|
||||
*/
|
||||
public static boolean isTierSorted(Tier tier)
|
||||
{
|
||||
return getName(tier) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries if a tier is high enough to be able to get drops for the given blockstate.
|
||||
* @param tier The tier to look up
|
||||
* @param state The state to test against
|
||||
* @return True if the tier is good enough
|
||||
*/
|
||||
public static boolean isCorrectTierForDrops(Tier tier, BlockState state)
|
||||
{
|
||||
if (!isTierSorted(tier))
|
||||
return isCorrectTierVanilla(tier, state);
|
||||
|
||||
for (int x = sortedTiers.indexOf(tier) + 1; x < sortedTiers.size(); x++) {
|
||||
Tag<Block> tag = sortedTiers.get(x).getTag();
|
||||
if (tag != null && state.is(tag))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to query all tiers that are lower than the given tier
|
||||
* @param tier The tier
|
||||
* @return All the lower tiers
|
||||
*/
|
||||
public static List<Tier> getTiersLowerThan(Tier tier)
|
||||
{
|
||||
if (!isTierSorted(tier)) return List.of();
|
||||
return sortedTiers.stream().takeWhile(t -> t != tier).toList();
|
||||
}
|
||||
|
||||
// ===================== PRIVATE INTERNAL STUFFS BELOW THIS LINE =====================
|
||||
|
||||
/**
|
||||
* Fallback for when a tier isn't in the registry, copy of the logic in {@link DiggerItem#isCorrectToolForDrops}
|
||||
*/
|
||||
private static boolean isCorrectTierVanilla(Tier tier, BlockState state)
|
||||
{
|
||||
int i = tier.getLevel();
|
||||
if (i < 3 && state.is(BlockTags.NEEDS_DIAMOND_TOOL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (i < 2 && state.is(BlockTags.NEEDS_IRON_TOOL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (i < 1 && state.is(BlockTags.NEEDS_STONE_TOOL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void processTier(Tier tier, ResourceLocation name, List<Object> afters, List<Object> befores)
|
||||
{
|
||||
tiers.put(name, tier);
|
||||
for(Object after : afters)
|
||||
{
|
||||
ResourceLocation other = getTierName(after);
|
||||
edges.put(other, name);
|
||||
}
|
||||
for(Object before : befores)
|
||||
{
|
||||
ResourceLocation other = getTierName(before);
|
||||
edges.put(name, other);
|
||||
}
|
||||
}
|
||||
|
||||
private static ResourceLocation getTierName(Object entry)
|
||||
{
|
||||
if (entry instanceof String s)
|
||||
return new ResourceLocation(s);
|
||||
if (entry instanceof ResourceLocation rl)
|
||||
return rl;
|
||||
if (entry instanceof Tier t)
|
||||
return Objects.requireNonNull(getName(t), "Can't have sorting dependencies for tiers not registered in the TierSortingRegistry");
|
||||
throw new IllegalStateException("Invalid object type passed into the tier dependencies " + entry.getClass());
|
||||
}
|
||||
|
||||
private static boolean hasCustomTiers = false;
|
||||
private static final BiMap<ResourceLocation, Tier> tiers = HashBiMap.create();
|
||||
private static final Multimap<ResourceLocation, ResourceLocation> edges = HashMultimap.create();
|
||||
private static final Multimap<ResourceLocation, ResourceLocation> vanillaEdges = HashMultimap.create();
|
||||
|
||||
static {
|
||||
var wood = new ResourceLocation("wood");
|
||||
var stone = new ResourceLocation("stone");
|
||||
var iron = new ResourceLocation("iron");
|
||||
var diamond = new ResourceLocation("diamond");
|
||||
var netherite = new ResourceLocation("netherite");
|
||||
var gold = new ResourceLocation("gold");
|
||||
processTier(Tiers.WOOD, wood, List.of(), List.of());
|
||||
processTier(Tiers.GOLD, gold, List.of(wood), List.of(stone));
|
||||
processTier(Tiers.STONE, stone, List.of(wood), List.of(iron));
|
||||
processTier(Tiers.IRON, iron, List.of(stone), List.of(diamond));
|
||||
processTier(Tiers.DIAMOND, diamond, List.of(iron), List.of(netherite));
|
||||
processTier(Tiers.NETHERITE, netherite, List.of(diamond), List.of());
|
||||
vanillaEdges.putAll(edges);
|
||||
}
|
||||
|
||||
private static final List<Tier> sortedTiers = new ArrayList<>();
|
||||
private static final List<Tier> sortedTiersUnmodifiable = Collections.unmodifiableList(sortedTiers);
|
||||
|
||||
private static final ResourceLocation CHANNEL_NAME = new ResourceLocation("forge:tier_sorting");
|
||||
private static final String PROTOCOL_VERSION = "1.0";
|
||||
private static final SimpleChannel SYNC_CHANNEL = NetworkRegistry.newSimpleChannel(
|
||||
CHANNEL_NAME, () -> "1.0",
|
||||
versionFromServer -> PROTOCOL_VERSION.equals(versionFromServer) || (allowVanilla() && NetworkRegistry.ACCEPTVANILLA.equals(versionFromServer)),
|
||||
versionFromClient -> PROTOCOL_VERSION.equals(versionFromClient) || (allowVanilla() && NetworkRegistry.ACCEPTVANILLA.equals(versionFromClient))
|
||||
);
|
||||
|
||||
static boolean allowVanilla()
|
||||
{
|
||||
return !hasCustomTiers;
|
||||
}
|
||||
|
||||
/*package private*/
|
||||
static void init()
|
||||
{
|
||||
SYNC_CHANNEL.registerMessage(0, SyncPacket.class, SyncPacket::encode, TierSortingRegistry::receive, TierSortingRegistry::handle, Optional.of(NetworkDirection.PLAY_TO_CLIENT));
|
||||
MinecraftForge.EVENT_BUS.addListener(TierSortingRegistry::playerLoggedIn);
|
||||
if (FMLEnvironment.dist == Dist.CLIENT) ClientEvents.init();
|
||||
}
|
||||
|
||||
/*package private*/
|
||||
static PreparableReloadListener getReloadListener()
|
||||
{
|
||||
return new SimplePreparableReloadListener<JsonObject>()
|
||||
{
|
||||
static final ResourceLocation ITEM_TIER_ORDERING_JSON = new ResourceLocation("forge", "item_tier_ordering.json");
|
||||
|
||||
final Gson gson = (new GsonBuilder()).create();
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected JsonObject prepare(@Nonnull ResourceManager resourceManager, ProfilerFiller p)
|
||||
{
|
||||
if (!resourceManager.hasResource(ITEM_TIER_ORDERING_JSON))
|
||||
return new JsonObject();
|
||||
|
||||
try (Resource r = resourceManager.getResource(ITEM_TIER_ORDERING_JSON); InputStream stream = r.getInputStream(); Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)))
|
||||
{
|
||||
return gson.fromJson(reader, JsonObject.class);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.error("Could not read Tier sorting file " + ITEM_TIER_ORDERING_JSON, e);
|
||||
return new JsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(@Nonnull JsonObject data, @Nonnull ResourceManager resourceManager, ProfilerFiller p)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (data.size() > 0)
|
||||
{
|
||||
JsonArray order = GsonHelper.getAsJsonArray(data, "order");
|
||||
List<Tier> customOrder = new ArrayList<>();
|
||||
for (JsonElement entry : order)
|
||||
{
|
||||
ResourceLocation id = new ResourceLocation(entry.getAsString());
|
||||
Tier tier = byName(id);
|
||||
if (tier == null) throw new IllegalStateException("Tier not found with name " + id);
|
||||
customOrder.add(tier);
|
||||
}
|
||||
|
||||
List<Tier> missingTiers = tiers.values().stream().filter(tier -> !customOrder.contains(tier)).toList();
|
||||
if (missingTiers.size() > 0)
|
||||
throw new IllegalStateException("Tiers missing from the ordered list: " + missingTiers.stream().map(tier -> Objects.toString(TierSortingRegistry.getName(tier))).collect(Collectors.joining(", ")));
|
||||
|
||||
setTierOrder(customOrder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOGGER.error("Error parsing Tier sorting file " + ITEM_TIER_ORDERING_JSON, e);
|
||||
}
|
||||
|
||||
recalculateItemTiers();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
private static void recalculateItemTiers()
|
||||
{
|
||||
final MutableGraph<Tier> graph = GraphBuilder.directed().nodeOrder(ElementOrder.<Tier>insertion()).build();
|
||||
|
||||
for(Tier tier : tiers.values())
|
||||
{
|
||||
graph.addNode(tier);
|
||||
}
|
||||
edges.forEach((key, value) -> {
|
||||
if (tiers.containsKey(key) && tiers.containsKey(value))
|
||||
graph.putEdge(tiers.get(key), tiers.get(value));
|
||||
});
|
||||
List<Tier> tierList = TopologicalSort.topologicalSort(graph, null);
|
||||
|
||||
setTierOrder(tierList);
|
||||
}
|
||||
|
||||
private static void setTierOrder(List<Tier> tierList)
|
||||
{
|
||||
runInServerThreadIfPossible(hasServer -> {
|
||||
sortedTiers.clear();
|
||||
sortedTiers.addAll(tierList);
|
||||
if(hasServer) syncToAll();
|
||||
});
|
||||
}
|
||||
|
||||
private static void runInServerThreadIfPossible(BooleanConsumer runnable)
|
||||
{
|
||||
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
|
||||
if (server != null) server.execute(() -> runnable.accept(true));
|
||||
else runnable.accept(false);
|
||||
}
|
||||
|
||||
private static void syncToAll()
|
||||
{
|
||||
for(ServerPlayer serverPlayer : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers())
|
||||
{
|
||||
syncToPlayer(serverPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void playerLoggedIn(PlayerEvent.PlayerLoggedInEvent event)
|
||||
{
|
||||
if (event.getPlayer() instanceof ServerPlayer serverPlayer)
|
||||
{
|
||||
syncToPlayer(serverPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void syncToPlayer(ServerPlayer serverPlayer)
|
||||
{
|
||||
if (SYNC_CHANNEL.isRemotePresent(serverPlayer.connection.getConnection()) && !serverPlayer.connection.getConnection().isMemoryConnection())
|
||||
{
|
||||
SYNC_CHANNEL.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new SyncPacket(sortedTiers.stream().map(TierSortingRegistry::getName).toList()));
|
||||
}
|
||||
}
|
||||
|
||||
private static SyncPacket receive(FriendlyByteBuf buffer)
|
||||
{
|
||||
int count = buffer.readVarInt();
|
||||
List<ResourceLocation> list = new ArrayList<>();
|
||||
for(int i=0;i<count;i++)
|
||||
list.add(buffer.readResourceLocation());
|
||||
return new SyncPacket(list);
|
||||
}
|
||||
|
||||
private static void handle(SyncPacket packet, Supplier<NetworkEvent.Context> context)
|
||||
{
|
||||
setTierOrder(packet.tiers.stream().map(TierSortingRegistry::byName).toList());
|
||||
context.get().setPacketHandled(true);
|
||||
}
|
||||
|
||||
private record SyncPacket(List<ResourceLocation> tiers)
|
||||
{
|
||||
private void encode(FriendlyByteBuf buffer)
|
||||
{
|
||||
buffer.writeVarInt(tiers.size());
|
||||
for(ResourceLocation loc : tiers)
|
||||
buffer.writeResourceLocation(loc);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClientEvents
|
||||
{
|
||||
public static void init()
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.addListener(ClientEvents::clientLogInToServer);
|
||||
}
|
||||
|
||||
private static void clientLogInToServer(ClientPlayerNetworkEvent.LoggedInEvent event)
|
||||
{
|
||||
if (event.getNetworkManager() == null || !event.getNetworkManager().isMemoryConnection())
|
||||
recalculateItemTiers();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@SuppressWarnings("ClassCanBeRecord")
|
||||
public class ToolAction
|
||||
{
|
||||
private static final Map<String, ToolAction> actions = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Returns all registered actions.
|
||||
* This collection can be kept around, and will update itself in response to changes to the map.
|
||||
* See {@link ConcurrentHashMap#values()} for details.
|
||||
*/
|
||||
public static Collection<ToolAction> getActions()
|
||||
{
|
||||
return Collections.unmodifiableCollection(actions.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a new ToolAction for the given name.
|
||||
*/
|
||||
public static ToolAction get(String name)
|
||||
{
|
||||
return actions.computeIfAbsent(name, ToolAction::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this tool action
|
||||
*/
|
||||
public String name()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "ToolAction[" + name + "]";
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Use {@link #get(String)} to get or create a ToolAction
|
||||
*/
|
||||
private ToolAction(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraftforge.common.extensions.IForgeBlock;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ToolActions
|
||||
{
|
||||
/**
|
||||
* Exposed by axes to allow querying tool behaviours
|
||||
*/
|
||||
public static final ToolAction AXE_DIG = ToolAction.get("axe_dig");
|
||||
|
||||
/**
|
||||
* Exposed by pickaxes to allow querying tool behaviours
|
||||
*/
|
||||
public static final ToolAction PICKAXE_DIG = ToolAction.get("pickaxe_dig");
|
||||
|
||||
/**
|
||||
* Exposed by shovels to allow querying tool behaviours
|
||||
*/
|
||||
public static final ToolAction SHOVEL_DIG = ToolAction.get("shovel_dig");
|
||||
|
||||
/**
|
||||
* Exposed by shovels to allow querying tool behaviours
|
||||
*/
|
||||
public static final ToolAction HOE_DIG = ToolAction.get("hoe_dig");
|
||||
|
||||
/**
|
||||
* Exposed by swords to allow querying tool behaviours
|
||||
*/
|
||||
public static final ToolAction SWORD_DIG = ToolAction.get("sword_dig");
|
||||
|
||||
/**
|
||||
* Passed onto {@link IForgeBlock#getToolModifiedState} when an axe wants to strip a log
|
||||
*/
|
||||
public static final ToolAction AXE_STRIP = ToolAction.get("axe_strip");
|
||||
|
||||
/**
|
||||
* Passed onto {@link IForgeBlock#getToolModifiedState} when an axe wants to scrape oxidization off copper
|
||||
*/
|
||||
public static final ToolAction AXE_SCRAPE = ToolAction.get("axe_scrape");
|
||||
|
||||
/**
|
||||
* Passed onto {@link IForgeBlock#getToolModifiedState} when an axe wants to remove wax out of copper
|
||||
*/
|
||||
public static final ToolAction AXE_WAX_OFF = ToolAction.get("axe_wax_off");
|
||||
|
||||
/**
|
||||
* Passed onto {@link IForgeBlock#getToolModifiedState} when a shovel wants to turn dirt into path
|
||||
*/
|
||||
public static final ToolAction SHOVEL_FLATTEN = ToolAction.get("shovel_flatten");
|
||||
|
||||
///**
|
||||
// * Passed onto {@link IForgeBlock#getToolModifiedState} when a hoe wants to turn dirt into soil
|
||||
// */
|
||||
// TODO: public static final ToolAction HOE_TILL = ToolAction.get("till");
|
||||
|
||||
|
||||
// Default actions supported by each tool type
|
||||
public static final Set<ToolAction> DEFAULT_AXE_ACTIONS = Stream.of(AXE_DIG, AXE_STRIP, AXE_SCRAPE, AXE_WAX_OFF).collect(Collectors.toCollection(Sets::newIdentityHashSet));
|
||||
public static final Set<ToolAction> DEFAULT_HOE_ACTIONS = Stream.of(HOE_DIG /* TODO: , HOE_TILL */).collect(Collectors.toCollection(Sets::newIdentityHashSet));
|
||||
public static final Set<ToolAction> DEFAULT_SHOVEL_ACTIONS = Stream.of(SHOVEL_DIG, SHOVEL_FLATTEN).collect(Collectors.toCollection(Sets::newIdentityHashSet));
|
||||
public static final Set<ToolAction> DEFAULT_PICKAXE_ACTIONS = Stream.of(PICKAXE_DIG).collect(Collectors.toCollection(Sets::newIdentityHashSet));
|
||||
public static final Set<ToolAction> DEFAULT_SWORD_ACTIONS = Stream.of(SWORD_DIG).collect(Collectors.toCollection(Sets::newIdentityHashSet));
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class ToolType
|
||||
{
|
||||
private static final Pattern VALID_NAME = Pattern.compile("[^a-z_]"); //Only a-z and _ are allowed, meaning names must be lower case. And use _ to separate words.
|
||||
private static final Map<String, ToolType> VALUES = new ConcurrentHashMap<>();
|
||||
|
||||
public static final ToolType AXE = get("axe");
|
||||
public static final ToolType HOE = get("hoe");
|
||||
public static final ToolType PICKAXE = get("pickaxe");
|
||||
public static final ToolType SHOVEL = get("shovel");
|
||||
|
||||
/**
|
||||
* Gets the ToolType for the specified name, or creates a new one if none for that name does yet exist.
|
||||
* This method can be called during parallel loading
|
||||
*/
|
||||
public static ToolType get(String name)
|
||||
{
|
||||
return VALUES.computeIfAbsent(name, k ->
|
||||
{
|
||||
if (VALID_NAME.matcher(name).find())
|
||||
throw new IllegalArgumentException("ToolType.get() called with invalid name: " + name);
|
||||
return new ToolType(name);
|
||||
});
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
private ToolType(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -32,25 +32,19 @@ import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||
import net.minecraft.world.entity.boss.wither.WitherBoss;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.WitherSkull;
|
||||
import net.minecraft.world.level.block.LadderBlock;
|
||||
import net.minecraft.world.level.block.TrapDoorBlock;
|
||||
import net.minecraft.world.item.*;
|
||||
import net.minecraft.world.level.block.*;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.item.AxeItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.ShovelItem;
|
||||
import net.minecraft.world.level.pathfinder.BlockPathTypes;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.IPlantable;
|
||||
import net.minecraftforge.common.Tags;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
@@ -58,18 +52,9 @@ import net.minecraft.world.level.Explosion;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.BeaconBeamBlock;
|
||||
import net.minecraft.world.level.block.BedBlock;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.FarmBlock;
|
||||
import net.minecraft.world.level.block.FenceGateBlock;
|
||||
import net.minecraft.world.level.block.FireBlock;
|
||||
import net.minecraft.world.level.block.HalfTransparentBlock;
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||
import net.minecraft.world.level.block.LeavesBlock;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
import net.minecraftforge.common.ToolActions;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public interface IForgeBlock
|
||||
@@ -163,7 +148,7 @@ public interface IForgeBlock
|
||||
*/
|
||||
default public boolean canHarvestBlock(BlockState state, BlockGetter world, BlockPos pos, Player player)
|
||||
{
|
||||
return ForgeHooks.canHarvestBlock(state, player, world, pos);
|
||||
return ForgeHooks.isCorrectToolForDrops(state, player);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -461,31 +446,6 @@ public interface IForgeBlock
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the class of tool required to harvest this block, if null is returned
|
||||
* we assume that anything can harvest this block.
|
||||
*/
|
||||
ToolType getHarvestTool(BlockState state);
|
||||
|
||||
/**
|
||||
* Queries the harvest level of this item stack for the specified tool class,
|
||||
* Returns -1 if this tool is not of the specified type
|
||||
*
|
||||
* @return Harvest level, or -1 if not the specified tool type.
|
||||
*/
|
||||
int getHarvestLevel(BlockState state);
|
||||
|
||||
/**
|
||||
* Checks if the specified tool type is efficient on this block,
|
||||
* meaning that it digs at full speed.
|
||||
*/
|
||||
default boolean isToolEffective(BlockState state, ToolType tool)
|
||||
{
|
||||
if (tool == ToolType.PICKAXE && (self() == Blocks.REDSTONE_ORE || self() == Blocks.REDSTONE_LAMP || self() == Blocks.OBSIDIAN))
|
||||
return false;
|
||||
return tool == getHarvestTool(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensitive version of getSoundType
|
||||
* @param state The state
|
||||
@@ -729,14 +689,21 @@ public interface IForgeBlock
|
||||
* @param pos The block position in world
|
||||
* @param player The player clicking the block
|
||||
* @param stack The stack being used by the player
|
||||
* @param toolAction The action being performed by the tool
|
||||
* @return The resulting state after the action has been performed
|
||||
*/
|
||||
@Nullable
|
||||
default BlockState getToolModifiedState(BlockState state, Level world, BlockPos pos, Player player, ItemStack stack, ToolType toolType)
|
||||
default BlockState getToolModifiedState(BlockState state, Level world, BlockPos pos, Player player, ItemStack stack, ToolAction toolAction)
|
||||
{
|
||||
if (toolType == ToolType.AXE) return AxeItem.getAxeStrippingState(state);
|
||||
// else if(toolType == ToolType.HOE) return HoeItem.getHoeTillingState(state); //TODO HoeItem bork
|
||||
else return toolType == ToolType.SHOVEL ? ShovelItem.getShovelPathingState(state) : null;
|
||||
if (!stack.canPerformAction(toolAction)) return null;
|
||||
if (ToolActions.AXE_STRIP.equals(toolAction)) return AxeItem.getAxeStrippingState(state);
|
||||
else if(ToolActions.AXE_SCRAPE.equals(toolAction)) return WeatheringCopper.getPrevious(state).orElse(null);
|
||||
else if(ToolActions.AXE_WAX_OFF.equals(toolAction)) return Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(state.getBlock())).map((p_150694_) -> {
|
||||
return p_150694_.withPropertiesOf(state);
|
||||
}).orElse(null);
|
||||
//else if(ToolActions.HOE_TILL.equals(toolAction)) return HoeItem.getHoeTillingState(state); //TODO HoeItem bork
|
||||
else if (ToolActions.SHOVEL_FLATTEN.equals(toolAction)) return ShovelItem.getShovelPathingState(state);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,6 @@ import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraftforge.common.IPlantable;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
@@ -48,6 +47,7 @@ import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
|
||||
public interface IForgeBlockState
|
||||
{
|
||||
@@ -387,29 +387,6 @@ public interface IForgeBlockState
|
||||
return self().getBlock().getWeakChanges(self(), world, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the class of tool required to harvest this block, if null is returned
|
||||
* we assume that anything can harvest this block.
|
||||
*/
|
||||
default ToolType getHarvestTool()
|
||||
{
|
||||
return self().getBlock().getHarvestTool(self());
|
||||
}
|
||||
|
||||
default int getHarvestLevel()
|
||||
{
|
||||
return self().getBlock().getHarvestLevel(self());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified tool type is efficient on this block,
|
||||
* meaning that it digs at full speed.
|
||||
*/
|
||||
default boolean isToolEffective(ToolType tool)
|
||||
{
|
||||
return self().getBlock().isToolEffective(self(), tool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sensitive version of getSoundType
|
||||
* @param world The world
|
||||
@@ -648,10 +625,10 @@ public interface IForgeBlockState
|
||||
* @return The resulting state after the action has been performed
|
||||
*/
|
||||
@Nullable
|
||||
default BlockState getToolModifiedState(Level world, BlockPos pos, Player player, ItemStack stack, ToolType toolType)
|
||||
default BlockState getToolModifiedState(Level world, BlockPos pos, Player player, ItemStack stack, ToolAction toolAction)
|
||||
{
|
||||
BlockState eventState = net.minecraftforge.event.ForgeEventFactory.onToolUse(self(), world, pos, player, stack, toolType);
|
||||
return eventState != self() ? eventState : self().getBlock().getToolModifiedState(self(), world, pos, player, stack, toolType);
|
||||
BlockState eventState = net.minecraftforge.event.ForgeEventFactory.onToolUse(self(), world, pos, player, stack, toolAction);
|
||||
return eventState != self() ? eventState : self().getBlock().getToolModifiedState(self(), world, pos, player, stack, toolAction);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package net.minecraftforge.common.extensions;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -26,6 +27,9 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import net.minecraft.tags.Tag;
|
||||
import net.minecraft.world.item.*;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -37,14 +41,7 @@ import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.monster.EnderMan;
|
||||
import net.minecraft.world.entity.monster.piglin.PiglinAi;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.ArmorMaterials;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.AxeItem;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -54,7 +51,8 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
|
||||
// TODO review most of the methods in this "patch"
|
||||
public interface IForgeItem
|
||||
@@ -519,14 +517,26 @@ public interface IForgeItem
|
||||
stack.getOrCreateTag().putInt("Damage", Math.max(0, damage));
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries if an item can perform the given action.
|
||||
* See {@link net.minecraftforge.common.ToolActions} for a description of each stock action
|
||||
* @param stack The stack being used
|
||||
* @param toolAction The action being queried
|
||||
* @return True if the stack can perform the action
|
||||
*/
|
||||
default boolean canPerformAction(ItemStack stack, ToolAction toolAction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* ItemStack sensitive version of {@link #canHarvestBlock(IBlockState)}
|
||||
*
|
||||
* @param stack The itemstack used to harvest the block
|
||||
* @param state The block trying to harvest
|
||||
* @return true if can harvest the block
|
||||
* @return true if the stack can harvest the block
|
||||
*/
|
||||
default boolean canHarvestBlock(ItemStack stack, BlockState state)
|
||||
default boolean isCorrectToolForDrops(ItemStack stack, BlockState state)
|
||||
{
|
||||
return self().isCorrectToolForDrops(state);
|
||||
}
|
||||
@@ -544,20 +554,6 @@ public interface IForgeItem
|
||||
return self().getMaxStackSize();
|
||||
}
|
||||
|
||||
Set<ToolType> getToolTypes(ItemStack stack);
|
||||
|
||||
/**
|
||||
* Queries the harvest level of this item stack for the specified tool class,
|
||||
* Returns -1 if this tool is not of the specified type
|
||||
*
|
||||
* @param stack This item stack instance
|
||||
* @param toolClass Tool Class
|
||||
* @param player The player trying to harvest the given blockstate
|
||||
* @param blockState The block to harvest
|
||||
* @return Harvest level, or -1 if not the specified tool type.
|
||||
*/
|
||||
int getHarvestLevel(ItemStack stack, ToolType tool, @Nullable Player player, @Nullable BlockState blockState);
|
||||
|
||||
/**
|
||||
* ItemStack sensitive version of getItemEnchantability
|
||||
*
|
||||
|
||||
@@ -19,14 +19,15 @@
|
||||
|
||||
package net.minecraftforge.common.extensions;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.tags.Tag;
|
||||
import net.minecraft.world.entity.monster.EnderMan;
|
||||
import net.minecraft.world.item.Tier;
|
||||
import net.minecraft.world.item.crafting.RecipeType;
|
||||
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
|
||||
import net.minecraft.world.item.enchantment.Enchantment;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
@@ -43,9 +44,11 @@ import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Extension added to ItemStack that bounces to ItemSack sensitive Item methods. Typically this is just for convince.
|
||||
*/
|
||||
@@ -88,24 +91,6 @@ public interface IForgeItemStack extends ICapabilitySerializable<CompoundTag>
|
||||
return self().getItem().getBurnTime(self(), recipeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the harvest level of this item stack for the specified tool class,
|
||||
* Returns -1 if this tool is not of the specified type
|
||||
*
|
||||
* @param tool the tool type of the item
|
||||
* @param player The player trying to harvest the given blockstate
|
||||
* @param state The block to harvest
|
||||
* @return Harvest level, or -1 if not the specified tool type.
|
||||
*/
|
||||
default int getHarvestLevel(ToolType tool, @Nullable Player player, @Nullable BlockState state)
|
||||
{
|
||||
return self().getItem().getHarvestLevel(self(), tool, player, state);
|
||||
}
|
||||
|
||||
default Set<ToolType> getToolTypes() {
|
||||
return self().getItem().getToolTypes(self());
|
||||
}
|
||||
|
||||
default InteractionResult onItemUseFirst(UseOnContext context)
|
||||
{
|
||||
Player entityplayer = context.getPlayer();
|
||||
@@ -130,6 +115,19 @@ public interface IForgeItemStack extends ICapabilitySerializable<CompoundTag>
|
||||
self().save(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries if an item can perform the given action.
|
||||
* See {@link net.minecraftforge.common.ToolActions} for a description of each stock action
|
||||
* @param stack The stack being used
|
||||
* @param toolAction The action being queried
|
||||
* @return True if the stack can perform the action
|
||||
*/
|
||||
default boolean canPerformAction(ToolAction toolAction)
|
||||
{
|
||||
return self().getItem().canPerformAction(self(), toolAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before a block is broken. Return true to prevent default block
|
||||
* harvesting.
|
||||
|
||||
@@ -91,7 +91,7 @@ import net.minecraftforge.client.event.ClientChatReceivedEvent;
|
||||
import net.minecraftforge.client.event.RenderBlockOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderBlockOverlayEvent.OverlayType;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
import net.minecraftforge.common.capabilities.CapabilityDispatcher;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.BlockSnapshot;
|
||||
@@ -361,9 +361,9 @@ public class ForgeEventFactory
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BlockState onToolUse(BlockState originalState, Level world, BlockPos pos, Player player, ItemStack stack, ToolType toolType)
|
||||
public static BlockState onToolUse(BlockState originalState, Level world, BlockPos pos, Player player, ItemStack stack, ToolAction toolAction)
|
||||
{
|
||||
BlockToolInteractEvent event = new BlockToolInteractEvent(world, pos, originalState, player, stack, toolType);
|
||||
BlockToolInteractEvent event = new BlockToolInteractEvent(world, pos, originalState, player, stack, toolAction);
|
||||
return MinecraftForge.EVENT_BUS.post(event) ? null : event.getFinalState();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
import net.minecraftforge.common.util.BlockSnapshot;
|
||||
import net.minecraftforge.eventbus.api.Cancelable;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
@@ -45,8 +45,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event.HasResult;
|
||||
|
||||
public class BlockEvent extends Event
|
||||
{
|
||||
private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("forge.debugBlockEvent", "false"));
|
||||
@@ -92,7 +90,7 @@ public class BlockEvent extends Event
|
||||
super(world, pos, state);
|
||||
this.player = player;
|
||||
|
||||
if (state == null || !ForgeHooks.canHarvestBlock(state, player, world, pos)) // Handle empty block or player unable to break block scenario
|
||||
if (state == null || !ForgeHooks.isCorrectToolForDrops(state, player)) // Handle empty block or player unable to break block scenario
|
||||
{
|
||||
this.exp = 0;
|
||||
}
|
||||
@@ -445,16 +443,16 @@ public class BlockEvent extends Event
|
||||
|
||||
private final Player player;
|
||||
private final ItemStack stack;
|
||||
private final ToolType toolType;
|
||||
private final ToolAction toolAction;
|
||||
private BlockState state;
|
||||
|
||||
public BlockToolInteractEvent(LevelAccessor world, BlockPos pos, BlockState originalState, Player player, ItemStack stack, ToolType toolType)
|
||||
public BlockToolInteractEvent(LevelAccessor world, BlockPos pos, BlockState originalState, Player player, ItemStack stack, ToolAction toolAction)
|
||||
{
|
||||
super(world, pos, originalState);
|
||||
this.player = player;
|
||||
this.stack = stack;
|
||||
this.state = originalState;
|
||||
this.toolType = toolType;
|
||||
this.toolAction = toolAction;
|
||||
}
|
||||
|
||||
/**Gets the player using the tool.*/
|
||||
@@ -469,10 +467,10 @@ public class BlockEvent extends Event
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**Gets the current type of the tool being compared against.*/
|
||||
public ToolType getToolType()
|
||||
/**Gets the action being performed.*/
|
||||
public ToolAction getToolAction()
|
||||
{
|
||||
return toolType;
|
||||
return toolAction;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user