Env Collector recipe and datagen

This commit is contained in:
Robin Bärtschi 2024-06-04 08:26:54 +02:00
parent 29ce7ddc77
commit 351d05cbf5
16 changed files with 320 additions and 87 deletions

View File

@ -3,6 +3,7 @@ plugins {
eclipse
idea
`maven-publish`
id("io.freefair.lombok") version "8.6"
id ("net.neoforged.gradle.userdev") version ("7.0.138")
}

View File

@ -0,0 +1,3 @@
// 1.20.6 2024-06-04T08:11:35.3127563 Recipes
a8f75064cc52045c05943428b359d7c7ef8967dc data/environmenttech/advancements/recipes/environmental_essence.json
d462a41d1b0fda35660ed3e4c807f83f6dc0e0cd data/environmenttech/recipes/environmental_essence.json

View File

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_the_recipe": {
"conditions": {
"recipe": "environmenttech:environmental_essence"
},
"trigger": "minecraft:recipe_unlocked"
},
"iron_ingot": {
"conditions": {
"items": [
{
"items": "minecraft:iron_ingot"
}
]
},
"trigger": "minecraft:inventory_changed"
}
},
"requirements": [
[
"has_the_recipe",
"iron_ingot"
]
],
"rewards": {
"recipes": [
"environmenttech:environmental_essence"
]
}
}

View File

@ -0,0 +1,11 @@
{
"type": "environmenttech:env_collector",
"envUsed": 10,
"ingredient": {
"item": "minecraft:iron_ingot"
},
"output": {
"count": 1,
"id": "environmenttech:environmental_essence"
}
}

View File

@ -2,16 +2,11 @@ package robaertschi.environmenttech;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.config.ModConfigEvent;
import net.neoforged.neoforge.common.ModConfigSpec;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
// An example config class. This is not required, but it's a good idea to have one to keep your config organized.
// Demonstrates how to use Neo's config APIs
@EventBusSubscriber(modid = EnvironmentTech.MODID, bus = EventBusSubscriber.Bus.MOD)
@ -27,30 +22,9 @@ public class Config
.comment("How much is the minimum of allowed ENV in a chunk.")
.defineInRange("minEnvForNewChunk", 0, 0, 1024);
private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
.comment("Whether to log the dirt block on common setup")
.define("logDirtBlock", true);
private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER
.comment("A magic number")
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
public static final ModConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
.comment("What you want the introduction message to be for the magic number")
.define("magicNumberIntroduction", "The magic number is... ");
// a list of strings that are treated as resource locations for items
private static final ModConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
.comment("A list of items to log on common setup.")
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName);
static final ModConfigSpec SPEC = BUILDER.build();
public static boolean logDirtBlock;
public static int magicNumber;
public static String magicNumberIntroduction;
public static Set<Item> items;
public static int maxEnvForNewChunk;
public static int minEnvForNewChunk;
@ -62,17 +36,8 @@ public class Config
@SubscribeEvent
static void onLoad(final ModConfigEvent event)
{
logDirtBlock = LOG_DIRT_BLOCK.get();
magicNumber = MAGIC_NUMBER.get();
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
maxEnvForNewChunk = MAX_ENV_FOR_NEW_CHUNK.get();
minEnvForNewChunk = MIN_ENV_FOR_NEW_CHUNK.get();
// convert the list of strings into a set of items
items = ITEM_STRINGS.get().stream()
.map(itemName -> BuiltInRegistries.ITEM.get(new ResourceLocation(itemName)))
.collect(Collectors.toSet());
}
}

View File

@ -1,20 +1,7 @@
package robaertschi.environmenttech;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
@ -25,21 +12,15 @@ import net.neoforged.fml.config.ModConfig;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import net.neoforged.neoforge.event.server.ServerStartingEvent;
import net.neoforged.neoforge.event.tick.PlayerTickEvent;
import net.neoforged.neoforge.registries.DeferredBlock;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister;
import org.slf4j.Logger;
import robaertschi.environmenttech.data.attachments.ETAttachments;
import robaertschi.environmenttech.data.capabilities.ETCapabilities;
import robaertschi.environmenttech.data.recipes.ETRecipes;
import robaertschi.environmenttech.level.block.ETBlocks;
import robaertschi.environmenttech.level.item.ETItems;
import java.io.IOException;
@Mod(EnvironmentTech.MODID)
public class EnvironmentTech
{
@ -62,6 +43,7 @@ public class EnvironmentTech
ETCapabilities.init(modEventBus);
ETBlocks.init(modEventBus);
ETItems.init(modEventBus);
ETRecipes.init(modEventBus);
NeoForge.EVENT_BUS.register(this);
@ -69,15 +51,6 @@ public class EnvironmentTech
private void commonSetup(final FMLCommonSetupEvent event)
{
// Some common setup code
LOGGER.info("HELLO FROM COMMON SETUP");
if (Config.logDirtBlock)
LOGGER.info("DIRT BLOCK >> {}", BuiltInRegistries.BLOCK.getKey(Blocks.DIRT));
LOGGER.info("{}{}", Config.magicNumberIntroduction, Config.magicNumber);
Config.items.forEach((item) -> LOGGER.info("ITEM >> {}", item.toString()));
}
@ -87,7 +60,7 @@ public class EnvironmentTech
}
@SubscribeEvent()
public void onPlayerTick(PlayerTickEvent.Post event) throws IOException {
public void onPlayerTick(PlayerTickEvent.Post event) {
var level = event.getEntity().level();
if (level.isClientSide()) {
return;

View File

@ -2,36 +2,38 @@ package robaertschi.environmenttech.data.capabilities;
import net.minecraft.util.Mth;
// TODO: Add max receive or something
public class EnvStorage implements IEnvStorage {
private final EnvType[] acceptedEnvTypes;
private final long maxEnv;
private long env;
private long maxTransfer;
public EnvStorage(EnvType acceptedEnvType, long maxEnv, long env) {
public EnvStorage(EnvType acceptedEnvType, long maxEnv, long env, long maxTransfer) {
this.acceptedEnvTypes = new EnvType[1];
this.acceptedEnvTypes[0] = acceptedEnvType;
this.maxEnv = maxEnv;
this.env = env;
this.maxTransfer = maxTransfer;
}
public EnvStorage(EnvType acceptedEnvType, long maxEnv) {
this(acceptedEnvType, maxEnv, 0);
this(acceptedEnvType, maxEnv, 0, maxEnv);
}
public EnvStorage(EnvType[] acceptedEnvTypes, long maxEnv, long env) {
public EnvStorage(EnvType[] acceptedEnvTypes, long maxEnv, long env, long maxTransfer) {
this.acceptedEnvTypes = acceptedEnvTypes;
this.maxEnv = maxEnv;
this.env = env;
this.maxTransfer = maxTransfer;
}
public EnvStorage(EnvType[] acceptedEnvTypes, long maxEnv) {
this(acceptedEnvTypes, maxEnv, 0);
this(acceptedEnvTypes, maxEnv, 0, maxEnv);
}
@Override
public long receiveEnv(long amount, boolean simulate) {
long received = Mth.clamp(this.maxEnv - this.env, 0, amount);
long received = Mth.clamp(this.maxEnv - this.env, 0, Math.min(amount, maxTransfer));
if (!simulate)
env += received;

View File

@ -0,0 +1,23 @@
package robaertschi.environmenttech.data.recipes;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import static robaertschi.environmenttech.EnvironmentTech.MODID;
public class ETRecipes {
public static final DeferredRegister<RecipeType<?>> RECIPE_TYPES = DeferredRegister.create(Registries.RECIPE_TYPE, MODID);
public static final DeferredRegister<RecipeSerializer<?>> RECIPE_SERIALIZERS = DeferredRegister.create(Registries.RECIPE_SERIALIZER, MODID);
public static final DeferredHolder<RecipeType<?>, RecipeType<EnvCollectorRecipe>> ENV_COLLECTOR_RECIPE_TYPE = RECIPE_TYPES.register("env_collector", RecipeType::simple);
public static final DeferredHolder<RecipeSerializer<?>, RecipeSerializer<EnvCollectorRecipe>> ENV_COLLECTOR_RECIPE_SERIALIZER = RECIPE_SERIALIZERS.register("env_collector", EnvCollectorRecipeSerializer::new);
public static void init(IEventBus modEventBus) {
RECIPE_TYPES.register(modEventBus);
RECIPE_SERIALIZERS.register(modEventBus);
}
}

View File

@ -0,0 +1,109 @@
package robaertschi.environmenttech.data.recipes;
import lombok.RequiredArgsConstructor;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementRequirements;
import net.minecraft.advancements.AdvancementRewards;
import net.minecraft.advancements.Criterion;
import net.minecraft.advancements.critereon.RecipeUnlockedTrigger;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.recipes.RecipeBuilder;
import net.minecraft.data.recipes.RecipeOutput;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Map;
public record EnvCollectorRecipe(Ingredient input, ItemStack output, int envUsed) implements Recipe<Container> {
@Override
public boolean matches(@NotNull Container pContainer, @NotNull Level pLevel) {
return this.input.test(pContainer.getItem(0));
}
@Override
public @NotNull ItemStack assemble(@NotNull Container pCraftingContainer, HolderLookup.@NotNull Provider pRegistries) {
return this.output.copy();
}
@Override
public boolean canCraftInDimensions(int pWidth, int pHeight) {
return true;
}
@Override
public @NotNull ItemStack getResultItem(@NotNull HolderLookup.Provider pRegistries) {
return this.output;
}
@Override
public @NotNull RecipeSerializer<?> getSerializer() {
return ETRecipes.ENV_COLLECTOR_RECIPE_SERIALIZER.get();
}
@Override
public @NotNull RecipeType<?> getType() {
return ETRecipes.ENV_COLLECTOR_RECIPE_TYPE.get();
}
@RequiredArgsConstructor
public static class Builder implements RecipeBuilder {
private final Ingredient ingredient;
private final ItemStack output;
private final int envUsed;
private final Map<String, Criterion<?>> criteria = new LinkedHashMap<>();
// Currently we just ignore the warning, maybe we will use it later, maybe never.
@SuppressWarnings("FieldCanBeLocal")
@Nullable
private String group;
@Override
public @NotNull RecipeBuilder group(@Nullable String pGroupName) {
this.group = pGroupName;
return this;
}
@Override
public @NotNull Item getResult() {
return this.output.getItem();
}
public @NotNull Builder unlockedBy(@NotNull String name, @NotNull Criterion<?> criterion) {
this.criteria.put(name, criterion);
return this;
}
@Override
public void save(RecipeOutput pRecipeOutput, @NotNull ResourceLocation pId) {
this.ensureValid(pId);
Advancement.Builder advancementBuilder = pRecipeOutput.advancement()
.addCriterion("has_the_recipe", RecipeUnlockedTrigger.unlocked(pId))
.rewards(AdvancementRewards.Builder.recipe(pId))
.requirements(AdvancementRequirements.Strategy.OR);
this.criteria.forEach(advancementBuilder::addCriterion);
EnvCollectorRecipe envCollectorRecipe = new EnvCollectorRecipe(this.ingredient, this.output, this.envUsed);
pRecipeOutput.accept(pId, envCollectorRecipe, advancementBuilder.build(pId.withPrefix("recipes/")));
}
private void ensureValid(ResourceLocation pId) {
if (this.criteria.isEmpty()) {
throw new IllegalStateException("No way of obtaining recipe " + pId);
}
}
}
}

View File

@ -0,0 +1,45 @@
package robaertschi.environmenttech.data.recipes;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import org.jetbrains.annotations.NotNull;
public class EnvCollectorRecipeSerializer implements RecipeSerializer<EnvCollectorRecipe> {
public static final MapCodec<EnvCollectorRecipe> CODEC = RecordCodecBuilder.mapCodec(
envCollectorRecipeInstance -> envCollectorRecipeInstance.group(
Ingredient.CODEC_NONEMPTY.fieldOf("ingredient").forGetter(EnvCollectorRecipe::input),
ItemStack.CODEC.fieldOf("output").forGetter(EnvCollectorRecipe::output),
Codec.INT.fieldOf("envUsed").forGetter(EnvCollectorRecipe::envUsed)
).apply(envCollectorRecipeInstance, EnvCollectorRecipe::new)
);
public final StreamCodec<RegistryFriendlyByteBuf, EnvCollectorRecipe> streamCodec = StreamCodec.of(this::toNetwork, this::fromNetwork);
@Override
public @NotNull MapCodec<EnvCollectorRecipe> codec() {
return CODEC;
}
@Override
public @NotNull StreamCodec<RegistryFriendlyByteBuf, EnvCollectorRecipe> streamCodec() {
return streamCodec;
}
private EnvCollectorRecipe fromNetwork(RegistryFriendlyByteBuf byteBuf) {
Ingredient ingredient = Ingredient.CONTENTS_STREAM_CODEC.decode(byteBuf);
ItemStack itemStack = ItemStack.STREAM_CODEC.decode(byteBuf);
int envUsed = byteBuf.readInt();
return new EnvCollectorRecipe(ingredient, itemStack, envUsed);
}
private void toNetwork(RegistryFriendlyByteBuf byteBuf, EnvCollectorRecipe recipe) {
Ingredient.CONTENTS_STREAM_CODEC.encode(byteBuf, recipe.input());
ItemStack.STREAM_CODEC.encode(byteBuf, recipe.output());
byteBuf.writeInt(recipe.envUsed());
}
}

View File

@ -0,0 +1,29 @@
package robaertschi.environmenttech.datagen;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.PackOutput;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
import net.neoforged.neoforge.data.event.GatherDataEvent;
import java.util.concurrent.CompletableFuture;
import static robaertschi.environmenttech.EnvironmentTech.MODID;
@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD, modid = MODID)
public class ETDatagen {
@SubscribeEvent()
public static void gatherData(GatherDataEvent event) {
DataGenerator generator = event.getGenerator();
PackOutput output = generator.getPackOutput();
ExistingFileHelper existingFileHelper = event.getExistingFileHelper();
CompletableFuture<HolderLookup.Provider> lookupProvider = event.getLookupProvider();
generator.addProvider(
event.includeServer(),
new ETRecipeProvider(output, lookupProvider)
);
}
}

View File

@ -0,0 +1,33 @@
package robaertschi.environmenttech.datagen;
import net.minecraft.advancements.critereon.InventoryChangeTrigger;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.data.recipes.RecipeOutput;
import net.minecraft.data.recipes.RecipeProvider;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import org.jetbrains.annotations.NotNull;
import robaertschi.environmenttech.data.recipes.EnvCollectorRecipe;
import robaertschi.environmenttech.level.item.ETItems;
import java.util.concurrent.CompletableFuture;
public class ETRecipeProvider extends RecipeProvider {
public ETRecipeProvider(PackOutput pOutput, CompletableFuture<HolderLookup.Provider> pRegistries) {
super(pOutput, pRegistries);
}
@Override
protected void buildRecipes(@NotNull RecipeOutput recipeOutput) {
new EnvCollectorRecipe.Builder(
Ingredient.of(Items.IRON_INGOT),
new ItemStack(ETItems.ENVIRONMENTAL_ESSENCE_ITEM.get()),
10
).unlockedBy(
"iron_ingot",
InventoryChangeTrigger.TriggerInstance.hasItems(Items.IRON_INGOT)
).save(recipeOutput);
}
}

View File

@ -2,15 +2,16 @@ package robaertschi.environmenttech.level.block;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import robaertschi.environmenttech.level.block.entity.ETBlockEntities;
import robaertschi.environmenttech.level.block.entity.EnvCollectorBlockEntity;
import javax.annotation.ParametersAreNonnullByDefault;
@ -39,4 +40,10 @@ public class EnvCollectorBlock extends BaseEntityBlock {
public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {
return new EnvCollectorBlockEntity(pPos, pState);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {
return createTickerHelper(pBlockEntityType, ETBlockEntities.ENV_COLLECTOR_BLOCK_ENTITY.get(), EnvCollectorBlockEntity::tick);
}
}

View File

@ -1,17 +1,19 @@
package robaertschi.environmenttech.level.block.entity;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.registries.DeferredHolder;
public class EnvCollectorBlockEntity extends BlockEntity {
public EnvCollectorBlockEntity(BlockEntityType<EnvCollectorBlockEntity> pType, BlockPos pPos, BlockState pBlockState) {
super(pType, pPos, pBlockState);
}
private int progress = 0;
public EnvCollectorBlockEntity(BlockPos pos, BlockState state) {
this(ETBlockEntities.ENV_COLLECTOR_BLOCK_ENTITY.get(), pos, state);
super(ETBlockEntities.ENV_COLLECTOR_BLOCK_ENTITY.get(), pos, state);
}
public static void tick(Level level, BlockPos blockPos, BlockState blockState, EnvCollectorBlockEntity envCollectorBlockEntity) {
}
}

View File

@ -34,7 +34,7 @@ public class ETItems {
.durability(10)
);
public static final DeferredItem<Item> ENVIRONMENTAL_ESSENCE = ITEMS.registerSimpleItem("environmental_essence");
public static final DeferredItem<Item> ENVIRONMENTAL_ESSENCE_ITEM = ITEMS.registerSimpleItem("environmental_essence");
@SuppressWarnings("unused")
@ -45,7 +45,7 @@ public class ETItems {
.displayItems((parameters, output) -> {
output.accept(ENV_DETECTOR_ITEM.get());
output.accept(EXAMPLE_BLOCK_ITEM.get());
output.accept(ENVIRONMENTAL_ESSENCE.get());
output.accept(ENVIRONMENTAL_ESSENCE_ITEM.get());
}).build());

View File

@ -4,11 +4,11 @@ import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import robaertschi.environmenttech.data.attachments.ETAttachments;
import javax.annotation.ParametersAreNonnullByDefault;
@ -21,7 +21,7 @@ public class EnvDetectorItem extends Item {
@Override
public InteractionResultHolder<ItemStack> use(Level pLevel, Player pPlayer, InteractionHand pUsedHand) {
public @NotNull InteractionResultHolder<ItemStack> use(Level pLevel, Player pPlayer, InteractionHand pUsedHand) {
if (pLevel.isClientSide()) return InteractionResultHolder.pass(pPlayer.getItemInHand(pUsedHand));
var chunk = pLevel.getChunk(pPlayer.blockPosition());
@ -33,9 +33,7 @@ public class EnvDetectorItem extends Item {
}
if (!pPlayer.isCreative()) {
pPlayer.getItemInHand(pUsedHand).hurtAndBreak(1, pLevel.getRandom(), pPlayer, () -> {
pPlayer.getItemInHand(pUsedHand).setCount(0);
});
pPlayer.getItemInHand(pUsedHand).hurtAndBreak(1, pLevel.getRandom(), pPlayer, () -> pPlayer.getItemInHand(pUsedHand).setCount(0));
}
return InteractionResultHolder.consume(pPlayer.getItemInHand(pUsedHand));