Item Utilities
Amber provides several utility classes for working with items, inventory, and item-related operations. These utilities help simplify common tasks and provide consistent behavior across platforms.
Deprecated
The ItemHelper and InventoryHelper classes are deprecated and will be removed in Amber 10.0.
Use com.iamkaf.amber.api.functions.v1.ItemFunctions instead. See Functions API → ItemFunctions for the new API.
ItemHelper
The ItemHelper class provides various methods for item manipulation and attribute management.
Item Repair
Repair items by a percentage of their maximum durability:
import com.iamkaf.amber.api.inventory.ItemHelper;
// Repair an item by 25% of its max durability
ItemStack tool = player.getMainHandItem();
ItemHelper.repairBy(tool, 0.25f);
// Repair an item by 50% of its max durability
ItemHelper.repairBy(armor, 0.5f);
// Fully repair an item (100%)
ItemHelper.repairBy(item, 1.0f);Ingredient Display Names
Get user-friendly display names for recipe ingredients:
public class RecipeHelper {
public static void printIngredientInfo(Ingredient ingredient) {
String displayName = ItemHelper.getIngredientDisplayName(ingredient);
if (player != null) {
player.sendSystemMessage(Component.literal("Required: " + displayName));
}
}
public static Component getIngredientComponent(Ingredient ingredient) {
String name = ItemHelper.getIngredientDisplayName(ingredient);
return Component.literal(name).withStyle(ChatFormatting.GRAY);
}
}Attribute Modifiers
Add and manage item attribute modifiers:
import com.iamkaf.amber.api.inventory.ItemHelper;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.EquipmentSlotGroup;
public class ItemEnchantment {
public static void addSpeedBoost(ItemStack boots) {
// Create a speed boost modifier
AttributeModifier speedModifier = new AttributeModifier(
ResourceLocation.fromNamespaceAndPath("mymod", "speed_boost"),
0.1, // 10% speed increase
AttributeModifier.Operation.ADD_MULTIPLIED_BASE
);
// Add the modifier to the boots
ItemHelper.addModifier(
boots,
Attributes.MOVEMENT_SPEED,
speedModifier,
EquipmentSlotGroup.FEET
);
}
public static void addAttackDamage(ItemStack sword) {
// Create a damage modifier
AttributeModifier damageModifier = new AttributeModifier(
ResourceLocation.fromNamespaceAndPath("mymod", "extra_damage"),
2.0, // +2 attack damage
AttributeModifier.Operation.ADD_VALUE
);
// Add the modifier to the sword
ItemHelper.addModifier(
sword,
Attributes.ATTACK_DAMAGE,
damageModifier,
EquipmentSlotGroup.MAINHAND
);
}
public static boolean hasSpeedBoost(ItemStack boots) {
return ItemHelper.hasModifier(boots,
ResourceLocation.fromNamespaceAndPath("mymod", "speed_boost"));
}
public static boolean hasCustomModifier(ItemStack stack, String modifierId) {
return ItemHelper.hasModifier(stack,
ResourceLocation.fromNamespaceAndPath("mymod", modifierId));
}
}InventoryHelper
The InventoryHelper class provides methods for checking and manipulating inventory contents.
Checking Inventory Contents
Check if an inventory contains specific items:
import com.iamkaf.amber.api.inventory.InventoryHelper;
import net.minecraft.world.item.Items;
import net.minecraft.tags.ItemTags;
public class InventoryChecks {
public static boolean hasDiamondPickaxe(Player player) {
return InventoryHelper.has(player.getInventory(), Items.DIAMOND_PICKAXE);
}
public static boolean hasWood(Player player) {
return InventoryHelper.has(player.getInventory(), ItemTags.LOGS);
}
public static boolean hasMultipleItems(Player player, Item item, int count) {
return InventoryHelper.has(player.getInventory(), item, count);
}
public static boolean hasIngredient(Player player, Ingredient ingredient) {
return InventoryHelper.has(player.getInventory(), ingredient);
}
public static boolean hasIngredients(Player player, Ingredient ingredient, int count) {
return InventoryHelper.has(player.getInventory(), ingredient, count);
}
}Consuming Items
Consume items from inventory if available:
public class ItemConsumption {
public static boolean consumeDiamond(Player player) {
return InventoryHelper.consumeIfAvailable(player.getInventory(), Items.DIAMOND);
}
public static boolean consumeMultipleItems(Player player, Item item, int count) {
return InventoryHelper.consumeIfAvailable(player.getInventory(), item, count);
}
public static boolean consumeWood(Player player) {
return InventoryHelper.consumeIfAvailable(player.getInventory(), ItemTags.LOGS);
}
public static boolean consumeForCrafting(Player player, Ingredient ingredient) {
return InventoryHelper.consumeIfAvailable(player.getInventory(), ingredient, 1);
}
public static boolean consumeWithCost(Player player, Item item, int cost) {
if (InventoryHelper.consumeIfAvailable(player.getInventory(), item, cost)) {
player.sendSystemMessage(Component.literal("Paid " + cost + " " + item.getName(new ItemStack(item)).getString()));
return true;
} else {
player.sendSystemMessage(Component.literal("Not enough " + item.getName(new ItemStack(item)).getString() + "!"));
return false;
}
}
}Inventory Iteration
Iterate through all items in an inventory:
public class InventoryScanner {
public static void findDamagedItems(Player player) {
List<ItemStack> damagedItems = new ArrayList<>();
InventoryHelper.forEach(player.getInventory(), stack -> {
if (!stack.isEmpty() && stack.getDamageValue() > 0) {
damagedItems.add(stack.copy());
}
});
if (!damagedItems.isEmpty()) {
player.sendSystemMessage(Component.literal("Found " + damagedItems.size() + " damaged items"));
}
}
public static void countEnchantedItems(Player player) {
AtomicInteger enchantedCount = new AtomicInteger(0);
InventoryHelper.forEach(player.getInventory(), stack -> {
if (!stack.isEmpty() && stack.isEnchanted()) {
enchantedCount.incrementAndGet();
}
});
player.sendSystemMessage(Component.literal("You have " + enchantedCount.get() + " enchanted items"));
}
public static List<ItemStack> getItemsOfType(Player player, Item targetItem) {
List<ItemStack> items = new ArrayList<>();
InventoryHelper.forEach(player.getInventory(), stack -> {
if (!stack.isEmpty() && stack.is(targetItem)) {
items.add(stack.copy());
}
});
return items;
}
}Player Feedback
The FeedbackHelper class provides methods for sending messages to players.
Chat Messages
Send messages to player chat:
import com.iamkaf.amber.api.player.FeedbackHelper;
public class PlayerMessaging {
public static void sendWelcomeMessage(Player player) {
FeedbackHelper.message(player,
Component.literal("Welcome to the server!")
.withStyle(ChatFormatting.GREEN));
}
public static void sendErrorMessage(Player player, String error) {
FeedbackHelper.message(player,
Component.literal("Error: " + error)
.withStyle(ChatFormatting.RED));
}
public static void sendInfoMessage(Player player, String info) {
FeedbackHelper.message(player,
Component.literal(info)
.withStyle(ChatFormatting.GRAY));
}
}Action Bar Messages
Send messages to the action bar:
public class ActionBarMessages {
public static void showEnergy(Player player, int energy, int maxEnergy) {
String percentage = String.format("%.1f", (double) energy / maxEnergy * 100);
FeedbackHelper.actionBarMessage(player,
Component.literal("Energy: " + energy + "/" + maxEnergy + " (" + percentage + "%)")
.withStyle(ChatFormatting.YELLOW));
}
public static void showCooldown(Player player, int seconds) {
FeedbackHelper.actionBarMessage(player,
Component.literal("Cooldown: " + seconds + "s")
.withStyle(ChatFormatting.RED));
}
public static void showStatus(Player player, String status) {
FeedbackHelper.actionBarMessage(player,
Component.literal(status)
.withStyle(ChatFormatting.AQUA));
}
}Level Utilities
The LevelHelper class provides methods for world-level operations.
Scheduled Tasks
Run tasks at regular intervals:
import com.iamkaf.amber.api.level.LevelHelper;
public class WorldScheduler {
public static void tickEvent(Level level) {
// Run every 100 ticks (5 seconds)
LevelHelper.runEveryXTicks(level, 100, gameTime -> {
// Check all players in the level
level.players().forEach(player -> {
// Apply periodic effect
if (player.hasEffect(MobEffects.REGENERATION)) {
player.addEffect(new MobEffectInstance(
MobEffects.REGENERATION,
200, // 10 seconds
0, // Amplifier
true, // Ambient particles
true // Show icon
));
}
});
});
// Run every 20 ticks (1 second)
LevelHelper.runEveryXTicks(level, 20, gameTime -> {
// Update world time display
if (level instanceof ServerLevel serverLevel) {
updateWorldClock(serverLevel);
}
});
// Run every 1200 ticks (1 minute)
LevelHelper.runEveryXTicks(level, 1200, gameTime -> {
// Save world data periodically
if (level instanceof ServerLevel serverLevel) {
saveCustomData(serverLevel, gameTime);
}
});
}
private static void updateWorldClock(ServerLevel level) {
// Custom clock update logic
}
private static void saveCustomData(ServerLevel level, long gameTime) {
// Custom data saving logic
}
}Item Drops
Drop items in the world:
public class WorldDrops {
public static void dropReward(Level level, Vec3 pos, Item item, int count) {
ItemStack stack = new ItemStack(item, count);
LevelHelper.dropItem(level, stack, pos);
}
public static void dropWithVelocity(Level level, Vec3 pos, ItemStack stack, Vec3 velocity) {
LevelHelper.dropItem(level, stack, pos, velocity);
}
public static void createExplosionDrops(Level level, Vec3 center, List<ItemStack> drops) {
Random random = new Random();
for (ItemStack drop : drops) {
// Random position within explosion radius
double angle = random.nextDouble() * 2 * Math.PI;
double distance = random.nextDouble() * 3.0; // 3 block radius
Vec3 dropPos = center.add(
Math.cos(angle) * distance,
0.5, // Slight upward offset
Math.sin(angle) * distance
);
// Random velocity away from center
Vec3 velocity = new Vec3(
Math.cos(angle) * 0.3,
random.nextDouble() * 0.2 + 0.1,
Math.sin(angle) * 0.3
);
LevelHelper.dropItem(level, drop, dropPos, velocity);
}
}
public static void dropLootTable(Level level, Vec3 pos, ResourceLocation lootTableId, LootContextParamSet parameters) {
LootParams.Builder builder = new LootParams.Builder((ServerLevel) level);
// Build context parameters based on what you need
if (level instanceof ServerLevel serverLevel) {
builder.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(BlockPos.containing(pos)));
}
LootParams lootParams = builder.build(parameters);
LootTable lootTable = level.getServer().getLootData().getLootTable(lootTableId);
// Generate and drop items
lootTable.getRandomItems(lootParams).forEach(stack -> {
LevelHelper.dropItem(level, stack, pos);
});
}
}Sound Utilities
The SoundHelper class provides methods for playing sounds.
Playing Sounds
Play sounds for players:
import com.iamkaf.amber.api.sound.SoundHelper;
public class SoundEffects {
public static void playSuccessSound(Player player) {
SoundHelper.sendClientSound(player, SoundEvents.UI_TOAST_CHALLENGE_COMPLETE);
}
public static void playErrorSound(Player player) {
SoundHelper.sendClientSound(player, SoundEvents.UI_BUTTON_CLICK);
}
public static void playLevelUpSound(Player player) {
SoundHelper.sendClientSound(player, SoundEvents.PLAYER_LEVELUP, SoundSource.MASTER, 1.0f, 1.0f);
}
public static void playCustomSound(Player player, SoundEvent sound, float volume, float pitch) {
SoundHelper.sendClientSound(player, sound, SoundSource.PLAYERS, volume, pitch);
}
public static void playAmbientSound(Player player) {
SoundHelper.sendClientSound(player, SoundEvents.AMBIENT_CAVE, SoundSource.AMBIENT, 0.5f, 1.0f);
}
}Math Utilities
The Chance class provides probability calculations.
Random Events
Calculate random event probabilities:
import com.iamkaf.amber.api.math.Chance;
public class RandomEvents {
public static boolean tryCriticalHit() {
// 25% chance of critical hit
return Chance.of(0.25f);
}
public static boolean tryRareDrop() {
// 5% chance of rare drop
return Chance.of(0.05f);
}
public static boolean tryCommonEvent() {
// 75% chance of common event
return Chance.of(0.75f);
}
public static void processRandomRewards(Player player) {
if (Chance.of(0.1f)) { // 10% chance
// Rare reward
player.getInventory().add(new ItemStack(Items.DIAMOND));
FeedbackHelper.message(player, Component.literal("Rare reward!"));
} else if (Chance.of(0.5f)) { // 50% chance
// Common reward
player.getInventory().add(new ItemStack(Items.GOLD_INGOT));
FeedbackHelper.message(player, Component.literal("Common reward!"));
}
// 40% chance of no reward
}
public static boolean shouldSpawnMob(Level level) {
// Higher chance at night, lower during day
boolean isNight = level.isNight();
float chance = isNight ? 0.3f : 0.1f;
return Chance.of(chance);
}
}Best Practices
1. Validation
Always validate items before operations:
public static boolean safeConsume(Inventory inventory, Item item, int amount) {
// Check if item exists first
if (!InventoryHelper.has(inventory, item, amount)) {
return false;
}
// Then consume
return InventoryHelper.consumeIfAvailable(inventory, item, amount);
}2. Null Safety
Check for null values when working with items:
public static void repairItemSafely(ItemStack stack) {
if (stack == null || stack.isEmpty()) {
return;
}
if (stack.getMaxDamage() > 0) {
ItemHelper.repairBy(stack, 0.1f);
}
}3. Side Awareness
Be aware of client/server side differences:
public static void playSoundIfServer(Player player, SoundEvent sound) {
if (player instanceof ServerPlayer) {
SoundHelper.sendClientSound(player, sound);
}
}These utility classes provide helpful shortcuts for common operations while maintaining cross-platform compatibility.