mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2026-01-04 15:41:38 +00:00
Implement Strippable Block
This commit is contained in:
@@ -54,7 +54,7 @@ blocks:
|
|||||||
loot:
|
loot:
|
||||||
template: loot_table:normal
|
template: loot_table:normal
|
||||||
arguments:
|
arguments:
|
||||||
item: default:palm_log
|
item: default:stripped_palm_log
|
||||||
settings:
|
settings:
|
||||||
template: block_settings:log
|
template: block_settings:log
|
||||||
overrides:
|
overrides:
|
||||||
@@ -107,7 +107,7 @@ blocks:
|
|||||||
loot:
|
loot:
|
||||||
template: loot_table:normal
|
template: loot_table:normal
|
||||||
arguments:
|
arguments:
|
||||||
item: default:palm_wood
|
item: default:stripped_palm_wood
|
||||||
settings:
|
settings:
|
||||||
template: block_settings:log
|
template: block_settings:log
|
||||||
overrides:
|
overrides:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.item.modifier.ItemModifier;
|
|||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -70,7 +71,7 @@ public class BukkitCustomItem implements CustomItem<ItemStack> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemBehavior behavior() {
|
public @NotNull ItemBehavior behavior() {
|
||||||
return this.behavior;
|
return this.behavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.momirealms.craftengine.bukkit.item;
|
package net.momirealms.craftengine.bukkit.item;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior;
|
||||||
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
|
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||||
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
||||||
@@ -7,6 +8,7 @@ import net.momirealms.craftengine.bukkit.util.MaterialUtils;
|
|||||||
import net.momirealms.craftengine.bukkit.util.Reflections;
|
import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||||
import net.momirealms.craftengine.core.entity.player.Player;
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
import net.momirealms.craftengine.core.item.*;
|
import net.momirealms.craftengine.core.item.*;
|
||||||
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviors;
|
import net.momirealms.craftengine.core.item.behavior.ItemBehaviors;
|
||||||
import net.momirealms.craftengine.core.item.modifier.CustomModelDataModifier;
|
import net.momirealms.craftengine.core.item.modifier.CustomModelDataModifier;
|
||||||
import net.momirealms.craftengine.core.item.modifier.IdModifier;
|
import net.momirealms.craftengine.core.item.modifier.IdModifier;
|
||||||
@@ -35,12 +37,25 @@ import java.nio.file.Path;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||||
|
private static final Map<Key, ItemBehavior> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.WOODEN_AXE, ItemKeys.STONE_AXE, ItemKeys.IRON_AXE, ItemKeys.GOLDEN_AXE, ItemKeys.DIAMOND_AXE, ItemKeys.NETHERITE_AXE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerVanillaItemExtraBehavior(ItemBehavior behavior, Key... items) {
|
||||||
|
for (Key key : items) {
|
||||||
|
VANILLA_ITEM_EXTRA_BEHAVIORS.put(key, behavior);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static BukkitItemManager instance;
|
private static BukkitItemManager instance;
|
||||||
private final BukkitItemFactory factory;
|
private final BukkitItemFactory factory;
|
||||||
private final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides;
|
private final Map<Key, TreeSet<LegacyOverridesModel>> legacyOverrides;
|
||||||
private final Map<Key, TreeMap<Integer, ItemModel>> modernOverrides;
|
private final Map<Key, TreeMap<Integer, ItemModel>> modernOverrides;
|
||||||
private final BukkitCraftEngine plugin;
|
private final BukkitCraftEngine plugin;
|
||||||
private final ItemEventListener itemEventListener;
|
private final ItemEventListener itemEventListener;
|
||||||
|
private final DebugStickListener debugStickListener;
|
||||||
private final Map<Key, List<Holder<Key>>> vanillaItemTags;
|
private final Map<Key, List<Holder<Key>>> vanillaItemTags;
|
||||||
private final Map<Key, List<Holder<Key>>> customItemTags;
|
private final Map<Key, List<Holder<Key>>> customItemTags;
|
||||||
private final Map<Key, Map<Integer, Key>> cmdConflictChecker;
|
private final Map<Key, Map<Integer, Key>> cmdConflictChecker;
|
||||||
@@ -55,6 +70,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
|||||||
this.customItemTags = new HashMap<>();
|
this.customItemTags = new HashMap<>();
|
||||||
this.cmdConflictChecker = new HashMap<>();
|
this.cmdConflictChecker = new HashMap<>();
|
||||||
this.itemEventListener = new ItemEventListener(plugin);
|
this.itemEventListener = new ItemEventListener(plugin);
|
||||||
|
this.debugStickListener = new DebugStickListener(plugin);
|
||||||
this.registerAllVanillaItems();
|
this.registerAllVanillaItems();
|
||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
@@ -100,6 +116,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
|||||||
public void load() {
|
public void load() {
|
||||||
super.load();
|
super.load();
|
||||||
Bukkit.getPluginManager().registerEvents(this.itemEventListener, plugin.bootstrap());
|
Bukkit.getPluginManager().registerEvents(this.itemEventListener, plugin.bootstrap());
|
||||||
|
Bukkit.getPluginManager().registerEvents(this.debugStickListener, plugin.bootstrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,6 +126,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
|||||||
this.modernOverrides.clear();
|
this.modernOverrides.clear();
|
||||||
this.customItemTags.clear();
|
this.customItemTags.clear();
|
||||||
HandlerList.unregisterAll(this.itemEventListener);
|
HandlerList.unregisterAll(this.itemEventListener);
|
||||||
|
HandlerList.unregisterAll(this.debugStickListener);
|
||||||
this.cmdConflictChecker.clear();
|
this.cmdConflictChecker.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +186,28 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
|||||||
return wrapped.id();
|
return wrapped.id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<List<ItemBehavior>> getItemBehavior(Key key) {
|
||||||
|
Optional<CustomItem<ItemStack>> customItemOptional = getCustomItem(key);
|
||||||
|
if (customItemOptional.isPresent()) {
|
||||||
|
CustomItem<ItemStack> customItem = customItemOptional.get();
|
||||||
|
Key vanillaMaterial = customItem.material();
|
||||||
|
ItemBehavior behavior = VANILLA_ITEM_EXTRA_BEHAVIORS.get(vanillaMaterial);
|
||||||
|
if (behavior != null) {
|
||||||
|
return Optional.of(List.of(behavior, customItem.behavior()));
|
||||||
|
} else {
|
||||||
|
return Optional.of(List.of(customItem.behavior()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ItemBehavior behavior = VANILLA_ITEM_EXTRA_BEHAVIORS.get(key);
|
||||||
|
if (behavior != null) {
|
||||||
|
return Optional.of(List.of(behavior));
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Key> items() {
|
public Collection<Key> items() {
|
||||||
return new ArrayList<>(customItems.keySet());
|
return new ArrayList<>(customItems.keySet());
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.item;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||||
|
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||||
|
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||||
|
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||||
|
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||||
|
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||||
|
import net.momirealms.craftengine.core.block.properties.Property;
|
||||||
|
import net.momirealms.craftengine.core.item.Item;
|
||||||
|
import net.momirealms.craftengine.core.util.MCUtils;
|
||||||
|
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class DebugStickListener implements Listener {
|
||||||
|
private final BukkitCraftEngine plugin;
|
||||||
|
|
||||||
|
public DebugStickListener(BukkitCraftEngine plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true)
|
||||||
|
public void onUseDebugStick(PlayerInteractEvent event) {
|
||||||
|
Block clickedBlock = event.getClickedBlock();
|
||||||
|
if (clickedBlock == null) return;
|
||||||
|
ItemStack itemInHand = event.getItem();
|
||||||
|
if (itemInHand == null) return;
|
||||||
|
Material material = itemInHand.getType();
|
||||||
|
if (material != Material.DEBUG_STICK) return;
|
||||||
|
Player bukkitPlayer = event.getPlayer();
|
||||||
|
BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer);
|
||||||
|
if (!(player.canInstabuild() && player.hasPermission("minecraft.debugstick")) && !player.hasPermission("minecraft.debugstick.always")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.getHand() == EquipmentSlot.OFF_HAND) {
|
||||||
|
int currentTicks = player.gameTicks();
|
||||||
|
if (!player.updateLastSuccessfulInteractionTick(currentTicks)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object blockState = BlockStateUtils.blockDataToBlockState(clickedBlock.getBlockData());
|
||||||
|
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||||
|
if (!BlockStateUtils.isVanillaBlock(stateId)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
boolean update = event.getAction() == Action.RIGHT_CLICK_BLOCK;
|
||||||
|
ImmutableBlockState clickedCustomBlock = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||||
|
CustomBlock block = clickedCustomBlock.owner().value();
|
||||||
|
Collection<Property<?>> properties = block.properties();
|
||||||
|
String blockId = block.id().toString();
|
||||||
|
try {
|
||||||
|
if (properties.isEmpty()) {
|
||||||
|
Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance(
|
||||||
|
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.empty").arguments(Component.text(blockId))), true);
|
||||||
|
player.sendPacket(systemChatPacket, false);
|
||||||
|
} else {
|
||||||
|
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(itemInHand);
|
||||||
|
Object storedData = wrapped.getTag("craftengine:debug_stick_state");
|
||||||
|
if (storedData == null) storedData = new HashMap<>();
|
||||||
|
if (storedData instanceof Map<?,?> map) {
|
||||||
|
Map<String, Object> data = MiscUtils.castToMap(map, false);
|
||||||
|
String currentPropertyName = (String) data.get(blockId);
|
||||||
|
Property<?> currentProperty = block.getProperty(currentPropertyName);
|
||||||
|
if (currentProperty == null) {
|
||||||
|
currentProperty = properties.iterator().next();
|
||||||
|
}
|
||||||
|
if (update) {
|
||||||
|
ImmutableBlockState nextState = cycleState(clickedCustomBlock, currentProperty, player.isSecondaryUseActive());
|
||||||
|
CraftEngineBlocks.place(clickedBlock.getLocation(), nextState, new UpdateOption.Builder().updateClients().updateKnownShape().build());
|
||||||
|
Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance(
|
||||||
|
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.update")
|
||||||
|
.arguments(
|
||||||
|
Component.text(currentProperty.name()),
|
||||||
|
Component.text(getNameHelper(nextState, currentProperty))
|
||||||
|
)), true);
|
||||||
|
player.sendPacket(systemChatPacket, false);
|
||||||
|
} else {
|
||||||
|
currentProperty = getRelative(properties, currentProperty, player.isSecondaryUseActive());
|
||||||
|
data.put(blockId, currentProperty.name());
|
||||||
|
wrapped.setTag(data, "craftengine:debug_stick_state");
|
||||||
|
wrapped.load();
|
||||||
|
Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance(
|
||||||
|
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.select")
|
||||||
|
.arguments(
|
||||||
|
Component.text(currentProperty.name()),
|
||||||
|
Component.text(getNameHelper(clickedCustomBlock, currentProperty))
|
||||||
|
)), true);
|
||||||
|
player.sendPacket(systemChatPacket, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
plugin.logger().warn("Failed to send system chat packet", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> ImmutableBlockState cycleState(ImmutableBlockState state, Property<T> property, boolean inverse) {
|
||||||
|
return state.with(property, getRelative(property.possibleValues(), state.get(property), inverse));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T getRelative(Iterable<T> elements, @Nullable T current, boolean inverse) {
|
||||||
|
return inverse ? MCUtils.findPreviousInIterable(elements, current) : MCUtils.findNextInIterable(elements, current);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Comparable<T>> String getNameHelper(ImmutableBlockState state, Property<T> property) {
|
||||||
|
return property.valueName(state.get(property));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,31 +2,25 @@ package net.momirealms.craftengine.bukkit.item;
|
|||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
|
||||||
import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent;
|
import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent;
|
||||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||||
import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior;
|
import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||||
import net.momirealms.craftengine.bukkit.util.*;
|
import net.momirealms.craftengine.bukkit.util.*;
|
||||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
|
||||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
|
||||||
import net.momirealms.craftengine.core.block.properties.Property;
|
|
||||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||||
import net.momirealms.craftengine.core.item.CustomItem;
|
|
||||||
import net.momirealms.craftengine.core.item.Item;
|
import net.momirealms.craftengine.core.item.Item;
|
||||||
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||||
import net.momirealms.craftengine.core.util.Direction;
|
import net.momirealms.craftengine.core.util.Direction;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
import net.momirealms.craftengine.core.util.MCUtils;
|
|
||||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
|
||||||
import net.momirealms.craftengine.core.world.BlockHitResult;
|
import net.momirealms.craftengine.core.world.BlockHitResult;
|
||||||
import net.momirealms.craftengine.core.world.BlockPos;
|
import net.momirealms.craftengine.core.world.BlockPos;
|
||||||
import net.momirealms.craftengine.core.world.Vec3d;
|
import net.momirealms.craftengine.core.world.Vec3d;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -39,7 +33,6 @@ import org.bukkit.event.player.PlayerInteractEvent;
|
|||||||
import org.bukkit.inventory.EquipmentSlot;
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ItemEventListener implements Listener {
|
public class ItemEventListener implements Listener {
|
||||||
@@ -62,26 +55,28 @@ public class ItemEventListener implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
// it's breaking the block
|
||||||
|
if (action == Action.LEFT_CLICK_BLOCK && event.getPlayer().getGameMode() == GameMode.CREATIVE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CustomBlockInteractEvent interactEvent = new CustomBlockInteractEvent(
|
CustomBlockInteractEvent interactEvent = new CustomBlockInteractEvent(
|
||||||
event.getPlayer(),
|
event.getPlayer(),
|
||||||
block.getLocation(),
|
block.getLocation(),
|
||||||
event.getInteractionPoint(),
|
event.getInteractionPoint(),
|
||||||
BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId),
|
BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId),
|
||||||
hand,
|
event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND,
|
||||||
action == Action.RIGHT_CLICK_BLOCK ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK
|
action == Action.RIGHT_CLICK_BLOCK ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK
|
||||||
);
|
);
|
||||||
if (EventUtils.fireAndCheckCancel(interactEvent)) {
|
if (EventUtils.fireAndCheckCancel(interactEvent)) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
public void onInteractAtBlock(PlayerInteractEvent event) {
|
public void onInteractAtBlock(PlayerInteractEvent event) {
|
||||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
||||||
if (event.useItemInHand() == Event.Result.DENY) return;
|
if (event.useItemInHand() == Event.Result.DENY || event.useInteractedBlock() == Event.Result.DENY) return;
|
||||||
if (event.useInteractedBlock() == Event.Result.DENY) return;
|
|
||||||
Location interactionPoint = event.getInteractionPoint();
|
Location interactionPoint = event.getInteractionPoint();
|
||||||
if (interactionPoint == null) return;
|
if (interactionPoint == null) return;
|
||||||
Player bukkitPlayer = event.getPlayer();
|
Player bukkitPlayer = event.getPlayer();
|
||||||
@@ -90,49 +85,58 @@ public class ItemEventListener implements Listener {
|
|||||||
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
||||||
if (hand == InteractionHand.OFF_HAND) {
|
if (hand == InteractionHand.OFF_HAND) {
|
||||||
int currentTicks = player.gameTicks();
|
int currentTicks = player.gameTicks();
|
||||||
|
// The client will send multiple packets to the server if the client thinks it should
|
||||||
|
// However, if the main hand item interaction is successful, the off-hand item should be blocked.
|
||||||
if (!player.updateLastSuccessfulInteractionTick(currentTicks)) {
|
if (!player.updateLastSuccessfulInteractionTick(currentTicks)) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets the item in hand
|
||||||
Item<ItemStack> itemInHand = player.getItemInHand(hand);
|
Item<ItemStack> itemInHand = player.getItemInHand(hand);
|
||||||
if (itemInHand == null) return;
|
if (itemInHand == null) return;
|
||||||
Optional<CustomItem<ItemStack>> customItem = itemInHand.getCustomItem();
|
Optional<List<ItemBehavior>> optionalItemBehaviors = itemInHand.getItemBehavior();
|
||||||
|
|
||||||
Material material = itemInHand.getItem().getType();
|
// has custom item behavior
|
||||||
// is custom item
|
if (optionalItemBehaviors.isPresent()) {
|
||||||
if (customItem.isPresent()) {
|
// do not allow to place block if it's a vanilla block
|
||||||
if (material.isBlock()) {
|
if (itemInHand.isBlockItem() && itemInHand.isCustomItem()) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
CustomItem<ItemStack> item = customItem.get();
|
for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) {
|
||||||
BlockPos pos = LocationUtils.toBlockPos(clickedBlock.getLocation());
|
BlockPos pos = LocationUtils.toBlockPos(clickedBlock.getLocation());
|
||||||
Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ());
|
Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ());
|
||||||
Direction direction = DirectionUtils.toDirection(event.getBlockFace());
|
Direction direction = DirectionUtils.toDirection(event.getBlockFace());
|
||||||
BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false);
|
BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false);
|
||||||
if (!player.isSecondaryUseActive()) {
|
if (!player.isSecondaryUseActive()) {
|
||||||
if (InteractUtils.isInteractable(BlockStateUtils.getRealBlockId(clickedBlock), bukkitPlayer, clickedBlock.getBlockData(), hitResult, itemInHand)) return;
|
// if it's interactable on server, cancel the behaviors
|
||||||
|
if (InteractUtils.isInteractable(BlockStateUtils.getBlockOwnerId(clickedBlock), bukkitPlayer, clickedBlock.getBlockData(), hitResult, itemInHand)) return;
|
||||||
|
}
|
||||||
|
InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(player, hand, hitResult));
|
||||||
|
int maxY = player.level().worldHeight().getMaxBuildHeight() - 1;
|
||||||
|
if (direction == Direction.UP
|
||||||
|
&& result != InteractionResult.SUCCESS
|
||||||
|
&& pos.y() >= maxY
|
||||||
|
&& itemBehavior instanceof BlockItemBehavior
|
||||||
|
) {
|
||||||
|
player.sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED));
|
||||||
|
}
|
||||||
|
if (result != InteractionResult.PASS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
InteractionResult result = item.behavior().useOnBlock(new UseOnContext(player, hand, hitResult));
|
return;
|
||||||
int maxY = player.level().worldHeight().getMaxBuildHeight() - 1;
|
}
|
||||||
if (direction == Direction.UP
|
|
||||||
&& result != InteractionResult.SUCCESS
|
// it's a vanilla block
|
||||||
&& pos.y() >= maxY
|
if (itemInHand.isBlockItem() && !itemInHand.isCustomItem()) {
|
||||||
&& item.behavior() instanceof BlockItemBehavior
|
|
||||||
) {
|
|
||||||
player.sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED));
|
|
||||||
}
|
|
||||||
} else if (material.isBlock()) {
|
|
||||||
// vanilla item
|
|
||||||
// client won't have sounds if the fake block is interactable
|
// client won't have sounds if the fake block is interactable
|
||||||
|
// so we should check and resend sounds on interact
|
||||||
Object blockState = BlockStateUtils.blockDataToBlockState(clickedBlock.getBlockData());
|
Object blockState = BlockStateUtils.blockDataToBlockState(clickedBlock.getBlockData());
|
||||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||||
if (BlockStateUtils.isVanillaBlock(stateId)) {
|
ImmutableBlockState againCustomBlock = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||||
return;
|
if (againCustomBlock == null || againCustomBlock.isEmpty()) {
|
||||||
}
|
|
||||||
ImmutableBlockState againCustomBlock = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
|
||||||
if (againCustomBlock.isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BlockPos pos = LocationUtils.toBlockPos(clickedBlock.getLocation());
|
BlockPos pos = LocationUtils.toBlockPos(clickedBlock.getLocation());
|
||||||
@@ -140,7 +144,7 @@ public class ItemEventListener implements Listener {
|
|||||||
Direction direction = DirectionUtils.toDirection(event.getBlockFace());
|
Direction direction = DirectionUtils.toDirection(event.getBlockFace());
|
||||||
BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false);
|
BlockHitResult hitResult = new BlockHitResult(vec3d, direction, pos, false);
|
||||||
try {
|
try {
|
||||||
BlockData craftBlockData = (BlockData) Reflections.method$CraftBlockData$createData.invoke(null, againCustomBlock.vanillaBlockState().handle());
|
BlockData craftBlockData = BlockStateUtils.createBlockData(againCustomBlock.vanillaBlockState().handle());
|
||||||
if (InteractUtils.isInteractable(Key.of(clickedBlock.getType().getKey().asString()), bukkitPlayer, craftBlockData, hitResult, itemInHand)) {
|
if (InteractUtils.isInteractable(Key.of(clickedBlock.getType().getKey().asString()), bukkitPlayer, craftBlockData, hitResult, itemInHand)) {
|
||||||
if (!player.isSecondaryUseActive()) {
|
if (!player.isSecondaryUseActive()) {
|
||||||
player.setResendSound();
|
player.setResendSound();
|
||||||
@@ -155,92 +159,4 @@ public class ItemEventListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
|
||||||
public void onUseDebugStick(PlayerInteractEvent event) {
|
|
||||||
Block clickedBlock = event.getClickedBlock();
|
|
||||||
if (clickedBlock == null) return;
|
|
||||||
ItemStack itemInHand = event.getItem();
|
|
||||||
if (itemInHand == null) return;
|
|
||||||
Material material = itemInHand.getType();
|
|
||||||
if (material != Material.DEBUG_STICK) return;
|
|
||||||
Player bukkitPlayer = event.getPlayer();
|
|
||||||
BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer);
|
|
||||||
if (!(player.canInstabuild() && player.hasPermission("minecraft.debugstick")) && !player.hasPermission("minecraft.debugstick.always")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (event.getHand() == EquipmentSlot.OFF_HAND) {
|
|
||||||
int currentTicks = player.gameTicks();
|
|
||||||
if (!player.updateLastSuccessfulInteractionTick(currentTicks)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object blockState = BlockStateUtils.blockDataToBlockState(clickedBlock.getBlockData());
|
|
||||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
|
||||||
if (!BlockStateUtils.isVanillaBlock(stateId)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
boolean update = event.getAction() == Action.RIGHT_CLICK_BLOCK;
|
|
||||||
ImmutableBlockState clickedCustomBlock = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
|
||||||
CustomBlock block = clickedCustomBlock.owner().value();
|
|
||||||
Collection<Property<?>> properties = block.properties();
|
|
||||||
String blockId = block.id().toString();
|
|
||||||
try {
|
|
||||||
if (properties.isEmpty()) {
|
|
||||||
Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance(
|
|
||||||
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.empty").arguments(Component.text(blockId))), true);
|
|
||||||
player.sendPacket(systemChatPacket, false);
|
|
||||||
} else {
|
|
||||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(itemInHand);
|
|
||||||
Object storedData = wrapped.getTag("craftengine:debug_stick_state");
|
|
||||||
if (storedData == null) storedData = new HashMap<>();
|
|
||||||
if (storedData instanceof Map<?,?> map) {
|
|
||||||
Map<String, Object> data = MiscUtils.castToMap(map, false);
|
|
||||||
String currentPropertyName = (String) data.get(blockId);
|
|
||||||
Property<?> currentProperty = block.getProperty(currentPropertyName);
|
|
||||||
if (currentProperty == null) {
|
|
||||||
currentProperty = properties.iterator().next();
|
|
||||||
}
|
|
||||||
if (update) {
|
|
||||||
ImmutableBlockState nextState = cycleState(clickedCustomBlock, currentProperty, player.isSecondaryUseActive());
|
|
||||||
CraftEngineBlocks.place(clickedBlock.getLocation(), nextState, new UpdateOption.Builder().updateClients().updateKnownShape().build());
|
|
||||||
Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance(
|
|
||||||
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.update")
|
|
||||||
.arguments(
|
|
||||||
Component.text(currentProperty.name()),
|
|
||||||
Component.text(getNameHelper(nextState, currentProperty))
|
|
||||||
)), true);
|
|
||||||
player.sendPacket(systemChatPacket, false);
|
|
||||||
} else {
|
|
||||||
currentProperty = getRelative(properties, currentProperty, player.isSecondaryUseActive());
|
|
||||||
data.put(blockId, currentProperty.name());
|
|
||||||
wrapped.setTag(data, "craftengine:debug_stick_state");
|
|
||||||
wrapped.load();
|
|
||||||
Object systemChatPacket = Reflections.constructor$ClientboundSystemChatPacket.newInstance(
|
|
||||||
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.select")
|
|
||||||
.arguments(
|
|
||||||
Component.text(currentProperty.name()),
|
|
||||||
Component.text(getNameHelper(clickedCustomBlock, currentProperty))
|
|
||||||
)), true);
|
|
||||||
player.sendPacket(systemChatPacket, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
plugin.logger().warn("Failed to send system chat packet", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T extends Comparable<T>> ImmutableBlockState cycleState(ImmutableBlockState state, Property<T> property, boolean inverse) {
|
|
||||||
return state.with(property, getRelative(property.possibleValues(), state.get(property), inverse));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> T getRelative(Iterable<T> elements, @Nullable T current, boolean inverse) {
|
|
||||||
return inverse ? MCUtils.findPreviousInIterable(elements, current) : MCUtils.findNextInIterable(elements, current);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T extends Comparable<T>> String getNameHelper(ImmutableBlockState state, Property<T> property) {
|
|
||||||
return property.valueName(state.get(property));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package net.momirealms.craftengine.bukkit.item.behavior;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||||
|
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||||
|
import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.EventUtils;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.MaterialUtils;
|
||||||
|
import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||||
|
import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock;
|
||||||
|
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||||
|
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||||
|
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||||
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.item.Item;
|
||||||
|
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||||
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
|
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||||
|
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||||
|
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||||
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
import net.momirealms.craftengine.core.world.BlockPos;
|
||||||
|
import net.momirealms.craftengine.core.world.Vec3d;
|
||||||
|
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||||
|
import org.bukkit.GameEvent;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Statistic;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class AxeItemBehavior extends ItemBehavior {
|
||||||
|
public static final Factory FACTORY = new Factory();
|
||||||
|
public static final AxeItemBehavior INSTANCE = new AxeItemBehavior();
|
||||||
|
private static final Key AXE_STRIP_SOUND = Key.of("minecraft:item.axe.strip");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InteractionResult useOnBlock(UseOnContext context) {
|
||||||
|
BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(context.getClickedPos());
|
||||||
|
Block block = clicked.block();
|
||||||
|
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData()));
|
||||||
|
if (state == null || state.isEmpty()) return InteractionResult.PASS;
|
||||||
|
|
||||||
|
if (!(state.behavior() instanceof StrippableBlockBehavior blockBehavior)) {
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = context.getPlayer();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Item<ItemStack> offHandItem = (Item<ItemStack>) player.getItemInHand(InteractionHand.OFF_HAND);
|
||||||
|
// is using a shield
|
||||||
|
if (context.getHand() == InteractionHand.MAIN_HAND && offHandItem != null && offHandItem.vanillaId().equals(ItemKeys.SHIELD) && !player.isSecondaryUseActive()) {
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<CustomBlock> optionalNewCustomBlock = BukkitBlockManager.instance().getBlock(blockBehavior.stripped());
|
||||||
|
if (optionalNewCustomBlock.isEmpty()) {
|
||||||
|
CraftEngine.instance().logger().warn("stripped block " + blockBehavior.stripped() + " does not exist");
|
||||||
|
return InteractionResult.FAIL;
|
||||||
|
}
|
||||||
|
CustomBlock newCustomBlock = optionalNewCustomBlock.get();
|
||||||
|
CompoundTag compoundTag = state.propertiesNbt();
|
||||||
|
ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag);
|
||||||
|
|
||||||
|
org.bukkit.entity.Player bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer());
|
||||||
|
// Call bukkit event
|
||||||
|
EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, block, BlockStateUtils.createBlockData(newState.customBlockState().handle()));
|
||||||
|
if (EventUtils.fireAndCheckCancel(event)) {
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos pos = context.getClickedPos();
|
||||||
|
context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1);
|
||||||
|
CraftEngineBlocks.place(block.getLocation(), newState, UpdateOption.UPDATE_ALL_IMMEDIATE);
|
||||||
|
block.getWorld().sendGameEvent(bukkitPlayer, GameEvent.BLOCK_CHANGE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||||
|
Item<?> item = context.getItem();
|
||||||
|
Material material = MaterialUtils.getMaterial(item.vanillaId());
|
||||||
|
bukkitPlayer.setStatistic(Statistic.USE_ITEM, material, bukkitPlayer.getStatistic(Statistic.USE_ITEM, material) + 1);
|
||||||
|
|
||||||
|
ItemStack itemStack = (ItemStack) item.getItem();
|
||||||
|
itemStack.damage(1, bukkitPlayer);
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory implements ItemBehaviorFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemBehavior create(Key id, Map<String, Object> arguments) {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,10 +8,12 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
|||||||
public static final Key EMPTY = Key.from("craftengine:empty");
|
public static final Key EMPTY = Key.from("craftengine:empty");
|
||||||
public static final Key BLOCK_ITEM = Key.from("craftengine:block_item");
|
public static final Key BLOCK_ITEM = Key.from("craftengine:block_item");
|
||||||
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
|
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
|
||||||
|
public static final Key AXE_ITEM = Key.from("craftengine:axe_item");
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
register(EMPTY, (args, id) -> EmptyItemBehavior.INSTANCE);
|
register(EMPTY, (args, id) -> EmptyItemBehavior.INSTANCE);
|
||||||
register(BLOCK_ITEM, BlockItemBehavior.FACTORY);
|
register(BLOCK_ITEM, BlockItemBehavior.FACTORY);
|
||||||
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
|
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
|
||||||
|
register(AXE_ITEM, AxeItemBehavior.FACTORY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,11 @@ public abstract class BukkitItemFactory extends ItemFactory<CraftEngine, RTagIte
|
|||||||
return Optional.of(Key.of(id.toString()));
|
return Optional.of(Key.of(id.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isBlockItem(ItemWrapper<ItemStack> item) {
|
||||||
|
return item.getItem().getType().isBlock();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Key vanillaId(ItemWrapper<ItemStack> item) {
|
protected Key vanillaId(ItemWrapper<ItemStack> item) {
|
||||||
return Key.of(item.getItem().getType().getKey().asString());
|
return Key.of(item.getItem().getType().getKey().asString());
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ public class PacketConsumers {
|
|||||||
Key itemId = state.settings().itemId();
|
Key itemId = state.settings().itemId();
|
||||||
// no item available
|
// no item available
|
||||||
if (itemId == null) return;
|
if (itemId == null) return;
|
||||||
BlockData data = (BlockData) Reflections.method$CraftBlockData$createData.invoke(null, state.vanillaBlockState().handle());
|
BlockData data = BlockStateUtils.createBlockData(state.vanillaBlockState().handle());
|
||||||
// compare item
|
// compare item
|
||||||
if (data == null || !data.getMaterial().equals(item.getType())) return;
|
if (data == null || !data.getMaterial().equals(item.getType())) return;
|
||||||
ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, (BukkitServerPlayer) user);
|
ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, (BukkitServerPlayer) user);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import org.bukkit.inventory.EquipmentSlot;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.PlayerInventory;
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import org.bukkit.util.RayTraceResult;
|
import org.bukkit.util.RayTraceResult;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Reference;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@@ -360,7 +361,7 @@ public class BukkitServerPlayer extends Player {
|
|||||||
if (canInstabuild() && (itemMaterial == Material.DEBUG_STICK
|
if (canInstabuild() && (itemMaterial == Material.DEBUG_STICK
|
||||||
|| itemMaterial == Material.TRIDENT
|
|| itemMaterial == Material.TRIDENT
|
||||||
|| (VersionHelper.isVersionNewerThan1_20_5() && itemMaterial == MaterialUtils.MACE)
|
|| (VersionHelper.isVersionNewerThan1_20_5() && itemMaterial == MaterialUtils.MACE)
|
||||||
|| item.is(Key.of("minecraft:swords")))) {
|
|| item.is(ItemTags.SWORDS))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,6 +483,7 @@ public class BukkitServerPlayer extends Player {
|
|||||||
return DirectionUtils.toDirection(platformPlayer().getFacing());
|
return DirectionUtils.toDirection(platformPlayer().getFacing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Item<ItemStack> getItemInHand(InteractionHand hand) {
|
public Item<ItemStack> getItemInHand(InteractionHand hand) {
|
||||||
PlayerInventory inventory = platformPlayer().getInventory();
|
PlayerInventory inventory = platformPlayer().getInventory();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.bukkit.block.Block;
|
|||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
|
||||||
public class BlockStateUtils {
|
public class BlockStateUtils {
|
||||||
@@ -23,6 +24,14 @@ public class BlockStateUtils {
|
|||||||
hasInit = true;
|
hasInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BlockData createBlockData(Object blockState) {
|
||||||
|
try {
|
||||||
|
return (BlockData) Reflections.method$CraftBlockData$createData.invoke(null, blockState);
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int blockDataToId(BlockData blockData) {
|
public static int blockDataToId(BlockData blockData) {
|
||||||
try {
|
try {
|
||||||
Object blockState = Reflections.field$CraftBlockData$data.get(blockData);
|
Object blockState = Reflections.field$CraftBlockData$data.get(blockData);
|
||||||
@@ -32,13 +41,13 @@ public class BlockStateUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Key getRealBlockId(Block block) {
|
public static Key getBlockOwnerId(Block block) {
|
||||||
BlockData data = block.getBlockData();
|
BlockData data = block.getBlockData();
|
||||||
Object blockState = blockDataToBlockState(data);
|
Object blockState = blockDataToBlockState(data);
|
||||||
return getRealBlockIdFromState(blockState);
|
return getBlockOwnerIdFromState(blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Key getRealBlockIdFromState(Object blockState) {
|
public static Key getBlockOwnerIdFromState(Object blockState) {
|
||||||
String id = blockState.toString();
|
String id = blockState.toString();
|
||||||
int first = id.indexOf('{');
|
int first = id.indexOf('{');
|
||||||
int last = id.indexOf('}');
|
int last = id.indexOf('}');
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import java.util.Map;
|
|||||||
public class ItemTags {
|
public class ItemTags {
|
||||||
private static final Map<Key, Object> CACHE = new HashMap<>();
|
private static final Map<Key, Object> CACHE = new HashMap<>();
|
||||||
|
|
||||||
|
public static final Key AXES = Key.of("minecraft:axes");
|
||||||
|
public static final Key SWORDS = Key.of("minecraft:swords");
|
||||||
|
|
||||||
public static Object getOrCreate(Key key) {
|
public static Object getOrCreate(Key key) {
|
||||||
Object value = CACHE.get(key);
|
Object value = CACHE.get(key);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|||||||
@@ -2689,6 +2689,42 @@ public class Reflections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Class<?> clazz$EquipmentSlot = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz(
|
||||||
|
BukkitReflectionUtils.assembleMCClass("world.entity.EquipmentSlot"),
|
||||||
|
BukkitReflectionUtils.assembleMCClass("world.entity.EnumItemSlot")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Method method$EquipmentSlot$values = requireNonNull(
|
||||||
|
ReflectionUtils.getStaticMethod(
|
||||||
|
clazz$EquipmentSlot, clazz$EquipmentSlot.arrayType()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final Object instance$EquipmentSlot$MAINHAND;
|
||||||
|
public static final Object instance$EquipmentSlot$OFFHAND;
|
||||||
|
public static final Object instance$EquipmentSlot$FEET;
|
||||||
|
public static final Object instance$EquipmentSlot$LEGS;
|
||||||
|
public static final Object instance$EquipmentSlot$CHEST;
|
||||||
|
public static final Object instance$EquipmentSlot$HEAD;
|
||||||
|
// public static final Object instance$EquipmentSlot$BODY;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Object[] values = (Object[]) method$EquipmentSlot$values.invoke(null);
|
||||||
|
instance$EquipmentSlot$MAINHAND = values[0];
|
||||||
|
instance$EquipmentSlot$OFFHAND = values[1];
|
||||||
|
instance$EquipmentSlot$FEET = values[2];
|
||||||
|
instance$EquipmentSlot$LEGS = values[3];
|
||||||
|
instance$EquipmentSlot$CHEST = values[4];
|
||||||
|
instance$EquipmentSlot$HEAD = values[5];
|
||||||
|
// instance$EquipmentSlot$BODY = values[6];
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static final Method method$Block$defaultBlockState = requireNonNull(
|
public static final Method method$Block$defaultBlockState = requireNonNull(
|
||||||
ReflectionUtils.getMethod(
|
ReflectionUtils.getMethod(
|
||||||
clazz$Block, clazz$BlockState
|
clazz$Block, clazz$BlockState
|
||||||
@@ -4124,4 +4160,11 @@ public class Reflections {
|
|||||||
clazz$CraftInventoryCrafting, clazz$Container, 0
|
clazz$CraftInventoryCrafting, clazz$Container, 0
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$LivingEntity = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz(
|
||||||
|
BukkitReflectionUtils.assembleMCClass("world.entity.LivingEntity"),
|
||||||
|
BukkitReflectionUtils.assembleMCClass("world.entity.EntityLiving")
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class ImmutableBlockState extends BlockStateHolder {
|
|||||||
this.vanillaBlockState = vanillaBlockState;
|
this.vanillaBlockState = vanillaBlockState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompoundTag propertiesNbt() {
|
public CompoundTag propertiesNbt() {
|
||||||
CompoundTag properties = new CompoundTag();
|
CompoundTag properties = new CompoundTag();
|
||||||
for (Property<?> property : getProperties()) {
|
for (Property<?> property : getProperties()) {
|
||||||
Comparable<?> value = get(property);
|
Comparable<?> value = get(property);
|
||||||
|
|||||||
@@ -5,11 +5,13 @@ import net.momirealms.craftengine.core.entity.Entity;
|
|||||||
import net.momirealms.craftengine.core.item.Item;
|
import net.momirealms.craftengine.core.item.Item;
|
||||||
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||||
import net.momirealms.craftengine.core.world.BlockPos;
|
import net.momirealms.craftengine.core.world.BlockPos;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public abstract class Player extends Entity implements NetWorkUser {
|
public abstract class Player extends Entity implements NetWorkUser {
|
||||||
|
|
||||||
public abstract boolean isSecondaryUseActive();
|
public abstract boolean isSecondaryUseActive();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public abstract Item<?> getItemInHand(InteractionHand hand);
|
public abstract Item<?> getItemInHand(InteractionHand hand);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.momirealms.craftengine.core.item;
|
package net.momirealms.craftengine.core.item;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -42,6 +43,21 @@ public class AbstractItem<W extends ItemWrapper<I>, I> implements Item<I> {
|
|||||||
return ((ItemManager<I>) factory.plugin.itemManager()).getCustomItem(id());
|
return ((ItemManager<I>) factory.plugin.itemManager()).getCustomItem(id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<List<ItemBehavior>> getItemBehavior() {
|
||||||
|
return factory.plugin.itemManager().getItemBehavior(id());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCustomItem() {
|
||||||
|
return factory.plugin.itemManager().getCustomItem(id()).isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBlockItem() {
|
||||||
|
return factory.isBlockItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key id() {
|
public Key id() {
|
||||||
return this.factory.id(this.item);
|
return this.factory.id(this.item);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.entity.player.Player;
|
|||||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
import net.momirealms.craftengine.core.item.modifier.ItemModifier;
|
import net.momirealms.craftengine.core.item.modifier.ItemModifier;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ public interface CustomItem<I> extends BuildableItem<I> {
|
|||||||
|
|
||||||
Item<I> buildItem(Player player);
|
Item<I> buildItem(Player player);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
ItemBehavior behavior();
|
ItemBehavior behavior();
|
||||||
|
|
||||||
interface Builder<I> {
|
interface Builder<I> {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package net.momirealms.craftengine.core.item;
|
package net.momirealms.craftengine.core.item;
|
||||||
|
|
||||||
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
import net.momirealms.craftengine.core.util.Key;
|
import net.momirealms.craftengine.core.util.Key;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -16,6 +17,12 @@ public interface Item<I> {
|
|||||||
|
|
||||||
Optional<CustomItem<I>> getCustomItem();
|
Optional<CustomItem<I>> getCustomItem();
|
||||||
|
|
||||||
|
Optional<List<ItemBehavior>> getItemBehavior();
|
||||||
|
|
||||||
|
boolean isCustomItem();
|
||||||
|
|
||||||
|
boolean isBlockItem();
|
||||||
|
|
||||||
Key id();
|
Key id();
|
||||||
|
|
||||||
Key vanillaId();
|
Key vanillaId();
|
||||||
|
|||||||
@@ -102,4 +102,6 @@ public abstract class ItemFactory<P extends Plugin, W extends ItemWrapper<I>, I>
|
|||||||
protected abstract void maxStackSize(ItemWrapper<I> item, Integer maxStackSize);
|
protected abstract void maxStackSize(ItemWrapper<I> item, Integer maxStackSize);
|
||||||
|
|
||||||
protected abstract boolean is(ItemWrapper<I> item, Key itemTag);
|
protected abstract boolean is(ItemWrapper<I> item, Key itemTag);
|
||||||
|
|
||||||
|
protected abstract boolean isBlockItem(ItemWrapper<I> item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,4 +11,10 @@ public class ItemKeys {
|
|||||||
public static final Key FISHING_ROD = Key.of("minecraft:fishing_rod");
|
public static final Key FISHING_ROD = Key.of("minecraft:fishing_rod");
|
||||||
public static final Key ELYTRA = Key.of("minecraft:elytra");
|
public static final Key ELYTRA = Key.of("minecraft:elytra");
|
||||||
public static final Key GOAT_HORN = Key.of("minecraft:goat_horn");
|
public static final Key GOAT_HORN = Key.of("minecraft:goat_horn");
|
||||||
|
public static final Key WOODEN_AXE = Key.of("minecraft:wooden_axe");
|
||||||
|
public static final Key STONE_AXE = Key.of("minecraft:stone_axe");
|
||||||
|
public static final Key IRON_AXE = Key.of("minecraft:iron_axe");
|
||||||
|
public static final Key GOLDEN_AXE = Key.of("minecraft:golden_axe");
|
||||||
|
public static final Key DIAMOND_AXE = Key.of("minecraft:diamond_axe");
|
||||||
|
public static final Key NETHERITE_AXE = Key.of("minecraft:netherite_axe");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.momirealms.craftengine.core.item;
|
package net.momirealms.craftengine.core.item;
|
||||||
|
|
||||||
import net.momirealms.craftengine.core.entity.player.Player;
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
|
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||||
import net.momirealms.craftengine.core.pack.LegacyOverridesModel;
|
import net.momirealms.craftengine.core.pack.LegacyOverridesModel;
|
||||||
import net.momirealms.craftengine.core.pack.LoadingSequence;
|
import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||||
import net.momirealms.craftengine.core.pack.generator.ModelGenerator;
|
import net.momirealms.craftengine.core.pack.generator.ModelGenerator;
|
||||||
@@ -42,6 +43,8 @@ public interface ItemManager<T> extends Reloadable, ModelGenerator, ConfigSectio
|
|||||||
|
|
||||||
Optional<CustomItem<T>> getCustomItem(Key key);
|
Optional<CustomItem<T>> getCustomItem(Key key);
|
||||||
|
|
||||||
|
Optional<List<ItemBehavior>> getItemBehavior(Key key);
|
||||||
|
|
||||||
Optional<? extends BuildableItem<T>> getVanillaItem(Key key);
|
Optional<? extends BuildableItem<T>> getVanillaItem(Key key);
|
||||||
|
|
||||||
default Optional<? extends BuildableItem<T>> getBuildableItem(Key key) {
|
default Optional<? extends BuildableItem<T>> getBuildableItem(Key key) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
|||||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||||
import net.momirealms.craftengine.core.entity.player.Player;
|
import net.momirealms.craftengine.core.entity.player.Player;
|
||||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||||
import net.momirealms.craftengine.core.world.CEWorld;
|
import net.momirealms.craftengine.core.world.World;
|
||||||
|
|
||||||
public abstract class ItemBehavior {
|
public abstract class ItemBehavior {
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ public abstract class ItemBehavior {
|
|||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InteractionResult use(CEWorld context, Player player, InteractionHand hand) {
|
public InteractionResult use(World world, Player player, InteractionHand hand) {
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user