Skip to content
Draft
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
727082d
First library commit
cpaca Jul 6, 2024
43de4a9
First attempt at writing shulkerForEach
cpaca Jul 6, 2024
0c0d0db
Fix Library.java
cpaca Jul 6, 2024
a68b4cd
Switch Library to be an item instead of a book
cpaca Jul 6, 2024
dfbf867
Make shulker-box-abilities save when block broken
cpaca Jul 6, 2024
1ea9dc9
Fix shulker-box-block-ability metadata
cpaca Jul 6, 2024
d632133
Fix Library onPlayerDeath for non-full shulkers
cpaca Jul 6, 2024
4eec3bf
Move shulkerbox onBlockDropItem to its own thing
cpaca Jul 7, 2024
c86decb
Found the shulkerbox tag
cpaca Jul 7, 2024
9d44b8b
Change shulkerForEach into editShulker
cpaca Jul 7, 2024
8779c54
First GemKnife commit
cpaca Jul 7, 2024
c6e8959
Add things to relevant collections
cpaca Jul 7, 2024
08b172b
Initial GemKnife implementation.
cpaca Jul 7, 2024
3129c28
Fix gemknife emerald consumption
cpaca Jul 7, 2024
76def6e
Update GemKnife to maybe use shulkerboxes
cpaca Jul 7, 2024
8bc39cc
Merge branch 'master' into LibraryOfMemories
dlee13 Jul 9, 2024
8190f43
Revert changes to BlockAbility
dlee13 Jul 9, 2024
2fa284f
Refactor Library
dlee13 Jul 9, 2024
545775a
Revert changes to Util
dlee13 Jul 9, 2024
3537da5
Refactor LibraryBlock
dlee13 Jul 9, 2024
3abaf7a
Refactor GemKnife
dlee13 Jul 9, 2024
d0e7a9d
Rewrite Gem Knife
cpaca Jul 9, 2024
94e75c6
Track remaining items instead of items-to-take
cpaca Jul 9, 2024
f6583b3
Attempt to make GemKnife work on Shulkers
cpaca Jul 9, 2024
6539272
Fix GemKnife shulker check
cpaca Jul 9, 2024
edee0c1
Fix Library's onBlockDropItem
cpaca Jul 9, 2024
428eaf8
Fix library momentos getting consumed
cpaca Jul 9, 2024
1c4cccd
Optimize Library
cpaca Jul 9, 2024
295b9ad
Merge branch 'master' into LibraryOfMemories
cpaca Jul 9, 2024
a245105
Implement Battery
dlee13 Jul 9, 2024
ae9f344
Refactor GemKnife
dlee13 Jul 9, 2024
9402a03
Require Battery to be in hotbar
dlee13 Jul 9, 2024
aa31934
Rename variable
dlee13 Jul 9, 2024
ac6d1ef
Remove unused superinterface
dlee13 Jul 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ private static Set<CustomEnchantment> buildCustomEnchantments(HoloItemsRevamp pl
new Memento(plugin),
new TideRider(plugin),
new Backdash(plugin),
new Plow(plugin)
new Plow(plugin),
new Library(plugin),
new GemKnife(plugin)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ default void onBlockPlace(BlockPlaceEvent event, BlockState blockState) {

/**
* Activates whenever a creature spawns in the same world as this BlockAbility.
*
*
* @param event The CreatureSpawnEvent
* @param blockState This BlockAbility's Block. Note that this may not be in the
* same location as the event.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void onBlockDropItem(BlockDropItemEvent event) {
return;
}

ability.onBlockDropItem(event, block.getState());
ability.onBlockDropItem(event, event.getBlockState());
}

@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ public List<Component> getLore() {
}

private static Idol buildCalliope(HoloItemsRevamp plugin) {
return new Idol(new MementoItem(plugin)) {
return new Idol(new MementoItem(plugin), new LibraryBlock(plugin)) {

@Override
public @NotNull String getSkinUrl() {
Expand Down Expand Up @@ -476,7 +476,7 @@ public List<Component> getLore() {
}

private static Idol buildAmelia(HoloItemsRevamp plugin) {
return new Idol() {
return new Idol(new GemKnifeItem(plugin)) {

@Override
public @NotNull String getSkinUrl() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package xyz.holocons.mc.holoitemsrevamp.enchantment;

import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Predicate;

import com.sk89q.worldedit.blocks.Blocks;
import org.bukkit.Material;
import org.bukkit.block.ShulkerBox;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.util.Consumer;
import org.jetbrains.annotations.NotNull;

import com.destroystokyo.paper.MaterialTags;
import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment;
import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp;

public class GemKnife extends CustomEnchantment implements EnchantmentAbility {

/**
* When you GemKnife a Block, what item will get spit out/output?
*/
private static final Map<Material, Material> COMPATIBLE_MATERIALS = Map.ofEntries(
Map.entry(Material.COAL_ORE, Material.COAL_BLOCK),
Map.entry(Material.DEEPSLATE_COAL_ORE, Material.COAL_BLOCK),
Map.entry(Material.IRON_ORE, Material.IRON_BLOCK),
Map.entry(Material.DEEPSLATE_IRON_ORE, Material.IRON_BLOCK),
Map.entry(Material.GOLD_ORE, Material.GOLD_BLOCK),
Map.entry(Material.DEEPSLATE_GOLD_ORE, Material.GOLD_BLOCK),
Map.entry(Material.NETHER_GOLD_ORE, Material.GOLD_BLOCK),
Map.entry(Material.GILDED_BLACKSTONE, Material.GOLD_BLOCK),
Map.entry(Material.REDSTONE_ORE, Material.REDSTONE_BLOCK),
Map.entry(Material.DEEPSLATE_REDSTONE_ORE, Material.REDSTONE_BLOCK),
Map.entry(Material.LAPIS_ORE, Material.LAPIS_BLOCK),
Map.entry(Material.DEEPSLATE_LAPIS_ORE, Material.LAPIS_BLOCK),
Map.entry(Material.NETHER_QUARTZ_ORE, Material.QUARTZ_BLOCK),
Map.entry(Material.GLOWSTONE, Material.GLOWSTONE));

/**
* How much of each material do you get per-netherite-ingot?
*/
private static final Map<Material, Integer> MATERIALS_PER_INGOT = Map.ofEntries(
Map.entry(Material.COAL_BLOCK, 64),
Map.entry(Material.IRON_BLOCK, 64),
Map.entry(Material.GOLD_BLOCK, 64),
Map.entry(Material.REDSTONE_BLOCK, 64),
Map.entry(Material.LAPIS_BLOCK, 64),
Map.entry(Material.QUARTZ_BLOCK, 64),
Map.entry(Material.GLOWSTONE, 64)
);

public GemKnife(HoloItemsRevamp plugin) {
super(plugin, "gem_knife");
}

@Override
public int getMaxLevel() {
return 1;
}

@Override
public boolean conflictsWith(@NotNull Enchantment enchantment) {
return false;
}

@Override
public boolean canEnchantItem(@NotNull ItemStack item) {
return item.getType() == Material.EMERALD;
}

@Override
public @NotNull Component displayName(int level) {
return Component.text("Gem Knife", NamedTextColor.GRAY)
.decoration(TextDecoration.ITALIC, false);
}

@Override
public int getCostMultiplier() {
// TODO: should this be infinity instead?
return 12;
}

@Override
public void onPlayerInteract(PlayerInteractEvent event, ItemStack itemStack) {
final var clickedBlock = event.getClickedBlock();
if (clickedBlock == null) {
return;
}
final var materialToDrop = COMPATIBLE_MATERIALS.get(clickedBlock.getType());
if (materialToDrop == null) {
return;
}
final var amountPerIngot = MATERIALS_PER_INGOT.get(materialToDrop);
if(amountPerIngot == null) {
// Shouldn't be possible, but just in case.
return;
}

final var ingotsTaken = removeFromInventory(
event.getPlayer().getInventory(), 1, Material.NETHERITE_INGOT);
final var amountToDrop = amountPerIngot * ingotsTaken;

clickedBlock.getWorld().dropItemNaturally(clickedBlock.getLocation(),
new ItemStack(materialToDrop, amountToDrop));
}

/**
* Removes an item from an inventory. Will recursively check into shulker boxes.
* @param inventory The inventory to scan for an item
* @param maxToTake The maximum amount of the item to remove from the inventory
* @param materialToTake What kind of material should be searched for/taken
* @return How many of the item was successfully removed from the inventory
*/
private static int removeFromInventory(Inventory inventory, final int maxToTake, Material materialToTake) {
int amountToTake = maxToTake;

for(ItemStack stack : inventory.getContents()) {
if(stack == null || stack.isEmpty()) {
continue;
}

// TODO: Check for "Battery" HoloItem
// That, or getShulkerBoxInventory (renamed to getBatteryInventory?) should do that.
final var shulkerInv = getShulkerBoxInventory(stack);
if(shulkerInv != null) {
final var finalAmountToTake = amountToTake;
final var amountTakenFromShulker = editShulkerBoxInventoryWithReturn(stack, editableShulkerInv ->
removeFromInventory(editableShulkerInv, finalAmountToTake, materialToTake));
if(amountTakenFromShulker != null) {
amountToTake -= amountTakenFromShulker;
}

if(amountToTake == 0) {
return maxToTake;
}
continue;
}

if(stack.getType() != materialToTake) {
continue;
}

final var stackSize = stack.getAmount();
if(stackSize >= amountToTake) {
// This stack has enough items.
stack.setAmount(stackSize - amountToTake);
return maxToTake;
}
else {
// This stack does not have enough items; absorb the entire stack.
amountToTake -= stackSize;
stack.setType(Material.AIR);
}
}
return maxToTake - amountToTake;
}

/**
* Edit the inventory of a shulkerbox. After the consumer is called,
* the shulker's inventory is saved, including any edits made.
*
* @param itemStack The (possible) shulkerbox to edit
* @param action The action to perform on the shulker's inventory.
*/
private static void editShulkerBoxInventory(ItemStack itemStack, Consumer<Inventory> action) {
itemStack.editMeta(BlockStateMeta.class, blockStateMeta -> {
if (blockStateMeta.getBlockState() instanceof ShulkerBox shulkerBox) {
action.accept(shulkerBox.getInventory());
}
});
}

/**
* Edit the inventory of a shulkerbox. After the consumer is called,
* the shulker's inventory is saved, including any edits made.
*
* @param itemStack The (possible) shulkerbox to edit
* @param action The action to perform on the shulker's inventory
* @return The return value of action, or null if the action was not called.
* @param <R> The return type of the function
*/
private static <R> R editShulkerBoxInventoryWithReturn(ItemStack itemStack, Function<Inventory, R> action) {
if(!(itemStack.getItemMeta() instanceof BlockStateMeta blockStateMeta)) {
return null;
}
if(!(blockStateMeta.getBlockState() instanceof ShulkerBox shulkerBox)) {
return null;
}
R returnValue = action.apply(shulkerBox.getInventory());
blockStateMeta.setBlockState(shulkerBox);
itemStack.setItemMeta(blockStateMeta);
return returnValue;
}

private static Inventory getShulkerBoxInventory(final ItemStack itemStack) {
if (itemStack.getItemMeta() instanceof BlockStateMeta blockStateMeta
&& blockStateMeta.getBlockState() instanceof ShulkerBox shulkerBox) {
return shulkerBox.getInventory();
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package xyz.holocons.mc.holoitemsrevamp.enchantment;

import org.bukkit.Material;
import org.bukkit.block.ShulkerBox;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.jetbrains.annotations.NotNull;

import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment;
import com.strangeone101.holoitemsapi.enchantment.EnchantmentAbility;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp;

public class Library extends CustomEnchantment implements EnchantmentAbility {

public Library(HoloItemsRevamp plugin) {
super(plugin, "library_of_memories");
}

@Override
public int getMaxLevel() {
return 1;
}

@Override
public boolean conflictsWith(@NotNull Enchantment enchantment) {
return false;
}

@Override
public boolean canEnchantItem(@NotNull ItemStack itemStack) {
// TODO: Other colors of shulkerbox
return itemStack.getType() == Material.SHULKER_BOX;
}

@Override
public @NotNull Component displayName(int i) {
return Component.text()
.color(NamedTextColor.GRAY)
.decoration(TextDecoration.ITALIC, false)
.append(Component.text("Library of Memories"))
.build();
}

@Override
public int getCostMultiplier() {
return 39;
}

@Override
public void onPlayerDeath(PlayerDeathEvent event, ItemStack itemStack) {
if (!(itemStack.getItemMeta() instanceof BlockStateMeta blockStateMeta)
|| !(blockStateMeta.getBlockState() instanceof ShulkerBox shulkerBox)) {
return;
}

for (final var inventoryItemStack : shulkerBox.getInventory()) {
if(inventoryItemStack == null) {
continue;
}
for (final var enchantment : inventoryItemStack.getEnchantments().keySet()) {
if (enchantment instanceof Memento memento) {
memento.onPlayerDeath(event, inventoryItemStack);
Comment thread
cpaca marked this conversation as resolved.
Outdated
}
}
}

blockStateMeta.setBlockState(shulkerBox);
itemStack.setItemMeta(blockStateMeta);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package xyz.holocons.mc.holoitemsrevamp.item;

import com.strangeone101.holoitemsapi.enchantment.CustomEnchantment;
import com.strangeone101.holoitemsapi.enchantment.EnchantManager;
import com.strangeone101.holoitemsapi.enchantment.Enchantable;
import com.strangeone101.holoitemsapi.item.CustomItem;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.jetbrains.annotations.NotNull;
import xyz.holocons.mc.holoitemsrevamp.HoloItemsRevamp;

import java.util.List;

public class GemKnifeItem extends CustomItem implements Enchantable {
private static final String name = "gem_knife";
private static final Material material = Material.EMERALD;
private static final Component displayName = Component.text("Gem Knife", NamedTextColor.GREEN);
private static final List<Component> lore = List.of(
Component.text("Right click to consume a charge and break a piece off of an ore soft than emerald.")
);

private final EnchantManager enchantManager;

public GemKnifeItem(HoloItemsRevamp plugin) {
super(plugin, name, material, displayName, lore);
this.enchantManager = plugin.getEnchantManager();
this.register();
}

@Override
protected Recipe getRecipe() {
// TODO
return null;
}

@Override
public @NotNull Enchantment getEnchantment() {
return CustomEnchantment.getByKey(getKey());
}

@Override
public ItemStack applyEnchantment(ItemStack itemStack) {
var enchantedStack = itemStack.clone();
var enchantedMeta = enchantedStack.hasItemMeta() ? enchantedStack.getItemMeta() : Bukkit.getItemFactory().getItemMeta(enchantedStack.getType());

if (enchantedMeta.addEnchant(getEnchantment(), 1, false)) {
enchantedStack.setItemMeta(enchantedMeta);
enchantManager.removeCustomEnchantmentLore(enchantedStack);
enchantManager.applyCustomEnchantmentLore(enchantedStack);
return enchantedStack;
} else {
return null;
}
}
}
Loading