Merge pull request #19 from BlazingGames/builder-wand-types

added different types of the builder wand
This commit is contained in:
XTerPL 2025-02-02 20:03:33 +01:00 committed by GitHub
commit 7d65f40476
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 236 additions and 82 deletions

View file

@ -19,6 +19,9 @@ import de.blazemcworld.blazinggames.BlazingGames;
import de.blazemcworld.blazinggames.items.ContextlessItem;
import de.blazemcworld.blazinggames.items.CustomItem;
import de.blazemcworld.blazinggames.items.change.ItemChangeProviders;
import de.blazemcworld.blazinggames.items.predicates.ItemPredicate;
import de.blazemcworld.blazinggames.items.predicates.MaterialItemPredicate;
import io.papermc.paper.datacomponent.DataComponentTypes;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
@ -41,9 +44,33 @@ import java.util.Map;
public class BuilderWand extends ContextlessItem {
private static final NamespacedKey modeKey = BlazingGames.get().key("builder_mode");
private final NamespacedKey key;
private final Component name;
private final int maxBlocks;
private final int durability;
private final Material gem;
private final Material handle;
private final ItemPredicate repairPredicate;
private final List<BuilderWandMode> availableModes;
public BuilderWand(NamespacedKey key, Component name, int maxBlocks, int durability, Material gem, Material handle, ItemPredicate repairPredicate, BuilderWandMode... availableModes) {
this.key = key;
this.name = name;
this.maxBlocks = maxBlocks;
this.durability = durability;
this.gem = gem;
this.handle = handle;
this.repairPredicate = repairPredicate;
this.availableModes = List.of(availableModes);
}
public BuilderWand(NamespacedKey key, Component name, int maxBlocks, int durability, Material gem, Material handle, BuilderWandMode... availableModes) {
this(key, name, maxBlocks, durability, gem, handle, new MaterialItemPredicate(gem), availableModes);
}
@Override
public @NotNull NamespacedKey getKey() {
return BlazingGames.get().key("builder_wand");
return key;
}
@Override
@ -51,6 +78,11 @@ public class BuilderWand extends ContextlessItem {
return 1;
}
@Override
protected ItemPredicate repairPredicate() {
return repairPredicate;
}
@Override
protected @NotNull ItemStack modifyMaterial(ItemStack wand) {
ItemMeta meta = wand.getItemMeta();
@ -59,12 +91,15 @@ public class BuilderWand extends ContextlessItem {
wand.setItemMeta(meta);
wand.setData(DataComponentTypes.DAMAGE, 0);
wand.setData(DataComponentTypes.MAX_DAMAGE, durability);
return wand;
}
@Override
protected @NotNull Component itemName() {
return Component.text("Builder's Wand").color(NamedTextColor.GOLD);
return name;
}
@Override
@ -73,7 +108,11 @@ public class BuilderWand extends ContextlessItem {
return List.of();
}
return List.of(Component.text(getModeText(wand)).color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, false));
return List.of(
Component.text("Can place up to " + maxBlocks + " blocks")
.color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, false),
Component.text(getModeText(wand)).color(NamedTextColor.GRAY).decoration(TextDecoration.ITALIC, false)
);
}
public ItemStack cycleMode(ItemStack wand) {
@ -86,7 +125,11 @@ public class BuilderWand extends ContextlessItem {
ItemMeta meta = wand.getItemMeta();
BuilderWandMode mode = meta.getPersistentDataContainer().getOrDefault(modeKey, BuilderWandMode.persistentType, BuilderWandMode.NO_LOCK);
mode = mode.getNextMode();
int idx = availableModes.indexOf(mode);
idx++;
if(idx >= availableModes.size()) idx = 0;
mode = availableModes.get(idx);
meta.getPersistentDataContainer().set(modeKey, BuilderWandMode.persistentType, mode);
@ -125,19 +168,35 @@ public class BuilderWand extends ContextlessItem {
Inventory inv = player.getInventory();
for (ItemStack itemStack : inv.getStorageContents()) {
if(itemStack == null) continue;
if(itemStack.getType() != itemMaterial) continue;
if(CustomItem.isCustomItem(itemStack)) continue;
if(player.getGameMode() == GameMode.CREATIVE) {
maxBlocks = this.maxBlocks;
}
else {
for (ItemStack itemStack : inv.getStorageContents()) {
if(itemStack == null) continue;
if(itemStack.getType() != itemMaterial) continue;
if(CustomItem.isCustomItem(itemStack)) continue;
maxBlocks += itemStack.getAmount();
maxBlocks += itemStack.getAmount();
}
if(eventItem.hasData(DataComponentTypes.DAMAGE) &&
eventItem.hasData(DataComponentTypes.MAX_DAMAGE) &&
!eventItem.hasData(DataComponentTypes.UNBREAKABLE)) {
int damage = eventItem.getDataOrDefault(DataComponentTypes.DAMAGE, 0);
int maxDamage = eventItem.getDataOrDefault(DataComponentTypes.MAX_DAMAGE, 0);
int durability = maxDamage - damage;
if(maxBlocks > durability) {
maxBlocks = durability;
}
}
if(maxBlocks > this.maxBlocks) {
maxBlocks = this.maxBlocks;
}
}
if(maxBlocks > 128) {
maxBlocks = 128;
}
if(maxBlocks <= 0 && player.getGameMode() != GameMode.CREATIVE)
if(maxBlocks <= 0)
{
return 0;
}
@ -241,8 +300,8 @@ public class BuilderWand extends ContextlessItem {
" R ",
"R "
);
wandRecipe.setIngredient('R', Material.BLAZE_ROD);
wandRecipe.setIngredient('S', Material.NETHER_STAR);
wandRecipe.setIngredient('R', handle);
wandRecipe.setIngredient('S', gem);
return Map.of(
getKey(), wandRecipe

View file

@ -124,16 +124,4 @@ public enum BuilderWandMode {
public String getModeText() {
return modeText;
}
public BuilderWandMode getNextMode() {
return switch(this) {
case NO_LOCK -> HORIZONTAL;
case HORIZONTAL -> VERTICAL;
case VERTICAL -> NORTH_SOUTH;
case NORTH_SOUTH -> NORTH_SOUTH_VERTICAL;
case NORTH_SOUTH_VERTICAL -> EAST_WEST;
case EAST_WEST -> EAST_WEST_VERTICAL;
case EAST_WEST_VERTICAL -> NO_LOCK;
};
}
}

View file

@ -87,6 +87,8 @@ public class VanillaEnchantmentWrapper implements EnchantmentWrapper {
@Override
public boolean conflictsWith(Enchantment other) {
if(other == enchantment) return false;
return enchantment.conflictsWith(other) || other.conflictsWith(enchantment);
}

View file

@ -16,6 +16,7 @@
package de.blazemcworld.blazinggames.events;
import de.blazemcworld.blazinggames.BlazingGames;
import de.blazemcworld.blazinggames.builderwand.BuilderWand;
import de.blazemcworld.blazinggames.crates.CrateData;
import de.blazemcworld.blazinggames.crates.CrateManager;
import de.blazemcworld.blazinggames.crates.DeathCrateKey;
@ -253,10 +254,11 @@ public class InteractEventListener implements Listener {
}
}
}
if(CustomItems.BUILDER_WAND.matchItem(eventItem)) {
if(CustomItem.getCustomItem(eventItem) instanceof BuilderWand wand) {
if(!player.hasCooldown(eventItem)) {
int blocksUsed = CustomItems.BUILDER_WAND.build(player, eventItem, block, face, clampedInteractionPoint);
int blocksUsed = wand.build(player, eventItem, block, face, clampedInteractionPoint);
if(blocksUsed > 0) {
player.damageItemStack(event.getHand(), blocksUsed);
player.setCooldown(eventItem, 5);
player.getWorld().playSound(player, Sound.ENTITY_CHICKEN_STEP, 1, 1.25f);
}
@ -267,14 +269,14 @@ public class InteractEventListener implements Listener {
}
if(event.getAction().isLeftClick() && hand != null) {
if(player.isSneaking() && CustomItems.BUILDER_WAND.matchItem(eventItem)) {
if(player.isSneaking() && CustomItem.getCustomItem(eventItem) instanceof BuilderWand wand) {
event.setCancelled(true);
eventItem = CustomItems.BUILDER_WAND.cycleMode(eventItem);
eventItem = wand.cycleMode(eventItem);
player.getInventory().setItem(hand, eventItem);
player.sendActionBar(Component.text(CustomItems.BUILDER_WAND.getModeText(eventItem)));
player.sendActionBar(Component.text(wand.getModeText(eventItem)));
}
}

View file

@ -17,6 +17,7 @@ package de.blazemcworld.blazinggames.events;
import de.blazemcworld.blazinggames.enchantments.sys.EnchantmentHelper;
import de.blazemcworld.blazinggames.items.CustomItem;
import de.blazemcworld.blazinggames.utils.ItemUtils;
import de.blazemcworld.blazinggames.utils.Pair;
import de.blazemcworld.blazinggames.utils.TextUtils;
import io.papermc.paper.datacomponent.DataComponentTypes;
@ -53,7 +54,35 @@ public class PrepareAnvilEventListener implements Listener {
if(enchantingItem != null && !enchantingItem.isEmpty()) {
repairCost += enchantingItem.getDataOrDefault(DataComponentTypes.REPAIR_COST, 0);
if(CustomItem.isCustomItem(enchantingItem))
if(ItemUtils.canRepairTool(result, enchantingItem)) {
if(result.hasData(DataComponentTypes.MAX_DAMAGE) &&
result.hasData(DataComponentTypes.DAMAGE) &&
!result.hasData(DataComponentTypes.UNBREAKABLE))
{
int damage = result.getData(DataComponentTypes.DAMAGE);
int maxDamage = result.getData(DataComponentTypes.MAX_DAMAGE);
int damageReduced = maxDamage / 4;
int count = 0;
while(count * damageReduced < damage) {
if(count >= enchantingItem.getAmount()) {
break;
}
count++;
}
damage -= count * damageReduced;
if(damage < 0) damage = 0;
result.setData(DataComponentTypes.DAMAGE, damage);
event.getView().setRepairItemCountCost(count);
repairCost += count;
increaseRepairCost = true;
}
}
else if(CustomItem.isCustomItem(enchantingItem))
{
if(EnchantmentHelper.canEnchantItem(result) && result.getAmount() == 1) {
CustomItem<?> item = CustomItem.getCustomItem(enchantingItem);
@ -68,55 +97,22 @@ public class PrepareAnvilEventListener implements Listener {
}
}
}
else
{
if(result.isRepairableBy(enchantingItem)) {
if(result.hasData(DataComponentTypes.MAX_DAMAGE) &&
result.hasData(DataComponentTypes.DAMAGE) &&
!result.hasData(DataComponentTypes.UNBREAKABLE))
{
int damage = result.getData(DataComponentTypes.DAMAGE);
int maxDamage = result.getData(DataComponentTypes.MAX_DAMAGE);
else if(EnchantmentHelper.canEnchantItem(result) && result.getAmount() == 1) {
if(enchantingItem.getType() == Material.ENCHANTED_BOOK) {
Pair<ItemStack, Integer> enchantResult = EnchantmentHelper.enchantFromItem(result, enchantingItem);
result = enchantResult.left;
repairCost += enchantResult.right;
increaseRepairCost = true;
int damageReduced = maxDamage / 4;
int count = 0;
while(count * damageReduced < damage) {
if(count >= enchantingItem.getAmount()) {
break;
}
count++;
}
damage -= count * damageReduced;
if(damage < 0) damage = 0;
result.setData(DataComponentTypes.DAMAGE, damage);
event.getView().setRepairItemCountCost(count);
repairCost += count;
increaseRepairCost = true;
}
minRepairCost = Math.min(minRepairCost, enchantingItem.getDataOrDefault(DataComponentTypes.REPAIR_COST, 0));
}
else {
if(EnchantmentHelper.canEnchantItem(result) && result.getAmount() == 1) {
if(enchantingItem.getType() == Material.ENCHANTED_BOOK) {
Pair<ItemStack, Integer> enchantResult = EnchantmentHelper.enchantFromItem(result, enchantingItem);
result = enchantResult.left;
repairCost += enchantResult.right;
increaseRepairCost = true;
else if(!CustomItem.isCustomItem(result) && enchantingItem.getType() == result.getType()) {
Pair<ItemStack, Integer> enchantResult = EnchantmentHelper.enchantFromItem(result, enchantingItem);
result = enchantResult.left;
repairCost += repairByCombination(result, enchantingItem, 12) + enchantResult.right;
increaseRepairCost = true;
minRepairCost = Math.min(minRepairCost, enchantingItem.getDataOrDefault(DataComponentTypes.REPAIR_COST, 0));
}
else if(!CustomItem.isCustomItem(result) && enchantingItem.getType() == result.getType()) {
Pair<ItemStack, Integer> enchantResult = EnchantmentHelper.enchantFromItem(result, enchantingItem);
result = enchantResult.left;
repairCost += repairByCombination(result, enchantingItem, 12) + enchantResult.right;
increaseRepairCost = true;
minRepairCost = Math.min(minRepairCost, enchantingItem.getDataOrDefault(DataComponentTypes.REPAIR_COST, 0));
}
}
minRepairCost = Math.min(minRepairCost, enchantingItem.getDataOrDefault(DataComponentTypes.REPAIR_COST, 0));
}
}
}

View file

@ -118,6 +118,16 @@ public abstract class CustomItem<T extends ItemContext> implements RecipeProvide
return itemName();
}
public final boolean repairableBy(ItemStack stack) {
ItemPredicate repairPredicate = repairPredicate();
if(repairPredicate == null) {
return false;
}
return repairPredicate.matchItem(stack);
}
// DO NOT CALL THIS METHOD, instead call create() on the item's instance
// also there's no need to set the "custom_item" item tag because
// the create() method does it anyway
@ -136,5 +146,9 @@ public abstract class CustomItem<T extends ItemContext> implements RecipeProvide
return List.of();
}
protected ItemPredicate repairPredicate() {
return null;
}
protected abstract T parseRawContext(Player player, String raw) throws ParseException;
}

View file

@ -20,6 +20,7 @@ import com.google.gson.JsonObject;
import de.blazemcworld.blazinggames.BlazingGames;
import de.blazemcworld.blazinggames.builderwand.BuilderWand;
import de.blazemcworld.blazinggames.builderwand.BuilderWandMode;
import de.blazemcworld.blazinggames.crates.DeathCrateKey;
import de.blazemcworld.blazinggames.crates.SkeletonKey;
import de.blazemcworld.blazinggames.crates.ToGoBoxItem;
@ -29,6 +30,9 @@ import de.blazemcworld.blazinggames.enchantments.sys.EnchantmentWrappers;
import de.blazemcworld.blazinggames.multiblocks.Blueprint;
import de.blazemcworld.blazinggames.packs.HookContext;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import javax.annotation.Nullable;
@ -41,7 +45,6 @@ import java.util.logging.Logger;
public class CustomItems implements ItemProvider {
public static final CustomSlabs CUSTOM_SLABS = new CustomSlabs();
public static final BuilderWand BUILDER_WAND = new BuilderWand();
public static final PortableCraftingTable PORTABLE_CRAFTING_TABLE = new PortableCraftingTable();
public static final TeleportAnchor TELEPORT_ANCHOR = new TeleportAnchor();
public static final Blueprint BLUEPRINT = new Blueprint();
@ -51,6 +54,30 @@ public class CustomItems implements ItemProvider {
public static final ToGoBoxItem TO_GO_BOX = new ToGoBoxItem();
public static final NetherStarChunk NETHER_STAR_CHUNK = new NetherStarChunk();
public static final BuilderWand WOODEN_BUILDER_WAND = new BuilderWand(
BlazingGames.get().key("wooden_builder_wand"),
Component.text("Wooden Builder's Wand"),
16, 256,
Material.FLINT, Material.STICK,
BuilderWandMode.NO_LOCK
);
public static final BuilderWand STORM_BUILDER_WAND = new BuilderWand(
BlazingGames.get().key("storm_builder_wand"),
Component.text("Storm Builder's Wand").color(NamedTextColor.BLUE),
64, 2048,
Material.DIAMOND, Material.BREEZE_ROD,
BuilderWandMode.NO_LOCK, BuilderWandMode.HORIZONTAL, BuilderWandMode.VERTICAL
);
public static final BuilderWand BLAZING_BUILDER_WAND = new BuilderWand(
BlazingGames.get().key("blazing_builder_wand"),
Component.text("Blazing Builder's Wand").color(NamedTextColor.GOLD),
128, 16384,
Material.NETHER_STAR, Material.BLAZE_ROD, CustomItems.NETHER_STAR_CHUNK,
BuilderWandMode.NO_LOCK, BuilderWandMode.HORIZONTAL, BuilderWandMode.VERTICAL,
BuilderWandMode.NORTH_SOUTH, BuilderWandMode.NORTH_SOUTH_VERTICAL,
BuilderWandMode.EAST_WEST, BuilderWandMode.EAST_WEST_VERTICAL
);
public static final EnchantmentTome FUSE_TOME = new EnchantmentTome(BlazingGames.get().key("fuse_tome"), "Fuse Tome", EnchantmentWrappers.MENDING);
public static final EnchantmentTome BIND_TOME = new EnchantmentTome(BlazingGames.get().key("bind_tome"), "Bind Tome", EnchantmentWrappers.BINDING_CURSE);
public static final EnchantmentTome VANISH_TOME = new EnchantmentTome(BlazingGames.get().key("vanish_tome"), "Vanish Tome", EnchantmentWrappers.VANISHING_CURSE);
@ -66,7 +93,6 @@ public class CustomItems implements ItemProvider {
@Override
public Set<CustomItem<?>> getItems() {
return Set.of(
BUILDER_WAND,
PORTABLE_CRAFTING_TABLE,
TELEPORT_ANCHOR,
BLUEPRINT,
@ -75,6 +101,9 @@ public class CustomItems implements ItemProvider {
SKELETON_KEY,
TO_GO_BOX,
NETHER_STAR_CHUNK,
WOODEN_BUILDER_WAND,
STORM_BUILDER_WAND,
BLAZING_BUILDER_WAND,
FUSE_TOME,
BIND_TOME,
VANISH_TOME,
@ -127,6 +156,13 @@ public class CustomItems implements ItemProvider {
BlazingGames.get().log(e);
}
// install animation options
try (InputStream stream = item.getClass().getResourceAsStream("/customitems/" + item.getKey().getKey() + ".png.mcmeta")) {
if (stream != null) context.installTextureAnimationData(item.getKey(), "item", stream.readAllBytes());
} catch (IOException e) {
BlazingGames.get().log(e);
}
// install model
try (InputStream stream = item.getClass().getResourceAsStream("/customitems/" + item.getKey().getKey() + ".json")) {
if (stream != null) context.installModel(item.getKey(), stream.readAllBytes());

View file

@ -54,6 +54,10 @@ public class HookContext {
writeFile("assets/" + namespace.getNamespace() + "/textures/" + type + "/" + namespace.getKey() + ".png", texture);
}
public void installTextureAnimationData(NamespacedKey namespace, String type, byte[] animationData) {
writeFile("assets/" + namespace.getNamespace() + "/textures/" + type + "/" + namespace.getKey() + ".png.mcmeta", animationData);
}
public void installModel(NamespacedKey namespace, byte[] model) {
writeFile("assets/" + namespace.getNamespace() + "/models/" + namespace.getKey() + ".json", model);
}

View file

@ -63,6 +63,13 @@ public class GuiElementsHook implements PackBuildHook {
} catch (IOException e) {
BlazingGames.get().log(e);
}
// install animation options
try (InputStream stream = BlazingGames.class.getResourceAsStream("/gui/" + texture.getKey() + ".png.mcmeta")) {
if (stream != null) context.installTextureAnimationData(texture, "item", stream.readAllBytes());
} catch (IOException e) {
BlazingGames.get().log(e);
}
}
for (NamespacedKey model : getGuiModels()) {

View file

@ -15,6 +15,7 @@
*/
package de.blazemcworld.blazinggames.utils;
import de.blazemcworld.blazinggames.items.CustomItem;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
@ -120,4 +121,16 @@ public class ItemUtils {
default -> mat;
};
}
public static boolean canRepairTool(ItemStack tool, ItemStack sacrificial) {
if(tool == null) return false;
if(sacrificial == null) return false;
CustomItem<?> customItem = CustomItem.getCustomItem(tool);
if(customItem == null) {
return !CustomItem.isCustomItem(sacrificial) && tool.isRepairableBy(sacrificial);
}
return customItem.repairableBy(sacrificial);
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "blazinggames:item/blazing_builder_wand"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,8 @@
{
"animation":
{
"frametime": 2,
"width": 16,
"height": 16
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "blazinggames:item/storm_builder_wand"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

View file

@ -0,0 +1,7 @@
{
"animation":
{
"frametime": 2,
"width": 16
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "blazinggames:item/wooden_builder_wand"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B