SuperLeadRope/src/main/java/top/r3944realms/superleadrope/content/item/SuperLeadRopeItem.java

237 lines
9.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Super Lead rope mod
* Copyright (C) 2025 R3944Realms
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package top.r3944realms.superleadrope.content.item;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TieredItem;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraftforge.common.extensions.IForgeItem;
import org.jetbrains.annotations.NotNull;
import top.r3944realms.superleadrope.api.SuperLeadRopeApi;
import top.r3944realms.superleadrope.api.type.capabilty.ILeashData;
import top.r3944realms.superleadrope.content.SLPToolTier;
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
import top.r3944realms.superleadrope.util.capability.LeashDataInnerAPI;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* The type Super lead rope item.
*/
//TODO:
// 1. 可抛掷使用 ***(下个版本实现)
// - 可转移拴绳
// 2. 多绑定(一个生物可以被多个加强拴绳绑定,产生共同作用效果)
// 3. 支持更多支撑方块
// 4. 可配置的生物栓效果(通过标签系统可配置哪些额外实体可被拴住)
// 5. 可自定义拴绳渲染位置(以匹配不同的生物模型)
// 6. 不可消耗的(但是有耐久,需要修复, 通过消耗原版拴绳恢复每次多重绑定就会消耗1点耐久
// 实现拴生物在生物的interact方法里去写相关逻辑
// 尝试0 mixin 实现 加强拴绳逻辑)
public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
// 配置常量
// 【手动调节,可以通过附魔获取更远抛掷和抛掷距离 - x1.3】//TODO:将可抛掷实现留到下次编写
// 可以做个大于一定距离时远距离使用时抛出拴绳的实体,击中生物才栓中的
private static final double SHORT_RANGE = 5.0D;
private static final float THROW_SPEED = 1.5F;
/**
* Instantiates a new Super lead rope item.
*
* @param pProperties the p properties
*/
public SuperLeadRopeItem(@NotNull Properties pProperties) {
super(SLPToolTier.STRING,
pProperties
.durability(1024)
.setNoRepair()
);
}
//通过按键 可抛掷启用/关闭实现不会影响use逻辑
@Override
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level pLevel, @NotNull Player pPlayer, @NotNull InteractionHand pUsedHand) {
ItemStack lead = pPlayer.getItemInHand(pUsedHand);
if(!pLevel.isClientSide) {
if (canUse(lead)) return InteractionResultHolder.pass(lead);
return super.use(pLevel, pPlayer, pUsedHand);
}
return InteractionResultHolder.success(lead);
}
/**
* Can use boolean.
*
* @param itemStack the item stack
* @return the boolean
*/
public static boolean canUse(@NotNull ItemStack itemStack) {
return itemStack.getDamageValue() < 1000;
}
@Override
public @NotNull InteractionResult useOn(@NotNull UseOnContext context) {
Level level = context.getLevel();
BlockPos pos = context.getClickedPos();
BlockState state = level.getBlockState(pos);
ItemStack itemStack = context.getItemInHand();
if (canUse(itemStack)) return InteractionResult.SUCCESS;
if(SuperLeashKnotEntity.isSupportBlock(state)) {
Player player = context.getPlayer();
if(!level.isClientSide && player != null) {
return bindToBlock(player, level, pos, itemStack, false) ? InteractionResult.CONSUME : InteractionResult.SUCCESS;
}
}
return InteractionResult.SUCCESS;
}
/**
* 右键蹲下绑定到另一实体上
*
* @param newHolder 新实体
* @param player 明确持有玩家
* @param level 维度世界
* @return 是否成功 boolean
*/
public static boolean bindToEntity(Entity newHolder, Player player, Level level) {
return bindToEntity(newHolder, player, level, player.getOnPos());
}
/**
* 右键蹲下绑定到另一实体上
*
* @param newHolder 新实体
* @param player 明确持有玩家
* @param level 维度世界
* @param pos 坐标(一般是明确持有玩家的位置)
* @return 是否成功 boolean
*/
public static boolean bindToEntity(Entity newHolder, Player player, Level level, BlockPos pos) {
boolean isSuccess = false;
// 查找当前玩家持有的可拴生物
List<Entity> list = SuperLeadRopeApi.leashableInArea(
level, pos.getCenter(),
entity -> SuperLeadRopeApi.isLeashHolder(entity, player.getUUID())
);
for (Entity e : list) {
Optional<ILeashData> leashDataOpt = LeashDataInnerAPI.getLeashData(e);
if (leashDataOpt.map(i -> i.canBeAttachedTo(newHolder)).orElse(false)) {
leashDataOpt.ifPresent(i -> i.transferLeash(player.getUUID(), newHolder));
isSuccess = true;
}
}
if (!isSuccess) {
return false;
} else {
level.gameEvent(GameEvent.ENTITY_INTERACT, pos, GameEvent.Context.of(player));
level.playSound(null, newHolder.getOnPos(), SLPSoundEvents.LEAD_UNTIED.get(), SoundSource.PLAYERS);
return true;
}
}
/**
* 右键蹲下绑定到支持方块上
*
* @param player 明确持有玩家
* @param level 维度世界
* @param leashStack 拴绳物品实例
* @param shouldBindSelf 是否应该触发拴自己逻辑检查
* @return 是否成功 boolean
*/
public static boolean bindToBlock(Player player, Level level, ItemStack leashStack, boolean shouldBindSelf) {
return bindToBlock(player, level, player.getOnPos(), leashStack, shouldBindSelf);
}
/**
* 右键蹲下绑定到支持方块上
*
* @param player 明确持有玩家
* @param level 维度世界
* @param pos 坐标(一般是明确持有玩家的位置)
* @param leashStack 拴绳物品实例
* @param shouldBindSelf 是否应该触发拴自己逻辑检查
* @return 是否成功 boolean
*/
public static boolean bindToBlock(Player player, Level level, BlockPos pos, ItemStack leashStack, boolean shouldBindSelf) {
SuperLeashKnotEntity knot = null;
AtomicBoolean isSuccess = new AtomicBoolean(false);
UUID uuid = player.getUUID();
List<Entity> list = SuperLeadRopeApi.leashableInArea(level, pos.getCenter(),
entity -> SuperLeadRopeApi.isLeashHolder(entity, uuid));
// 情况一:拴自己到新 knot
if (shouldBindSelf && list.isEmpty()) {
if (leashStack.isEmpty() || !canUse(leashStack)) {
return false;
}
knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);
knot.playPlacementSound();
SuperLeashKnotEntity finalKnot = knot;
LeashDataInnerAPI.getLeashData(player).ifPresent(i -> {
if (i.canBeAttachedTo(finalKnot)) {
if (!level.isClientSide) i.addLeash(finalKnot);
isSuccess.set(true);
}
});
}
// 情况二:把已有生物拴到 knot
else if (!list.isEmpty()) {
for (Entity e : list) {
if (knot == null) {
knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);
knot.playPlacementSound();
}
SuperLeashKnotEntity finalKnot = knot;
LeashDataInnerAPI.getLeashData(e).ifPresent(i -> {
if (i.canBeAttachedTo(finalKnot)) {
if (!level.isClientSide) i.transferLeash(uuid, finalKnot);
isSuccess.set(true);
}
});
}
}
if (isSuccess.get()) {
level.gameEvent(GameEvent.BLOCK_ATTACH, pos, GameEvent.Context.of(player));
return true;
}
return false;
}
}