feature: 1.添加了拴绳相关属性的配置 2.创建ILeashState实现自定义拴绳渲染位置(待关联)
refactor: 1.调整和优化两Cap的Nbt序列化实现 todo:1.渲染器相关代码并未清除(暂时) 2.永恒土豆待分离逻辑
This commit is contained in:
parent
0b5bde6047
commit
1a56faad9f
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-09-08T23:59:30.214676 Languages: zh_tw
|
||||
01bf653cea7c3be88445a248753b4cc75e5ac45e assets/superleadrope/lang/zh_tw.json
|
||||
// 1.20.1 2025-09-11T20:29:48.0546389 Languages: zh_tw
|
||||
852af450b5a31ef7436f17cb9e0d92d282e6831a assets/superleadrope/lang/zh_tw.json
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-09-08T23:59:30.214676 Languages: zh_cn
|
||||
6c4c5affb9dae3253eae9155ee4fb58deb5c4b92 assets/superleadrope/lang/zh_cn.json
|
||||
// 1.20.1 2025-09-11T20:29:48.04512 Languages: zh_cn
|
||||
78b1f4779544658700e3bf6e8f5f53ef15db7531 assets/superleadrope/lang/zh_cn.json
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-09-08T23:59:30.214676 Languages: lzh
|
||||
e7d897e78d2a100c249948780b7f1c07ad94e9b9 assets/superleadrope/lang/lzh.json
|
||||
// 1.20.1 2025-09-11T20:29:48.0526255 Languages: lzh
|
||||
f20f2b37e9d7bfc332b5c579573e6de9f4504996 assets/superleadrope/lang/lzh.json
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2025-09-08T23:59:30.214676 Languages: en_us
|
||||
9055e381f25bb65f46b6c4489800326812fd3659 assets/superleadrope/lang/en_us.json
|
||||
// 1.20.1 2025-09-11T20:29:48.0501199 Languages: en_us
|
||||
d0fa9a0b01c9a2057af32d116fc8fb4e63192fa8 assets/superleadrope/lang/en_us.json
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
"death.attack.eternal_potato_not_complete": "§c%1$s was not the rightful owner, struck by lightning!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s was not the rightful owner, struck by lightning!",
|
||||
"entity.superleadrope.super_lead_knot": "Super Lead Knot",
|
||||
"gamerule.slp.TeleportWithLeashedEntities": "Teleport leashed player with player holder",
|
||||
"gamerule.slp.TeleportWithLeashedEntities.description": "Holder will teleport with their leashed players ",
|
||||
"item.eternal_potato.msg.bind_msg": "§6Bound to you as the server-wide shared person.",
|
||||
"item.eternal_potato.msg.cannot_drop": "§cThe Eternal Potato cannot be dropped! +%d punishments.",
|
||||
"item.eternal_potato.msg.obligation_countdown": "Punish Countdown: §a%d §fseconds remaining",
|
||||
|
|
@ -22,5 +24,8 @@
|
|||
"item.superleadrope.super_lead_rope": "Super Lead Rope",
|
||||
"sound.superleadrope.subtitle.lead_break": "Lead Break",
|
||||
"sound.superleadrope.subtitle.lead_tied": "Lead Tied",
|
||||
"sound.superleadrope.subtitle.lead_untied": "Lead Untie"
|
||||
"sound.superleadrope.subtitle.lead_untied": "Lead Untie",
|
||||
"superleadrope.command.motion.message.adder.successful": "§bAdd Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.multiply.successful": "§bMultiply Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§bSet Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r"
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
"death.attack.eternal_potato_not_complete": "§c%1$s 非汝所主,雷霆降身!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s 非汝所主,雷霆降身!",
|
||||
"entity.superleadrope.super_lead_knot": "神駒羈縻索結",
|
||||
"gamerule.slp.TeleportWithLeashedEntities": "繫畜隨持者傳送",
|
||||
"gamerule.slp.TeleportWithLeashedEntities.description": "傳送時繫畜隨持者同傳",
|
||||
"item.eternal_potato.msg.bind_msg": "§6已与汝绑定,为全服共享之人。",
|
||||
"item.eternal_potato.msg.cannot_drop": "§c永恒土豆不可丟棄,懲罰數增加%d!",
|
||||
"item.eternal_potato.msg.obligation_countdown": "受罚倒数:§a%d §f瞬",
|
||||
|
|
@ -22,5 +24,8 @@
|
|||
"item.superleadrope.super_lead_rope": "神駒羈縻索",
|
||||
"sound.superleadrope.subtitle.lead_break": "索絕",
|
||||
"sound.superleadrope.subtitle.lead_tied": "繫索",
|
||||
"sound.superleadrope.subtitle.lead_untied": "解索"
|
||||
"sound.superleadrope.subtitle.lead_untied": "解索",
|
||||
"superleadrope.command.motion.message.adder.successful": "§b增益既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.multiply.successful": "§b倍乘既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§b定值既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r"
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
"death.attack.eternal_potato_not_complete": "§c%1$s 因使用非自己绑定物品,受到闪电惩罚!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s 因使用非自己绑定物品,受到闪电惩罚!",
|
||||
"entity.superleadrope.super_lead_knot": "超级拴绳结",
|
||||
"gamerule.slp.TeleportWithLeashedEntities": "被拴实体随玩家持有者传送",
|
||||
"gamerule.slp.TeleportWithLeashedEntities.description": "传送时将被拴实体与持有者一起传送",
|
||||
"item.eternal_potato.msg.bind_msg": "§6已与你绑定,成为全服共有之人。",
|
||||
"item.eternal_potato.msg.cannot_drop": "§c永恒土豆是不可丢弃的,惩罚数加%d!",
|
||||
"item.eternal_potato.msg.obligation_countdown": "惩罚倒计时: §a%d §f秒",
|
||||
|
|
@ -22,5 +24,8 @@
|
|||
"item.superleadrope.super_lead_rope": "超级拴绳",
|
||||
"sound.superleadrope.subtitle.lead_break": "拴绳断裂",
|
||||
"sound.superleadrope.subtitle.lead_tied": "拴绳系上",
|
||||
"sound.superleadrope.subtitle.lead_untied": "拴绳解开"
|
||||
"sound.superleadrope.subtitle.lead_untied": "拴绳解开",
|
||||
"superleadrope.command.motion.message.adder.successful": "§b添加成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.multiply.successful": "§b倍乘成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§b设置成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r"
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
"death.attack.eternal_potato_not_complete": "§c%1$s 因使用非自己綁定物品,受到閃電懲罰!",
|
||||
"death.attack.eternal_potato_not_owner": "§c%1$s 因使用非自己綁定物品,受到閃電懲罰!",
|
||||
"entity.superleadrope.super_lead_knot": "超級拴繩結",
|
||||
"gamerule.slp.TeleportWithLeashedEntities": "被拴实体随玩家持有者傳送",
|
||||
"gamerule.slp.TeleportWithLeashedEntities.description": "將被拴实体將隨持有者一起傳送",
|
||||
"item.eternal_potato.msg.bind_msg": "§6已與你綁定,成為全服共有之人。",
|
||||
"item.eternal_potato.msg.cannot_drop": "§c永恆土豆不可丟棄,懲罰數加%d!",
|
||||
"item.eternal_potato.msg.obligation_countdown": "懲罰倒計時: §a%d §f秒",
|
||||
|
|
@ -22,5 +24,8 @@
|
|||
"item.superleadrope.super_lead_rope": "超級拴繩",
|
||||
"sound.superleadrope.subtitle.lead_break": "拴繩斷裂",
|
||||
"sound.superleadrope.subtitle.lead_tied": "拴繩係上",
|
||||
"sound.superleadrope.subtitle.lead_untied": "拴繩解開"
|
||||
"sound.superleadrope.subtitle.lead_untied": "拴繩解開",
|
||||
"superleadrope.command.motion.message.adder.successful": "§b添加成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.multiply.successful": "§b倍乘成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"superleadrope.command.motion.message.setter.successful": "§b設置成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r"
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
package top.r3944realms.superleadrope;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
|
@ -35,6 +37,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.event.BuildCreativeModeTabContentsEvent;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.entity.EntityJoinLevelEvent;
|
||||
import net.minecraftforge.event.entity.EntityLeaveLevelEvent;
|
||||
|
|
@ -53,9 +56,11 @@ import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
|||
import top.r3944realms.superleadrope.content.capability.CapabilityRemainder;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.IEternalPotato;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
||||
import top.r3944realms.superleadrope.content.command.MotionCommand;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedPlayers;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedEntities;
|
||||
import top.r3944realms.superleadrope.content.item.EternalPotatoItem;
|
||||
import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem;
|
||||
import top.r3944realms.superleadrope.core.leash.LeashInteractHandler;
|
||||
|
|
@ -86,9 +91,10 @@ public class CommonEventHandler {
|
|||
Entity entity = event.getEntity();
|
||||
if (entity.level().isClientSide) return;
|
||||
if (entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart) {
|
||||
entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(LeashSyncManager::track);
|
||||
entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(LeashSyncManager.Data::track);
|
||||
entity.getCapability(CapabilityHandler.LEASH_STATE_CAP).ifPresent(LeashSyncManager.State::track);
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
LeashSyncManager.forEach(i -> {
|
||||
LeashSyncManager.Data.forEach(i -> {
|
||||
if (i.isLeashedBy(serverPlayer) && i.isInDelayedLeash(serverPlayer.getUUID())) {
|
||||
i.removeDelayedLeash(serverPlayer.getUUID());//重新加入去除延迟
|
||||
}
|
||||
|
|
@ -103,13 +109,14 @@ public class CommonEventHandler {
|
|||
if (entity.level().isClientSide) return;
|
||||
if (entity instanceof LivingEntity || entity instanceof Boat || entity instanceof Minecart) {
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
LeashSyncManager.forEach(i -> {
|
||||
LeashSyncManager.Data.forEach(i -> {
|
||||
if(i.isLeashedBy(serverPlayer)) {
|
||||
i.addDelayedLeash(serverPlayer); //添加延迟
|
||||
}
|
||||
});
|
||||
}
|
||||
entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(LeashSyncManager::untrack);
|
||||
entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(LeashSyncManager.Data::untrack);
|
||||
entity.getCapability(CapabilityHandler.LEASH_STATE_CAP).ifPresent(LeashSyncManager.State::untrack);
|
||||
}
|
||||
}
|
||||
@SubscribeEvent
|
||||
|
|
@ -142,7 +149,7 @@ public class CommonEventHandler {
|
|||
if (SuperLeashKnotEntity.isSupportBlock(blockState)) {
|
||||
boolean shouldConsume = SuperLeadRopeItem.bindToBlock(player, level, blockPos, event.getItemStack(), itemInHand.is(SLPItems.SUPER_LEAD_ROPE.get()));
|
||||
if (shouldConsume) {
|
||||
event.setCancellationResult(InteractionResult.CONSUME);
|
||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -248,7 +255,7 @@ public class CommonEventHandler {
|
|||
// 获取范围内可被拴住实体
|
||||
List<Entity> entities = LeashDataImpl.leashableInArea(telEntity);
|
||||
//规则关闭则禁止
|
||||
if(!SLPGameruleRegistry.getGameruleBoolValue(event.getEntity().level(), TeleportWithLeashedPlayers.ID)) {
|
||||
if(!SLPGameruleRegistry.getGameruleBoolValue(event.getEntity().level(), TeleportWithLeashedEntities.ID)) {
|
||||
entities.forEach(i -> i.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(j -> j.removeLeash(i)));
|
||||
return;
|
||||
}
|
||||
|
|
@ -260,7 +267,7 @@ public class CommonEventHandler {
|
|||
float originalPitch = beLeashedEntity.getXRot();
|
||||
Vec3 originalDeltaMovement = beLeashedEntity.getDeltaMovement();
|
||||
|
||||
AtomicReference<ILeashDataCapability.LeashInfo> originalLeashInfo = new AtomicReference<>();
|
||||
AtomicReference<ILeashData.LeashInfo> originalLeashInfo = new AtomicReference<>();
|
||||
beLeashedEntity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(cap -> {
|
||||
originalLeashInfo.set(cap.getLeashInfo(telEntity).orElse(null));
|
||||
cap.removeLeash(telEntity);
|
||||
|
|
@ -296,9 +303,9 @@ public class CommonEventHandler {
|
|||
}
|
||||
|
||||
// --- 恢复拴绳 ---
|
||||
ILeashDataCapability.LeashInfo leashInfo = Optional.ofNullable(originalLeashInfo.get())
|
||||
ILeashData.LeashInfo leashInfo = Optional.ofNullable(originalLeashInfo.get())
|
||||
.map(info -> info.transferHolder(telEntity))
|
||||
.orElse(ILeashDataCapability.LeashInfo.EMPTY);
|
||||
.orElse(ILeashData.LeashInfo.EMPTY);
|
||||
|
||||
beLeashedEntity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(
|
||||
cap -> cap.addLeash(telEntity, leashInfo)
|
||||
|
|
@ -321,14 +328,16 @@ public class CommonEventHandler {
|
|||
|
||||
// 每10 tick标记为脏(needsSync)
|
||||
if (tickCounter % 10 == 0) {
|
||||
LeashSyncManager.forEach(ILeashDataCapability::markForSync);
|
||||
LeashSyncManager.Data.forEach(ILeashData::markForSync);
|
||||
LeashSyncManager.State.forEach(ILeashState::markForSync);
|
||||
}
|
||||
|
||||
// 定期同步检查
|
||||
LeashSyncManager.forEach(ILeashDataCapability::checkSync);
|
||||
LeashSyncManager.Data.forEach(ILeashData::checkSync);
|
||||
LeashSyncManager.State.forEach(ILeashState::checkSync);
|
||||
|
||||
// 应用物理拉力/效果
|
||||
LeashSyncManager.forEach(ILeashDataCapability::applyLeashForces);
|
||||
LeashSyncManager.Data.forEach(ILeashData::applyLeashForces);
|
||||
}
|
||||
}
|
||||
@SubscribeEvent
|
||||
|
|
@ -344,6 +353,11 @@ public class CommonEventHandler {
|
|||
public static void attachCapability(AttachCapabilitiesEvent<?> event) {
|
||||
CapabilityHandler.attachCapability(event);
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void onRegisterCommand (RegisterCommandsEvent event) {
|
||||
CommandDispatcher<CommandSourceStack> dispatcher = event.getDispatcher();
|
||||
MotionCommand.register(dispatcher);
|
||||
}
|
||||
}
|
||||
@net.minecraftforge.fml.common.Mod.EventBusSubscriber(modid = SuperLeadRope.MOD_ID, bus= net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD)
|
||||
public static class Mod {
|
||||
|
|
@ -363,4 +377,4 @@ public class CommonEventHandler {
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
package top.r3944realms.superleadrope;
|
||||
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.config.ModConfig;
|
||||
|
|
@ -48,4 +49,15 @@ public class SuperLeadRope {
|
|||
ModLoadingContext modLoadingContext = ModLoadingContext.get();
|
||||
ConfigUtil.registerConfig(modLoadingContext, ModConfig.Type.COMMON, LeashCommonConfig.SPEC, c, "leash");
|
||||
}
|
||||
|
||||
public static class ModInfo {
|
||||
public static final String VERSION;
|
||||
static {
|
||||
// 从 ModList 获取当前 ModContainer 的元数据
|
||||
VERSION = ModList.get()
|
||||
.getModContainerById(MOD_ID)
|
||||
.map(c -> c.getModInfo().getVersion().toString())
|
||||
.orElse("UNKNOWN");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import net.minecraft.world.level.Level;
|
|||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.client.renderer.resolver.SuperLeashStateResolver;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
|
||||
import java.util.Optional;
|
||||
|
|
@ -49,15 +49,15 @@ public class LeashRenderHandler {
|
|||
cameraEntity.getBoundingBox().inflate(50))) {
|
||||
|
||||
entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(leashData -> {
|
||||
if(leashData instanceof ILeashDataCapability) {}
|
||||
for (ILeashDataCapability.LeashInfo leashInfo : leashData.getAllLeashes()) {
|
||||
if(leashData instanceof ILeashData) {}
|
||||
for (ILeashData.LeashInfo leashInfo : leashData.getAllLeashes()) {
|
||||
renderLeashFromInfo(entity, leashInfo, poseStack, bufferSource, partialTick);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderLeashFromInfo(Entity entity, ILeashDataCapability.LeashInfo leashInfo,
|
||||
private static void renderLeashFromInfo(Entity entity, ILeashData.LeashInfo leashInfo,
|
||||
PoseStack poseStack, MultiBufferSource bufferSource,
|
||||
float partialTick) {
|
||||
try {
|
||||
|
|
@ -67,7 +67,7 @@ public class LeashRenderHandler {
|
|||
Entity holder = holderOpt.get();
|
||||
|
||||
// 构建渲染状态
|
||||
SuperLeashStateResolver.resolve(entity, holder, leashInfo, partialTick).ifPresent(
|
||||
SuperLeashStateResolver.resolve(holder, entity, leashInfo, partialTick).ifPresent(
|
||||
leashRenderState -> SuperLeashRenderer.renderLeash(leashRenderState, poseStack, bufferSource)
|
||||
);
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ public class LeashRenderHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private static Optional<Entity> getHolderFromLeashInfo(Level level, ILeashDataCapability.LeashInfo leashInfo) {
|
||||
private static Optional<Entity> getHolderFromLeashInfo(Level level, ILeashData.LeashInfo leashInfo) {
|
||||
if (leashInfo.blockPosOpt().isPresent()) {
|
||||
BlockPos pos = leashInfo.blockPosOpt().get();
|
||||
return Optional.of(SuperLeashKnotEntity.getOrCreateKnot(level, pos));
|
||||
|
|
|
|||
|
|
@ -20,11 +20,15 @@ import net.minecraft.world.level.Level;
|
|||
import net.minecraft.world.phys.Vec3;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.client.renderer.state.SuperLeashRenderState;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
//TODO: 未来实现更高级的渲染
|
||||
public class SuperLeashStateResolver {
|
||||
private static final float MAX_TENSION = 1.5f;
|
||||
|
|
@ -44,18 +48,37 @@ public class SuperLeashStateResolver {
|
|||
public static Optional<SuperLeashRenderState> resolve(
|
||||
Entity holder,
|
||||
Entity leashedEntity,
|
||||
ILeashDataCapability.LeashInfo leashInfo,
|
||||
ILeashData.LeashInfo leashInfo,
|
||||
float partialTicks) {
|
||||
|
||||
if (holder == null || leashedEntity == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
AtomicReference<Vec3> holderOffset = new AtomicReference<>();
|
||||
AtomicReference<Vec3> entityOffset = new AtomicReference<>();
|
||||
LeashUtil.getLeashState(leashedEntity).ifPresent(state ->
|
||||
state
|
||||
.getLeashState(holder)
|
||||
.ifPresent(ls -> {
|
||||
holderOffset.set(
|
||||
Optional.ofNullable(ls.holderLocationOffset())
|
||||
.orElse(ls.defaultHolderLocationOffset())
|
||||
);
|
||||
entityOffset.set(
|
||||
Optional.ofNullable(ls.applyEntityLocationOffset())
|
||||
.orElse(
|
||||
state
|
||||
.getLeashApplyEntityLocationOffset()
|
||||
.orElse(state.getDefaultLeashApplyEntityLocationOffset())
|
||||
)
|
||||
);
|
||||
}
|
||||
));
|
||||
|
||||
// 获取当前帧位置(带插值)
|
||||
Vec3 currentHolderPos = getInterpolatedPosition(holder, partialTicks)
|
||||
.add(0, holder.getBbHeight() * 0.7, 0);
|
||||
Vec3 currentEntityPos = getInterpolatedPosition(leashedEntity, partialTicks)
|
||||
.add(leashInfo.attachOffset());
|
||||
Vec3 currentHolderPos = getInterpolatedPosition(holder, partialTicks).add(holderOffset.get());
|
||||
Vec3 currentEntityPos = getInterpolatedPosition(leashedEntity, partialTicks).add(entityOffset.get());
|
||||
|
||||
|
||||
// 获取上一帧数据
|
||||
FrameCache cache = frameCacheMap.get(leashedEntity.getUUID());
|
||||
|
|
@ -77,7 +100,7 @@ public class SuperLeashStateResolver {
|
|||
currentHolderPos, currentEntityPos,
|
||||
lastHolderPos, lastEntityPos,
|
||||
lastAngle, lastSpeed,
|
||||
tension, partialTicks);
|
||||
tension);
|
||||
|
||||
// 更新缓存
|
||||
frameCacheMap.put(leashedEntity.getUUID(),
|
||||
|
|
@ -108,7 +131,7 @@ public class SuperLeashStateResolver {
|
|||
Vec3 currentStart, Vec3 currentEnd,
|
||||
Vec3 lastStart, Vec3 lastEnd,
|
||||
float lastAngle, float lastSpeed,
|
||||
float tension, float partialTicks) {
|
||||
float tension) {
|
||||
|
||||
// 计算当前方向向量
|
||||
Vec3 currentDir = currentEnd.subtract(currentStart).normalize();
|
||||
|
|
@ -182,7 +205,7 @@ public class SuperLeashStateResolver {
|
|||
List<SuperLeashRenderState> states = new ArrayList<>();
|
||||
Level level = leashedEntity.level();
|
||||
|
||||
for (ILeashDataCapability.LeashInfo leashInfo : leashData.getAllLeashes()) {
|
||||
for (ILeashData.LeashInfo leashInfo : leashData.getAllLeashes()) {
|
||||
Entity holder = null;
|
||||
if (leashInfo.blockPosOpt().isEmpty() && leashInfo.holderIdOpt().isPresent()){
|
||||
holder = level.getEntity(leashInfo.holderIdOpt().get());
|
||||
|
|
|
|||
|
|
@ -30,27 +30,76 @@ public class LeashCommonConfig {
|
|||
}
|
||||
public static class Common {
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends String>> teleportWhitelist;
|
||||
|
||||
public final ForgeConfigSpec.ConfigValue<String> SLPModCommandPrefix;
|
||||
public final ForgeConfigSpec.BooleanValue EnableSLPModCommandPrefix;
|
||||
public final ForgeConfigSpec.DoubleValue maxLeashLength;
|
||||
public final ForgeConfigSpec.DoubleValue elasticDistance;
|
||||
public final ForgeConfigSpec.DoubleValue extremeSnapFactor;
|
||||
public final ForgeConfigSpec.DoubleValue springDampening;
|
||||
public final ForgeConfigSpec.ConfigValue<List<? extends Double>> axisSpecificElasticity;
|
||||
public final ForgeConfigSpec.IntValue maxLeashesPerEntity;
|
||||
public Common(ForgeConfigSpec.Builder builder) {
|
||||
builder.push("leash");
|
||||
|
||||
BUILDER.push("Command");
|
||||
EnableSLPModCommandPrefix = builder
|
||||
.comment("The prefix of this mod's commands")
|
||||
.define("SLPModCommandPrefix", true);
|
||||
SLPModCommandPrefix = builder
|
||||
.comment("The prefix of this mod's commands"," [ Default:'slp'] ")
|
||||
.define("EnableSLPModCommandPrefix", "slp");
|
||||
BUILDER.pop();
|
||||
builder.push("Entity");
|
||||
teleportWhitelist = builder
|
||||
.comment("Entity teleport whitelist.",
|
||||
"Use `#modid` to allow teleporting to all entities from a mod.",
|
||||
"Use `modid:entity_name` to allow teleporting to a specific entity.")
|
||||
.comment(
|
||||
"Entity teleport whitelist.",
|
||||
"Accepted formats:",
|
||||
" - #modid : allow teleporting to all entities from a specific mod",
|
||||
" - modid:entity_name : allow teleporting to a specific entity",
|
||||
" - #modid:tag_name : allow teleporting to all entities under a given entity type tag"
|
||||
)
|
||||
.defineListAllowEmpty(
|
||||
List.of("allowedTeleportEntities"),
|
||||
List.of("#minecraft", "modernlife:bicycle", "modernlife:motorboat"),
|
||||
o -> o instanceof String s && isValidFormat(s)
|
||||
);
|
||||
builder.pop();
|
||||
builder.push("LeashSettings");
|
||||
maxLeashLength = builder
|
||||
.comment("Maximum leash distance (in blocks) for any entity")
|
||||
.defineInRange("maxLeashLength", 12.0, 6.0, 256.0);
|
||||
elasticDistance = builder
|
||||
.comment("Default elastic distance for the Super Lead rope")
|
||||
.defineInRange("elasticDistance", 6.0, 6.0, 128.0);
|
||||
|
||||
extremeSnapFactor = builder
|
||||
.comment("Leash break factor = maxDistance * factor")
|
||||
.defineInRange("extremeSnapFactor", 2.0, 1.0, 4.0);
|
||||
|
||||
springDampening = builder
|
||||
.comment("Spring dampening coefficient")
|
||||
.defineInRange("springDampening", 0.7, 0.0, 1.0);
|
||||
|
||||
axisSpecificElasticity = builder
|
||||
.comment("Axis-specific elasticity coefficients for X,Y,Z axes")
|
||||
.defineList("axisSpecificElasticity", List.of(0.8, 0.2, 0.8), o -> o instanceof Double);
|
||||
|
||||
maxLeashesPerEntity = builder
|
||||
.comment("Maximum number of leashes per entity")
|
||||
.defineInRange("maxLeashesPerEntity", 6, 1, 24);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
|
||||
private static boolean isValidFormat(String s) {
|
||||
if (s.startsWith("#")) {
|
||||
return s.length() > 1 && s.substring(1).matches("[a-z0-9_]+");
|
||||
String body = s.substring(1);
|
||||
// 支持 #modid (整个模组)
|
||||
if (body.matches("[a-z0-9_]+")) {
|
||||
return true;
|
||||
}
|
||||
// 支持 #modid:tag_name (标签)
|
||||
return body.matches("[a-z0-9_]+:[a-z0-9_/]+");
|
||||
}
|
||||
// 普通实体 ID
|
||||
return s.matches("[a-z0-9_]+:[a-z0-9_/]+");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,17 +24,21 @@ import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
|||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.IEternalPotato;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
||||
import top.r3944realms.superleadrope.content.capability.provider.EternalPotatoProvider;
|
||||
import top.r3944realms.superleadrope.content.capability.provider.LeashDataProvider;
|
||||
import top.r3944realms.superleadrope.content.capability.provider.LeashStateProvider;
|
||||
import top.r3944realms.superleadrope.content.item.EternalPotatoItem;
|
||||
|
||||
public class CapabilityHandler {
|
||||
public static final Capability<ILeashDataCapability> LEASH_DATA_CAP = CapabilityManager.get(new CapabilityToken<>(){});
|
||||
public static final Capability<ILeashData> LEASH_DATA_CAP = CapabilityManager.get(new CapabilityToken<>(){});
|
||||
public static Capability<ILeashState> LEASH_STATE_CAP = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
public static Capability<IEternalPotato> ETERNAL_POTATO_CAP = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
public static void registerCapability(RegisterCapabilitiesEvent event) {
|
||||
event.register(ILeashDataCapability.class);
|
||||
event.register(ILeashData.class);
|
||||
event.register(IEternalPotato.class);
|
||||
event.register(ILeashState.class);
|
||||
}
|
||||
|
||||
public static void attachCapability(AttachCapabilitiesEvent<?> event) {
|
||||
|
|
@ -43,6 +47,7 @@ public class CapabilityHandler {
|
|||
(LeashDataImpl.isLeashable(entity))//只对活体 船 矿车添加CAP
|
||||
) {
|
||||
event.addCapability(LeashDataProvider.LEASH_DATA_REL, new LeashDataProvider(entity));
|
||||
event.addCapability(LeashStateProvider.LEASH_STATE_REL, new LeashStateProvider(entity));
|
||||
} else if (object instanceof ItemStack stack && stack.getItem() instanceof EternalPotatoItem) {
|
||||
event.addCapability(EternalPotatoProvider.ETERNAL_POTATO_DATA_REL, new EternalPotatoProvider(stack));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,25 @@
|
|||
|
||||
package top.r3944realms.superleadrope.content.capability;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashUtil;
|
||||
|
||||
public class CapabilityRemainder {
|
||||
public static void onPlayerClone(PlayerEvent.Clone event) {
|
||||
if (event.isWasDeath()) {
|
||||
//
|
||||
Player newEntity = event.getEntity();
|
||||
if(newEntity instanceof ServerPlayer newPlayer) {
|
||||
Player original = event.getOriginal();
|
||||
original.reviveCaps();
|
||||
LeashUtil.getLeashState(original)
|
||||
.ifPresent(oldCap ->
|
||||
LeashUtil.getLeashState(newPlayer)
|
||||
.ifPresent(newData ->
|
||||
newData.copy(oldCap, newEntity)
|
||||
)
|
||||
);
|
||||
original.invalidateCaps();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package top.r3944realms.superleadrope.content.capability.impi;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
|
@ -28,7 +29,6 @@ import net.minecraft.world.entity.animal.horse.Llama;
|
|||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.vehicle.Boat;
|
||||
import net.minecraft.world.entity.vehicle.Minecart;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
|
@ -36,17 +36,21 @@ import net.minecraftforge.network.PacketDistributor;
|
|||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.config.LeashCommonConfig;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
import top.r3944realms.superleadrope.network.NetworkHandler;
|
||||
import top.r3944realms.superleadrope.network.toClient.LeashDataSyncPacket;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashUtil;
|
||||
import top.r3944realms.superleadrope.util.nbt.NBTReader;
|
||||
import top.r3944realms.superleadrope.util.nbt.NBTWriter;
|
||||
import top.r3944realms.superleadrope.util.riding.RindingLeash;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
|
@ -80,12 +84,35 @@ import java.util.stream.Stream;
|
|||
* </tbody>
|
||||
* </table>
|
||||
*/
|
||||
public class LeashDataImpl implements ILeashDataCapability {
|
||||
private static final double LEASH_ELASTIC_DIST = 6.0; // 弹性距离
|
||||
private static final double LEASH_EXTREME_SNAP_DIST_FACTOR = 2.0; // 断裂距离 = 最大距离 * 2 //TODO:未来可配置
|
||||
private static final float SPRING_DAMPENING = 0.7f; // 阻尼系数
|
||||
private static final Vec3 AXIS_SPECIFIC_ELASTICITY = new Vec3(0.8, 0.2, 0.8); // 轴向弹性系数(Y轴较弱)
|
||||
private static final int MAX_LEASHES_PER_ENTITY = 6;//一个实体最多链接多少个拴绳 //TODO:未来可配置
|
||||
public class LeashDataImpl implements ILeashData {
|
||||
private static final class Config {
|
||||
private Config() {} // 私有构造防止实例化
|
||||
|
||||
static double maxLeashDistance() {
|
||||
return LeashCommonConfig.COMMON.maxLeashLength.get();
|
||||
}
|
||||
|
||||
static double leashElasticDist() {
|
||||
return LeashCommonConfig.COMMON.elasticDistance.get();
|
||||
}
|
||||
|
||||
static double leashExtremeSnapDistFactor() {
|
||||
return LeashCommonConfig.COMMON.extremeSnapFactor.get();
|
||||
}
|
||||
|
||||
static double springDampening() {
|
||||
return LeashCommonConfig.COMMON.springDampening.get();
|
||||
}
|
||||
|
||||
static Vec3 axisSpecificElasticity() {
|
||||
List<? extends Double> list = LeashCommonConfig.COMMON.axisSpecificElasticity.get();
|
||||
return new Vec3(list.get(0), list.get(1), list.get(2));
|
||||
}
|
||||
|
||||
static int maxLeashesPerEntity() {
|
||||
return LeashCommonConfig.COMMON.maxLeashesPerEntity.get();
|
||||
}
|
||||
}
|
||||
private final Entity entity;
|
||||
private boolean needsSync = false;
|
||||
private long lastSyncTime;
|
||||
|
|
@ -93,11 +120,11 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
private final Map<UUID, LeashInfo> leashHolders = new ConcurrentHashMap<>();
|
||||
// 引入解决 绳结不保存导致第二进入持有者不存在的问题
|
||||
private final Map<BlockPos, LeashInfo> leashKnots = new ConcurrentHashMap<>();
|
||||
// private CompoundTag lastSyncedData = new CompoundTag();
|
||||
|
||||
public LeashDataImpl(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markForSync() {
|
||||
if (!entity.level().isClientSide) {
|
||||
|
|
@ -106,13 +133,17 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
}
|
||||
|
||||
/** 立即同步,无视时间间隔 */
|
||||
/**
|
||||
* 立即同步,无视时间间隔
|
||||
*/
|
||||
@Override
|
||||
public void immediateSync() {
|
||||
syncNow();
|
||||
}
|
||||
|
||||
/** 定期调用,每 tick 或每几秒检测 */
|
||||
/**
|
||||
* 定期调用,每 tick 或每几秒检测
|
||||
*/
|
||||
@Override
|
||||
public void checkSync() {
|
||||
if (!needsSync || entity.level().isClientSide) return;
|
||||
|
|
@ -124,7 +155,9 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
}
|
||||
|
||||
/** 内部统一同步方法,避免重复逻辑 */
|
||||
/**
|
||||
* 内部统一同步方法,避免重复逻辑
|
||||
*/
|
||||
private void syncNow() {
|
||||
CompoundTag currentData = serializeNBT();
|
||||
|
||||
|
|
@ -137,19 +170,44 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
needsSync = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addLeash(Entity holder) {
|
||||
return addLeash(holder, Config.maxLeashDistance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addLeash(Entity holder, String reserved) {
|
||||
return addLeash(holder, Config.maxLeashDistance(), reserved);
|
||||
}
|
||||
|
||||
// 添加拴绳(支持自定义最大长度)
|
||||
@Override
|
||||
public boolean addLeash(Entity holder, double maxDistance) {
|
||||
return addLeash(holder, maxDistance, Config.leashElasticDist(), 0, "");
|
||||
}
|
||||
|
||||
// 添加拴绳(支持自定义最大长度和弹性距离)
|
||||
@Override
|
||||
public boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance) {
|
||||
boolean result = addLeash(holder, leashStack, maxDistance, LEASH_ELASTIC_DIST, 0);
|
||||
if (result) markForSync();
|
||||
return result;
|
||||
public boolean addLeash(Entity holder, double maxDistance, double elasticDistance, int maxKeepLeashTicks) {
|
||||
return addLeash(holder, maxDistance, elasticDistance, maxKeepLeashTicks, "");
|
||||
}
|
||||
|
||||
// 添加拴绳(支持自定义最大长度 + reserved 字段)
|
||||
@Override
|
||||
public boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance, double elasticDistance, int maxKeepLeashTicks) {
|
||||
public boolean addLeash(Entity holder, double maxDistance, String reserved) {
|
||||
return addLeash(holder, maxDistance, Config.leashElasticDist(), 0, reserved);
|
||||
}
|
||||
|
||||
// 添加拴绳(最终实现:支持最大长度、弹性距离、保持 Tick、reserved)
|
||||
@Override
|
||||
public boolean addLeash(Entity holder, double maxDistance,
|
||||
double elasticDistance, int maxKeepLeashTicks, String reserved) {
|
||||
boolean isSuperKnot = holder instanceof SuperLeashKnotEntity;
|
||||
if ((!isSuperKnot && leashHolders.containsKey(holder.getUUID()) || (isSuperKnot && leashKnots.containsKey(((SuperLeashKnotEntity) holder).getPos())))) {
|
||||
if ((!isSuperKnot && leashHolders.containsKey(holder.getUUID()))
|
||||
|| (isSuperKnot && leashKnots.containsKey(((SuperLeashKnotEntity) holder).getPos()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!canBeLeashed()) {
|
||||
Optional<UUID> uuidOptional = occupyLeash();
|
||||
if (uuidOptional.isEmpty()) {
|
||||
|
|
@ -157,36 +215,62 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
removeLeash(uuidOptional.get());
|
||||
}
|
||||
LeashInfo info = LeashInfo.CreateLeashInfo(
|
||||
|
||||
LeashInfo info = LeashInfo.create(
|
||||
holder,
|
||||
leashStack.getItem().getDescription().toString(),
|
||||
reserved,
|
||||
calculateAttachOffset(entity),
|
||||
maxDistance,
|
||||
elasticDistance,
|
||||
maxKeepLeashTicks,
|
||||
maxKeepLeashTicks
|
||||
);
|
||||
if (holder instanceof SuperLeashKnotEntity s) {
|
||||
leashKnots.put(s.getPos(), info);
|
||||
|
||||
if (isSuperKnot) {
|
||||
leashKnots.put(((SuperLeashKnotEntity) holder).getPos(), info);
|
||||
} else {
|
||||
leashHolders.put(holder.getUUID(), info);
|
||||
}
|
||||
else leashHolders.put(holder.getUUID(), info);
|
||||
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 使用已有的 LeashInfo 添加拴绳(直接走最终实现)
|
||||
@Override
|
||||
public boolean addLeash(Entity holder, LeashInfo leashInfo) {
|
||||
return addLeash(holder, ItemStack.EMPTY, leashInfo.maxDistance(), leashInfo.elasticDistance(), leashInfo.maxKeepLeashTicks());
|
||||
public void addLeash(Entity holder, LeashInfo leashInfo) {
|
||||
addLeash(holder,
|
||||
leashInfo.maxDistance(),
|
||||
leashInfo.elasticDistance(),
|
||||
leashInfo.maxKeepLeashTicks(),
|
||||
leashInfo.reserved()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDelayedLeash(Player holderPlayer) {
|
||||
return delayedHolders.add(holderPlayer.getUUID());
|
||||
public void addDelayedLeash(Player holderPlayer) {
|
||||
delayedHolders.add(holderPlayer.getUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeDelayedLeash(UUID onceHolderUUID) {
|
||||
return delayedHolders.remove(onceHolderUUID);
|
||||
public void removeDelayedLeash(UUID onceHolderUUID) {
|
||||
delayedHolders.remove(onceHolderUUID);
|
||||
}
|
||||
|
||||
private <K> boolean updateLeashInfo(
|
||||
Map<K, LeashInfo> map,
|
||||
K key,
|
||||
Function<LeashInfo, LeashInfo> updater
|
||||
) {
|
||||
LeashInfo old = map.get(key);
|
||||
if (old == null || old.holderIdOpt().isEmpty()) return false;
|
||||
|
||||
LeashInfo updated = updater.apply(old);
|
||||
if (updated == null) return false;
|
||||
|
||||
map.put(key, updated);
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -203,76 +287,101 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
setMaxDistance(holder.getUUID(), newMaxDistance, newMaxKeepLeashTicks);
|
||||
}
|
||||
|
||||
// 动态修改最大拴绳长度
|
||||
@Override
|
||||
public boolean setMaxDistance(Entity holder, double distance, int maxKeepTicks, String reserved) {
|
||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||
setMaxDistance(superLeashKnotEntity.getPos(), distance, maxKeepTicks, reserved) :
|
||||
setMaxDistance(holder.getUUID(), distance, maxKeepTicks, reserved);
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setMaxDistance(UUID holderUUID, double newMaxDistance) {
|
||||
LeashInfo info = leashHolders.get(holderUUID);
|
||||
if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
leashHolders.put(holderUUID, new LeashInfo(
|
||||
info.holderUUIDOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||
old.holderUUIDOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
newMaxDistance,
|
||||
info.elasticDistance(), // 保持原有弹性距离
|
||||
info.keepLeashTicks(),
|
||||
info.maxKeepLeashTicks()
|
||||
old.elasticDistance(),
|
||||
old.keepLeashTicks(),
|
||||
old.maxKeepLeashTicks()
|
||||
));
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setMaxDistance(UUID holderUUID, double newMaxDistance, int newMaxKeepLeashTicks) {
|
||||
LeashInfo info = leashHolders.get(holderUUID);
|
||||
if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
leashHolders.put(holderUUID, new LeashInfo(
|
||||
info.holderUUIDOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||
old.holderUUIDOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
newMaxDistance,
|
||||
info.elasticDistance(), // 保持原有弹性距离
|
||||
newMaxKeepLeashTicks,
|
||||
info.maxKeepLeashTicks()
|
||||
));
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance) {
|
||||
LeashInfo info = leashKnots.get(knotPos);
|
||||
if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
leashKnots.put(knotPos, new LeashInfo(
|
||||
info.blockPosOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
newMaxDistance,
|
||||
info.elasticDistance(), // 保持原有弹性距离
|
||||
info.keepLeashTicks(),
|
||||
info.maxKeepLeashTicks()
|
||||
));
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance, int newMaxKeepLeashTicks) {
|
||||
LeashInfo info = leashKnots.get(knotPos);
|
||||
if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
leashKnots.put(knotPos, new LeashInfo(
|
||||
info.blockPosOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
newMaxDistance,
|
||||
info.elasticDistance(), // 保持原有弹性距离
|
||||
info.keepLeashTicks(),
|
||||
old.elasticDistance(),
|
||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||
newMaxKeepLeashTicks
|
||||
));
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setMaxDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved) {
|
||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||
old.holderUUIDOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
reserved,
|
||||
old.attachOffset(),
|
||||
distance,
|
||||
old.elasticDistance(),
|
||||
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
||||
maxKeepTicks
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance) {
|
||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||
old.blockPosOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
newMaxDistance,
|
||||
old.elasticDistance(),
|
||||
old.keepLeashTicks(),
|
||||
old.maxKeepLeashTicks()
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setMaxDistance(BlockPos knotPos, double newMaxDistance, int newMaxKeepLeashTicks) {
|
||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||
old.blockPosOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
newMaxDistance,
|
||||
old.elasticDistance(),
|
||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||
newMaxKeepLeashTicks
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setMaxDistance(BlockPos knotPos, double distance, int maxKeepTicks, String reserved) {
|
||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||
old.blockPosOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
reserved,
|
||||
old.attachOffset(),
|
||||
distance,
|
||||
old.elasticDistance(),
|
||||
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
||||
maxKeepTicks
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -283,42 +392,34 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
|
||||
// 动态修改弹性距离
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setElasticDistance(UUID holderUUID, double newElasticDistance) {
|
||||
LeashInfo info = leashHolders.get(holderUUID);
|
||||
if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
|
||||
leashHolders.put(holderUUID, new LeashInfo(
|
||||
info.holderUUIDOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
info.maxDistance(),
|
||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||
old.holderUUIDOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
old.maxDistance(),
|
||||
newElasticDistance,
|
||||
info.keepLeashTicks(),
|
||||
info.maxKeepLeashTicks()
|
||||
old.keepLeashTicks(),
|
||||
old.maxKeepLeashTicks()
|
||||
));
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance) {
|
||||
LeashInfo info = leashKnots.get(knotPos);
|
||||
if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
|
||||
leashKnots.put(knotPos, new LeashInfo(
|
||||
info.blockPosOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
info.maxDistance(),
|
||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||
old.blockPosOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
old.maxDistance(),
|
||||
newElasticDistance,
|
||||
info.keepLeashTicks(),
|
||||
info.maxKeepLeashTicks()
|
||||
old.keepLeashTicks(),
|
||||
old.maxKeepLeashTicks()
|
||||
));
|
||||
markForSync();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -328,41 +429,72 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
setElasticDistance(holder.getUUID(), newElasticDistance, newMaxKeepLeashTicks);
|
||||
}
|
||||
|
||||
// 动态修改弹性距离
|
||||
@Override
|
||||
public boolean setElasticDistance(UUID holderUUID, double newElasticDistance, int newMaxKeepLeashTicks) {
|
||||
LeashInfo info = leashHolders.get(holderUUID);
|
||||
if (info == null || info.holderUUIDOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
|
||||
leashHolders.put(holderUUID, new LeashInfo(
|
||||
info.holderUUIDOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
info.maxDistance(),
|
||||
newElasticDistance,
|
||||
Math.min(info.keepLeashTicks(), newMaxKeepLeashTicks), // 限制剩余Tick不超过新最大值
|
||||
newMaxKeepLeashTicks
|
||||
));
|
||||
return true;
|
||||
public boolean setElasticDistance(Entity holder, double distance, int maxKeepTicks, String reserved) {
|
||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||
setElasticDistance(superLeashKnotEntity.getPos(), distance, maxKeepTicks, reserved) :
|
||||
setElasticDistance(holder.getUUID(), distance, maxKeepTicks, reserved);
|
||||
}
|
||||
|
||||
// 动态修改弹性距离
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks) {
|
||||
LeashInfo info = leashKnots.get(knotPos);
|
||||
if (info == null || info.blockPosOpt().isEmpty() || info.holderIdOpt().isEmpty()) return false;
|
||||
|
||||
leashKnots.put(knotPos, new LeashInfo(
|
||||
info.blockPosOpt().get(),
|
||||
info.holderIdOpt().get(),
|
||||
info.reserved(),
|
||||
info.attachOffset(),
|
||||
info.maxDistance(),
|
||||
public boolean setElasticDistance(UUID holderUUID, double newElasticDistance, int newMaxKeepLeashTicks) {
|
||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||
old.holderUUIDOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
old.maxDistance(),
|
||||
newElasticDistance,
|
||||
Math.min(info.keepLeashTicks(), newMaxKeepLeashTicks), // 限制剩余Tick不超过新最大值
|
||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||
newMaxKeepLeashTicks
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setElasticDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved) {
|
||||
return updateLeashInfo(leashHolders, holderUUID, old -> new LeashInfo(
|
||||
old.holderUUIDOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
reserved,
|
||||
old.attachOffset(),
|
||||
old.maxDistance(),
|
||||
distance,
|
||||
Math.min(old.keepLeashTicks(), maxKeepTicks),
|
||||
maxKeepTicks
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks) {
|
||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||
old.blockPosOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
old.reserved(),
|
||||
old.attachOffset(),
|
||||
old.maxDistance(),
|
||||
newElasticDistance,
|
||||
old.keepLeashTicks(),
|
||||
old.maxKeepLeashTicks()
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("OptionalGetWithoutIsPresent")
|
||||
@Override
|
||||
public boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks, String reserved) {
|
||||
return updateLeashInfo(leashKnots, knotPos, old -> new LeashInfo(
|
||||
old.blockPosOpt().get(),
|
||||
old.holderIdOpt().get(),
|
||||
reserved,
|
||||
old.attachOffset(),
|
||||
old.maxDistance(),
|
||||
newElasticDistance,
|
||||
Math.min(old.keepLeashTicks(), newMaxKeepLeashTicks),
|
||||
newMaxKeepLeashTicks
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -439,14 +571,14 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
LeashInfo info = entry.getValue();
|
||||
Vec3 entityPos = entity.position().add(info.attachOffset());
|
||||
double distance = holderPos.distanceTo(entityPos);
|
||||
double extremeSnapDist = info.maxDistance() * LEASH_EXTREME_SNAP_DIST_FACTOR;
|
||||
double extremeSnapDist = info.maxDistance() * Config.leashExtremeSnapDistFactor();
|
||||
|
||||
// 1. 检查是否超出断裂距离
|
||||
if (distance > extremeSnapDist) {
|
||||
if (info.keepLeashTicks() > 0) {
|
||||
// 计算临界拉力
|
||||
Vec3 pullForce = calculateCriticalPullForce(holderPos, entityPos, distance, info);
|
||||
entry.setValue(info.decrementKeepLeashTicks());
|
||||
entry.setValue(info.decrementKeepTicks());
|
||||
return pullForce;
|
||||
}
|
||||
// 断裂
|
||||
|
|
@ -471,7 +603,7 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
|
||||
// 3. 重置缓冲Tick
|
||||
if (distance <= info.maxDistance() && info.keepLeashTicks() < info.maxKeepLeashTicks()) {
|
||||
entry.setValue(info.resetKeepLeashTicks());
|
||||
entry.setValue(info.resetKeepTicks());
|
||||
}
|
||||
|
||||
return pullForce;
|
||||
|
|
@ -489,13 +621,13 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
|
||||
Vec3 pullForce = pullDirection.scale(
|
||||
(distance - info.elasticDistance()) * pullStrength * SPRING_DAMPENING
|
||||
(distance - info.elasticDistance()) * pullStrength * Config.springDampening()
|
||||
);
|
||||
|
||||
return new Vec3(
|
||||
pullForce.x * AXIS_SPECIFIC_ELASTICITY.x,
|
||||
pullForce.y * AXIS_SPECIFIC_ELASTICITY.y,
|
||||
pullForce.z * AXIS_SPECIFIC_ELASTICITY.z
|
||||
pullForce.x * Config.axisSpecificElasticity().x,
|
||||
pullForce.y * Config.axisSpecificElasticity().y,
|
||||
pullForce.z * Config.axisSpecificElasticity().z
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -506,13 +638,13 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
double pullStrength = 1.0 + excessRatio * 2.0;
|
||||
|
||||
Vec3 pullForce = pullDirection.scale(
|
||||
(distance - info.elasticDistance()) * pullStrength * SPRING_DAMPENING
|
||||
(distance - info.elasticDistance()) * pullStrength * Config.springDampening()
|
||||
);
|
||||
|
||||
return new Vec3(
|
||||
pullForce.x * AXIS_SPECIFIC_ELASTICITY.x,
|
||||
pullForce.y * AXIS_SPECIFIC_ELASTICITY.y,
|
||||
pullForce.z * AXIS_SPECIFIC_ELASTICITY.z
|
||||
pullForce.x * Config.axisSpecificElasticity().x,
|
||||
pullForce.y * Config.axisSpecificElasticity().y,
|
||||
pullForce.z * Config.axisSpecificElasticity().z
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -566,10 +698,10 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean transferLeash(Entity holder, Entity newHolder, ItemStack stack) {
|
||||
public boolean transferLeash(Entity holder, Entity newHolder, String reserved) {
|
||||
return holder instanceof SuperLeashKnotEntity superLeashKnotEntity ?
|
||||
transferLeash(superLeashKnotEntity.getPos(), newHolder, stack) :
|
||||
transferLeash(holder.getUUID(), newHolder, stack);
|
||||
transferLeash(superLeashKnotEntity.getPos(), newHolder, reserved) :
|
||||
transferLeash(holder.getUUID(), newHolder, reserved);
|
||||
}
|
||||
|
||||
// 将拴绳持有者转移到新实体(非拴绳结 -> 任意)
|
||||
|
|
@ -588,14 +720,14 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean transferLeash(UUID oldHolderUUID, Entity newHolder, ItemStack stack) {
|
||||
public boolean transferLeash(UUID oldHolderUUID, Entity newHolder, String reserved) {
|
||||
LeashInfo info = leashHolders.remove(oldHolderUUID);
|
||||
if (info == null || newHolder == null) return false;
|
||||
if(newHolder instanceof SuperLeashKnotEntity superLeashKnotEntity) {
|
||||
LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity, stack.getDescriptionId());
|
||||
LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity, reserved);
|
||||
leashKnots.put(superLeashKnotEntity.getPos(), leashInfo);
|
||||
} else {
|
||||
LeashInfo leashInfo = info.transferHolder(newHolder, stack.getDescriptionId());
|
||||
LeashInfo leashInfo = info.transferHolder(newHolder, reserved);
|
||||
leashHolders.put(newHolder.getUUID(), leashInfo);
|
||||
}
|
||||
markForSync();
|
||||
|
|
@ -618,14 +750,14 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean transferLeash(BlockPos knotPos, Entity newHolder, ItemStack stack) {
|
||||
public boolean transferLeash(BlockPos knotPos, Entity newHolder, String reserved) {
|
||||
LeashInfo info = leashKnots.remove(knotPos);
|
||||
if (info == null || newHolder == null) return false;
|
||||
if(newHolder instanceof SuperLeashKnotEntity superLeashKnotEntity) {
|
||||
LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity, stack.getDescriptionId());
|
||||
LeashInfo leashInfo = info.transferHolder(superLeashKnotEntity, reserved);
|
||||
leashKnots.put(superLeashKnotEntity.getPos(), leashInfo);
|
||||
} else {
|
||||
LeashInfo leashInfo = info.transferHolder(newHolder, stack.getDescriptionId());
|
||||
LeashInfo leashInfo = info.transferHolder(newHolder, reserved);
|
||||
leashHolders.put(newHolder.getUUID(), leashInfo);
|
||||
}
|
||||
markForSync();
|
||||
|
|
@ -743,9 +875,7 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
throw new IllegalArgumentException("LeashInfo.blockPos is empty");
|
||||
}
|
||||
BlockPos blockPos = info.blockPosOpt().get();
|
||||
infoTag.putInt("HolderX", blockPos.getX());
|
||||
infoTag.putInt("HolderY", blockPos.getY());
|
||||
infoTag.putInt("HolderZ", blockPos.getZ());
|
||||
infoTag.put("KnotBlockPos", NbtUtils.writeBlockPos(blockPos));
|
||||
return getCommonCompoundTag(info, infoTag);
|
||||
}
|
||||
|
||||
|
|
@ -755,9 +885,7 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
infoTag.putInt("HolderID", info.holderIdOpt().get());
|
||||
infoTag.putString("LeashItem", info.reserved());
|
||||
infoTag.putDouble("OffsetX", info.attachOffset().x);
|
||||
infoTag.putDouble("OffsetY", info.attachOffset().y);
|
||||
infoTag.putDouble("OffsetZ", info.attachOffset().z);
|
||||
infoTag.put("Offset", NBTWriter.writeVec3(info.attachOffset()));
|
||||
infoTag.putDouble("MaxDistance", info.maxDistance());
|
||||
infoTag.putDouble("ElasticDistance", info.elasticDistance());
|
||||
infoTag.putInt("KeepLeashTicks", info.keepLeashTicks());
|
||||
|
|
@ -793,10 +921,47 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
}
|
||||
}
|
||||
}
|
||||
private static @NotNull UUID getDelayedUUIDFormListTag(@NotNull CompoundTag infoTag) {
|
||||
if (infoTag.contains("DelayHolderUUID"))
|
||||
return infoTag.getUUID("DelayHolderUUID");
|
||||
throw new IllegalArgumentException("LeashInfo.intId is empty");
|
||||
}
|
||||
@Contract("_ -> new")
|
||||
private static @NotNull LeashInfo getUUIDLeashDataFormListTag(@NotNull CompoundTag infoTag) {
|
||||
if (infoTag.contains("HolderUUID")){
|
||||
return new LeashInfo(
|
||||
infoTag.getUUID("HolderUUID"),
|
||||
infoTag.getInt("HolderID"),
|
||||
infoTag.getString("LeashItem"),
|
||||
NBTReader.readVec3(infoTag.getCompound("Offset")),
|
||||
infoTag.getDouble("MaxDistance"),
|
||||
infoTag.contains("ElasticDistance") ? infoTag.getDouble("ElasticDistance") : 6.0,
|
||||
infoTag.getInt("KeepLeashTicks"),
|
||||
infoTag.contains("MaxKeepLeashTicks") ? infoTag.getInt("MaxKeepLeashTicks") : 20
|
||||
);
|
||||
} else
|
||||
throw new IllegalArgumentException("Unknown LeashInfo");
|
||||
}
|
||||
@Contract("_ -> new")
|
||||
private static @NotNull LeashInfo getBlockPosLeashDataFormListTag(@NotNull CompoundTag infoTag) {
|
||||
if (infoTag.contains("KnotBlockPos")) {
|
||||
return new LeashInfo(
|
||||
NbtUtils.readBlockPos(infoTag.getCompound("KnotBlockPos")),
|
||||
infoTag.getInt("HolderID"),
|
||||
infoTag.getString("LeashItem"),
|
||||
NBTReader.readVec3(infoTag.getCompound("Offset")),
|
||||
infoTag.getDouble("MaxDistance"),
|
||||
infoTag.contains("ElasticDistance") ? infoTag.getDouble("ElasticDistance") : 6.0,
|
||||
infoTag.getInt("KeepLeashTicks"),
|
||||
infoTag.contains("MaxKeepLeashTicks") ? infoTag.getInt("MaxKeepLeashTicks") : 20
|
||||
);
|
||||
} else
|
||||
throw new IllegalArgumentException("Unknown LeashInfo");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeLeashed() {
|
||||
return (leashHolders.size() + leashKnots.size()) <= MAX_LEASHES_PER_ENTITY;
|
||||
return (leashHolders.size() + leashKnots.size()) <= Config.maxLeashesPerEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -823,43 +988,7 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
return Optional.empty(); // 理论上不会到这里
|
||||
}
|
||||
|
||||
private static @NotNull UUID getDelayedUUIDFormListTag(@NotNull CompoundTag infoTag) {
|
||||
if (infoTag.contains("DelayHolderUUID"))
|
||||
return infoTag.getUUID("DelayHolderUUID");
|
||||
throw new IllegalArgumentException("LeashInfo.intId is empty");
|
||||
}
|
||||
@Contract("_ -> new")
|
||||
private static @NotNull LeashInfo getUUIDLeashDataFormListTag(@NotNull CompoundTag infoTag) {
|
||||
if (infoTag.contains("HolderUUID")){
|
||||
return new LeashInfo(
|
||||
infoTag.getUUID("HolderUUID"),
|
||||
infoTag.getInt("HolderID"),
|
||||
infoTag.getString("LeashItem"),
|
||||
new Vec3(infoTag.getDouble("OffsetX"), infoTag.getDouble("OffsetY"), infoTag.getDouble("OffsetZ")),
|
||||
infoTag.getDouble("MaxDistance"),
|
||||
infoTag.contains("ElasticDistance") ? infoTag.getDouble("ElasticDistance") : 6.0,
|
||||
infoTag.getInt("KeepLeashTicks"),
|
||||
infoTag.contains("MaxKeepLeashTicks") ? infoTag.getInt("MaxKeepLeashTicks") : 20
|
||||
);
|
||||
} else
|
||||
throw new IllegalArgumentException("Unknown LeashInfo");
|
||||
}
|
||||
@Contract("_ -> new")
|
||||
private static @NotNull LeashInfo getBlockPosLeashDataFormListTag(@NotNull CompoundTag infoTag) {
|
||||
if (infoTag.contains("HolderX")) {
|
||||
return new LeashInfo(
|
||||
new BlockPos(infoTag.getInt("HolderX"), infoTag.getInt("HolderY"), infoTag.getInt("HolderZ")),
|
||||
infoTag.getInt("HolderID"),
|
||||
infoTag.getString("LeashItem"),
|
||||
new Vec3(infoTag.getDouble("OffsetX"), infoTag.getDouble("OffsetY"), infoTag.getDouble("OffsetZ")),
|
||||
infoTag.getDouble("MaxDistance"),
|
||||
infoTag.contains("ElasticDistance") ? infoTag.getDouble("ElasticDistance") : 6.0,
|
||||
infoTag.getInt("KeepLeashTicks"),
|
||||
infoTag.contains("MaxKeepLeashTicks") ? infoTag.getInt("MaxKeepLeashTicks") : 20
|
||||
);
|
||||
} else
|
||||
throw new IllegalArgumentException("Unknown LeashInfo");
|
||||
}
|
||||
|
||||
|
||||
public static @NotNull List<Entity> leashableInArea(Level pLevel, Vec3 pPos, Predicate<Entity> filter) {
|
||||
return leashableInArea(pLevel, pPos, filter, 1024D);
|
||||
|
|
@ -882,17 +1011,23 @@ public class LeashDataImpl implements ILeashDataCapability {
|
|||
return false;
|
||||
} else {
|
||||
Optional<LeashInfo> leashInfo = getLeashInfo(pEntity);
|
||||
return leashInfo.isEmpty() && (entity.distanceTo(pEntity) <= LEASH_ELASTIC_DIST * LEASH_EXTREME_SNAP_DIST_FACTOR) && canBeLeashed();//距离最大,则不可以被固定或转移
|
||||
return leashInfo.isEmpty() && (entity.distanceTo(pEntity) <= Config.leashElasticDist() * Config.leashExtremeSnapDistFactor()) && canBeLeashed();//距离最大,则不可以被固定或转移
|
||||
}
|
||||
}
|
||||
public static boolean isLeashHolder(@NotNull Entity pEntity, UUID pHolderUUID) {
|
||||
AtomicBoolean isTarget = new AtomicBoolean(false);
|
||||
pEntity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> isTarget.set(i.isLeashedBy(pHolderUUID)));
|
||||
LeashUtil.getLeashData(pEntity)
|
||||
.ifPresent(i ->
|
||||
isTarget.set(i.isLeashedBy(pHolderUUID))
|
||||
);
|
||||
return isTarget.get();
|
||||
}
|
||||
public static boolean isLeashHolder(@NotNull Entity pEntity, BlockPos pKnotPos) {
|
||||
AtomicBoolean isTarget = new AtomicBoolean(false);
|
||||
pEntity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> isTarget.set(i.isLeashedBy(pKnotPos)));
|
||||
LeashUtil.getLeashData(pEntity)
|
||||
.ifPresent(i ->
|
||||
isTarget.set(i.isLeashedBy(pKnotPos))
|
||||
);
|
||||
return isTarget.get();
|
||||
}
|
||||
public static boolean isLeashHolder(@NotNull Entity pEntity, Entity pTestHolder) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* 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.capability.impi;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
import top.r3944realms.superleadrope.network.NetworkHandler;
|
||||
import top.r3944realms.superleadrope.network.toClient.LeashStateSyncPacket;
|
||||
import top.r3944realms.superleadrope.util.nbt.NBTReader;
|
||||
import top.r3944realms.superleadrope.util.nbt.NBTWriter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
//TODO: 将拴绳状态与数据联系在一起
|
||||
public class LeashStateImpl implements ILeashState {
|
||||
private Entity entity;
|
||||
private boolean needsSync = false;
|
||||
private long lastSyncTime;
|
||||
private final Map<UUID, ILeashState.LeashState> leashHolders = new ConcurrentHashMap<>();
|
||||
private final Map<BlockPos, ILeashState.LeashState> leashKnots = new ConcurrentHashMap<>();
|
||||
private volatile Vec3 staticApplyEntityLocationOffset;
|
||||
private volatile Vec3 defaultApplyEntityLocationOffset = new Vec3(0 , 0.45, 0);
|
||||
public LeashStateImpl(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markForSync() {
|
||||
if (!entity.level().isClientSide) {
|
||||
needsSync = true;
|
||||
immediateSync(); // 立即同步一次
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void immediateSync() {
|
||||
syncNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSync() {
|
||||
if (!needsSync || entity.level().isClientSide) return;
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
// 每隔 2 秒同步一次
|
||||
if (now - lastSyncTime > 2000) {
|
||||
syncNow();
|
||||
}
|
||||
}
|
||||
|
||||
private void syncNow() {
|
||||
CompoundTag currentData = serializeNBT();
|
||||
|
||||
NetworkHandler.sendToPlayer(
|
||||
new LeashStateSyncPacket(entity.getId(), currentData),
|
||||
entity,
|
||||
PacketDistributor.TRACKING_ENTITY_AND_SELF
|
||||
);
|
||||
lastSyncTime = System.currentTimeMillis();
|
||||
needsSync = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, LeashState> getHolderLeashStates() {
|
||||
ConcurrentMap<UUID, LeashState> retMap = Maps.newConcurrentMap();
|
||||
retMap.putAll(leashHolders);
|
||||
return retMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockPos, LeashState> getKnotLeashStates() {
|
||||
ConcurrentMap<BlockPos, LeashState> retMap = Maps.newConcurrentMap();
|
||||
retMap.putAll(leashKnots);
|
||||
return retMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LeashState> getLeashState(Entity holder) {
|
||||
return holder instanceof SuperLeashKnotEntity leashKnot ? getLeashState(leashKnot.getPos())
|
||||
: getLeashState(holder.getUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LeashState> getLeashState(UUID uuid) {
|
||||
return leashHolders.containsKey(uuid) ? Optional.of(leashHolders.get(uuid)) : Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LeashState> getLeashState(BlockPos pos) {
|
||||
return leashKnots.containsKey(pos) ? Optional.of(leashKnots.get(pos)) : Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 getDefaultLeashApplyEntityLocationOffset() {
|
||||
return defaultApplyEntityLocationOffset;
|
||||
}
|
||||
@Override
|
||||
public Optional<Vec3> getLeashApplyEntityLocationOffset() {
|
||||
return Optional.ofNullable(staticApplyEntityLocationOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLeashHolderLocationOffset(Entity holder) {
|
||||
if (entity instanceof SuperLeashKnotEntity leashKnot) {
|
||||
resetLeashHolderLocationOffset(leashKnot.getPos());
|
||||
} else resetLeashHolderLocationOffset(holder.getUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLeashHolderLocationOffset(UUID holderUUID) {
|
||||
leashHolders.computeIfPresent(holderUUID, (uuid, state) -> state.resetHolderLocationOffset());
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLeashHolderLocationOffset(BlockPos knotPos) {
|
||||
leashKnots.computeIfPresent(knotPos, (blockPos, state) -> state.resetHolderLocationOffset());
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeashHolderLocationOffset(Entity holder, Vec3 offset) {
|
||||
if (entity instanceof SuperLeashKnotEntity leashKnot) {
|
||||
setLeashHolderLocationOffset(leashKnot.getPos(), offset);
|
||||
} else setLeashHolderLocationOffset(holder.getUUID(), offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeashHolderLocationOffset(UUID holderUUID, Vec3 offset) {
|
||||
leashHolders.computeIfPresent(holderUUID, (uuid, state) -> state.setHolderLocationOffset(offset));
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeashHolderLocationOffset(BlockPos knotPos, Vec3 leashHolderLocationOffset) {
|
||||
leashKnots.computeIfPresent(knotPos, (blockPos, state) -> state.setHolderLocationOffset(leashHolderLocationOffset));
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLeashHolderLocationOffset(Entity holder, Vec3 offset) {
|
||||
if (entity instanceof SuperLeashKnotEntity leashKnot) {
|
||||
addLeashHolderLocationOffset(leashKnot.getPos(), offset);
|
||||
} else addLeashHolderLocationOffset(holder.getUUID(), offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLeashHolderLocationOffset(UUID holderUUID, Vec3 offset) {
|
||||
leashHolders.computeIfPresent(holderUUID, (uuid, state) -> state.setHolderLocationOffset(state.holderLocationOffset().add(offset)));
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLeashHolderLocationOffset(BlockPos knotPos, Vec3 offset) {
|
||||
leashKnots.computeIfPresent(knotPos, (blockPos, state) -> state.setHolderLocationOffset(state.holderLocationOffset().add(offset)));
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLeashHolderLocationOffset(Entity holder) {
|
||||
if (entity instanceof SuperLeashKnotEntity leashKnot) {
|
||||
removeLeashHolderLocationOffset(leashKnot.getPos());
|
||||
} else removeLeashHolderLocationOffset(holder.getUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLeashHolderLocationOffset(UUID holderUUID) {
|
||||
leashHolders.remove(holderUUID);
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLeashHolderLocationOffset(BlockPos knotPos) {
|
||||
leashKnots.remove(knotPos);
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetAllLeashHolderLocationsOffset() {
|
||||
leashKnots.replaceAll((pos, leashState) -> leashState.resetHolderLocationOffset());
|
||||
leashHolders.replaceAll((uuid, leashState) -> leashState.resetHolderLocationOffset());
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetAllLeashApplyEntityLocationsOffset() {
|
||||
leashKnots.replaceAll((pos, leashState) -> leashState.setApplyEntityLocationOffset(defaultApplyEntityLocationOffset));
|
||||
leashHolders.replaceAll((uuid, leashState) -> leashState.setApplyEntityLocationOffset(defaultApplyEntityLocationOffset));
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLeashApplyEntityLocationOffset() {
|
||||
staticApplyEntityLocationOffset = null;
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLeashApplyEntityLocationOffset(Vec3 leashHolderLocationOffset) {
|
||||
staticApplyEntityLocationOffset = leashHolderLocationOffset;
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLeashApplyEntityLocationOffset(Vec3 offset) {
|
||||
Optional.ofNullable(this.staticApplyEntityLocationOffset)
|
||||
.ifPresentOrElse(vec3 -> vec3.add(offset), () -> this.staticApplyEntityLocationOffset = offset);
|
||||
markForSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(ILeashState other, Entity newEntity) {
|
||||
this.entity = newEntity;
|
||||
this.defaultApplyEntityLocationOffset = other.getDefaultLeashApplyEntityLocationOffset();
|
||||
this.staticApplyEntityLocationOffset = other.getLeashApplyEntityLocationOffset().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag serializeNBT() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
ListTag holdersList = new ListTag();
|
||||
leashHolders.forEach((uuid, state ) -> {
|
||||
CompoundTag infoTag = generateCompoundTagFromUUIDLeashInfo(uuid, state);
|
||||
holdersList.add(infoTag);
|
||||
});
|
||||
leashKnots.forEach((blockPos, state ) -> {
|
||||
CompoundTag infoTag = generateCompoundTagFromBlockPosLeashState(blockPos, state);
|
||||
holdersList.add(infoTag);
|
||||
});
|
||||
tag.put("LeashHolders", holdersList);
|
||||
if (staticApplyEntityLocationOffset != null) {
|
||||
tag.put("StaticApplyEntityLocationOffset", NBTWriter.writeVec3(staticApplyEntityLocationOffset));
|
||||
}
|
||||
tag.put("DefaultApplyEntityLocationOffset", NBTWriter.writeVec3(defaultApplyEntityLocationOffset));
|
||||
return tag;
|
||||
}
|
||||
private static @NotNull CompoundTag generateCompoundTagFromUUIDLeashInfo(@NotNull UUID uuid, @NotNull ILeashState.LeashState info) {
|
||||
CompoundTag infoTag = new CompoundTag();
|
||||
infoTag.putUUID("HolderUUID", uuid);
|
||||
return getCommonCompoundTag(info ,infoTag);
|
||||
}
|
||||
private static @NotNull CompoundTag generateCompoundTagFromBlockPosLeashState(@NotNull BlockPos blockpos, @NotNull ILeashState.LeashState info) {
|
||||
CompoundTag infoTag = new CompoundTag();
|
||||
infoTag.put("KnotBlockPos", NbtUtils.writeBlockPos(blockpos));
|
||||
return getCommonCompoundTag(info, infoTag);
|
||||
}
|
||||
|
||||
private static @NotNull CompoundTag getCommonCompoundTag(@NotNull ILeashState.LeashState info, CompoundTag infoTag) {
|
||||
infoTag.put("ApplyEntityLocationOffset", NBTWriter.writeVec3(info.applyEntityLocationOffset()));
|
||||
infoTag.put("HolderEntityLocationOffset", NBTWriter.writeVec3(info.holderLocationOffset()));
|
||||
infoTag.put("DefaultHolderLocationOffset", NBTWriter.writeVec3(info.defaultHolderLocationOffset()));
|
||||
return infoTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeNBT(@NotNull CompoundTag nbt) {
|
||||
leashHolders.clear();
|
||||
leashKnots.clear();
|
||||
if (nbt.contains("LeashHolders", ListTag.TAG_LIST)) {
|
||||
ListTag holdersList = nbt.getList("LeashHolders", ListTag.TAG_COMPOUND);
|
||||
if(nbt.contains("StaticApplyEntityLocationOffset")) {
|
||||
staticApplyEntityLocationOffset = NBTReader.readVec3(nbt.getCompound("StaticApplyEntityLocationOffset"));
|
||||
}
|
||||
if (nbt.contains("DefaultApplyEntityLocationOffset")) {
|
||||
defaultApplyEntityLocationOffset = NBTReader.readVec3(nbt.getCompound("DefaultApplyEntityLocationOffset"));
|
||||
} else throw new IllegalArgumentException("Nbt Lost DefaultApplyEntityLocationOffset Value");
|
||||
for (int i = 0; i < holdersList.size(); i++) {
|
||||
CompoundTag infoTag = holdersList.getCompound(i);
|
||||
if (infoTag.contains("HolderUUID")) {
|
||||
ILeashState.LeashState uuidLeashDataFormListTag = getUUIDLeashStateForm(infoTag);
|
||||
leashHolders.put(infoTag.getUUID("HolderUUID"), uuidLeashDataFormListTag);
|
||||
} else {
|
||||
ILeashState.LeashState blockPosLeashDataFormListTag = getUUIDLeashStateForm(infoTag);
|
||||
leashKnots.put(NbtUtils.readBlockPos(infoTag.getCompound("KnotBlockPos")), blockPosLeashDataFormListTag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@Contract("_ -> new")
|
||||
private static @NotNull ILeashState.LeashState getUUIDLeashStateForm(@NotNull CompoundTag infoTag) {
|
||||
return new ILeashState.LeashState(
|
||||
NBTReader.readVec3(infoTag.getCompound("HolderEntityLocationOffset")),
|
||||
NBTReader.readVec3(infoTag.getCompound("ApplyEntityLocationOffset")),
|
||||
NBTReader.readVec3(infoTag.getCompound("DefaultHolderLocationOffset"))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* 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.capability.inter;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Capability interface for managing leash data of entities and knots.
|
||||
*/
|
||||
public interface ILeashData extends INBTSerializable<CompoundTag> {
|
||||
|
||||
/* ----------------------
|
||||
* Add / remove leashes
|
||||
* ---------------------- */
|
||||
boolean addLeash(Entity holder);
|
||||
boolean addLeash(Entity holder, String reserved);
|
||||
boolean addLeash(Entity holder, double maxDistance);
|
||||
boolean addLeash(Entity holder, double maxDistance, double elasticDistance, int maxKeepTicks);
|
||||
boolean addLeash(Entity holder, double maxDistance, String reserved);
|
||||
boolean addLeash(Entity holder, double maxDistance, double elasticDistance, int maxKeepTicks, String reserved);
|
||||
|
||||
void addLeash(Entity holder, LeashInfo info);
|
||||
|
||||
void addDelayedLeash(Player holderPlayer);
|
||||
void removeDelayedLeash(UUID onceHolderPlayerUUID);
|
||||
|
||||
boolean removeLeash(Entity holder);
|
||||
boolean removeLeash(UUID holderUUID);
|
||||
boolean removeLeash(BlockPos knotPos);
|
||||
|
||||
void removeAllLeashes();
|
||||
void removeAllHolderLeashes();
|
||||
void removeAllKnotLeashes();
|
||||
|
||||
/* ----------------------
|
||||
* Modify leash properties
|
||||
* ---------------------- */
|
||||
boolean setMaxDistance(Entity holder, double distance);
|
||||
boolean setMaxDistance(Entity holder, double distance, int maxKeepTicks);
|
||||
boolean setMaxDistance(Entity holder, double distance, int maxKeepTicks, String reserved);
|
||||
|
||||
boolean setMaxDistance(UUID holderUUID, double distance);
|
||||
boolean setMaxDistance(UUID holderUUID, double distance, int maxKeepTicks);
|
||||
boolean setMaxDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved);
|
||||
|
||||
boolean setMaxDistance(BlockPos knotPos, double distance);
|
||||
boolean setMaxDistance(BlockPos knotPos, double distance, int maxKeepTicks);
|
||||
boolean setMaxDistance(BlockPos knotPos, double distance, int maxKeepTicks, String reserved);
|
||||
|
||||
boolean setElasticDistance(Entity holder, double distance);
|
||||
boolean setElasticDistance(Entity holder, double distance, int maxKeepTicks);
|
||||
boolean setElasticDistance(Entity holder, double distance, int maxKeepTicks, String reserved);
|
||||
|
||||
boolean setElasticDistance(UUID holderUUID, double distance);
|
||||
boolean setElasticDistance(UUID holderUUID, double distance, int maxKeepTicks);
|
||||
boolean setElasticDistance(UUID holderUUID, double distance, int maxKeepTicks, String reserved);
|
||||
|
||||
boolean setElasticDistance(BlockPos knotPos, double distance);
|
||||
boolean setElasticDistance(BlockPos knotPos, double distance, int maxKeepTicks);
|
||||
boolean setElasticDistance(BlockPos knotPos, double distance, int maxKeepTicks, String reserved);
|
||||
|
||||
/* ----------------------
|
||||
* Apply physics
|
||||
* ---------------------- */
|
||||
void applyLeashForces();
|
||||
|
||||
/* ----------------------
|
||||
* Transfer leash holders
|
||||
* ---------------------- */
|
||||
boolean transferLeash(Entity holder, Entity newHolder);
|
||||
boolean transferLeash(Entity holder, Entity newHolder, String reserved);
|
||||
|
||||
boolean transferLeash(UUID holderUUID, Entity newHolder);
|
||||
boolean transferLeash(UUID holderUUID, Entity newHolder, String reserved);
|
||||
|
||||
boolean transferLeash(BlockPos knotPos, Entity newHolder);
|
||||
boolean transferLeash(BlockPos knotPos, Entity newHolder, String reserved);
|
||||
|
||||
/* ----------------------
|
||||
* Query state
|
||||
* ---------------------- */
|
||||
boolean hasLeash();
|
||||
boolean hasKnotLeash();
|
||||
boolean hasHolderLeash();
|
||||
|
||||
Collection<LeashInfo> getAllLeashes();
|
||||
|
||||
boolean isLeashedBy(Entity holder);
|
||||
boolean isLeashedBy(UUID holderUUID);
|
||||
boolean isLeashedBy(BlockPos knotPos);
|
||||
|
||||
boolean isInDelayedLeash(UUID holderUUID);
|
||||
|
||||
Optional<LeashInfo> getLeashInfo(Entity holder);
|
||||
Optional<LeashInfo> getLeashInfo(UUID holderUUID);
|
||||
Optional<LeashInfo> getLeashInfo(BlockPos knotPos);
|
||||
|
||||
boolean canBeLeashed();
|
||||
boolean canBeAttachedTo(Entity entity);
|
||||
|
||||
/* ----------------------
|
||||
* Occupy / sync
|
||||
* ---------------------- */
|
||||
/**
|
||||
* 抢占位(已离线玩家)。
|
||||
* 用于解决玩家下线后所持有对象会移除持有者的问题(实际上是占用个弱集合)
|
||||
*/
|
||||
Optional<UUID> occupyLeash();
|
||||
|
||||
void markForSync();
|
||||
void immediateSync();
|
||||
void checkSync();
|
||||
|
||||
/* ----------------------
|
||||
* Data record
|
||||
* ---------------------- */
|
||||
record LeashInfo(
|
||||
Optional<BlockPos> blockPosOpt,
|
||||
Optional<UUID> holderUUIDOpt,
|
||||
Optional<Integer> holderIdOpt, // Only for client side use
|
||||
String reserved, // 保留字段
|
||||
Vec3 attachOffset,
|
||||
double maxDistance,
|
||||
double elasticDistance,
|
||||
int keepLeashTicks, // 剩余 Tick 数
|
||||
int maxKeepLeashTicks // 最大保持 Tick 数
|
||||
) {
|
||||
public static final LeashInfo EMPTY = new LeashInfo(
|
||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||
"", Vec3.ZERO, 12.0D, 6.0D, 0, 0
|
||||
);
|
||||
|
||||
/* ---------- Factory ---------- */
|
||||
public static LeashInfo create(
|
||||
Entity entity,
|
||||
String reserved,
|
||||
Vec3 offset,
|
||||
double maxDistance,
|
||||
double elasticDistance,
|
||||
int keepTicks,
|
||||
int maxKeepTicks
|
||||
) {
|
||||
return entity instanceof SuperLeashKnotEntity knot
|
||||
? new LeashInfo(knot.getPos(), entity.getId(), reserved,
|
||||
offset, maxDistance, elasticDistance, keepTicks, maxKeepTicks)
|
||||
: new LeashInfo(entity.getUUID(), entity.getId(), reserved,
|
||||
offset, maxDistance, elasticDistance, keepTicks, maxKeepTicks);
|
||||
}
|
||||
|
||||
public LeashInfo(UUID holderUUID, int holderId, String reserved, Vec3 offset,
|
||||
double maxDistance, double elasticDistance, int keepTicks, int maxKeepTicks) {
|
||||
this(Optional.empty(), Optional.of(holderUUID), Optional.of(holderId),
|
||||
reserved, offset, maxDistance, elasticDistance, keepTicks, maxKeepTicks);
|
||||
}
|
||||
|
||||
public LeashInfo(BlockPos knotPos, int holderId, String reserved, Vec3 offset,
|
||||
double maxDistance, double elasticDistance, int keepTicks, int maxKeepTicks) {
|
||||
this(Optional.of(knotPos), Optional.empty(), Optional.of(holderId),
|
||||
reserved, offset, maxDistance, elasticDistance, keepTicks, maxKeepTicks);
|
||||
}
|
||||
|
||||
/* ---------- State updates ---------- */
|
||||
public LeashInfo decrementKeepTicks() {
|
||||
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, reserved, attachOffset,
|
||||
maxDistance, elasticDistance,
|
||||
Math.max(0, keepLeashTicks - 1), maxKeepLeashTicks);
|
||||
}
|
||||
|
||||
public LeashInfo resetKeepTicks() {
|
||||
return new LeashInfo(blockPosOpt, holderUUIDOpt, holderIdOpt, reserved, attachOffset,
|
||||
maxDistance, elasticDistance,
|
||||
maxKeepLeashTicks, maxKeepLeashTicks);
|
||||
}
|
||||
|
||||
public LeashInfo transferHolder(Entity entity) {
|
||||
return transferHolder(entity, reserved);
|
||||
}
|
||||
|
||||
public LeashInfo transferHolder(Entity entity, String newReserved) {
|
||||
boolean isKnot = entity instanceof SuperLeashKnotEntity;
|
||||
return new LeashInfo(
|
||||
isKnot ? Optional.of(((SuperLeashKnotEntity) entity).getPos()) : Optional.empty(),
|
||||
!isKnot ? Optional.of(entity.getUUID()) : Optional.empty(),
|
||||
Optional.of(entity.getId()),
|
||||
newReserved, attachOffset, maxDistance, elasticDistance,
|
||||
keepLeashTicks, maxKeepLeashTicks
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
/*
|
||||
* 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.capability.inter;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ILeashDataCapability extends INBTSerializable<CompoundTag> {
|
||||
// 原LeashData的方法接口
|
||||
boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance);
|
||||
boolean addLeash(Entity holder, ItemStack leashStack, double maxDistance, double elasticDistance, int maxKeepLeashTicks);
|
||||
boolean addLeash(Entity holder, LeashInfo leashInfo);
|
||||
boolean addDelayedLeash(Player holderPlayer);
|
||||
boolean removeDelayedLeash(UUID onceHolderPlayerUUID);
|
||||
boolean setMaxDistance(Entity holder, double newMaxDistance);
|
||||
boolean setMaxDistance(Entity holder,double newMaxDistance, int newMaxKeepLeashTicks);
|
||||
boolean setMaxDistance(UUID holderUUID, double newMaxDistance);
|
||||
boolean setMaxDistance(UUID holderUUID, double newMaxDistance, int newMaxKeepLeashTicks);
|
||||
boolean setMaxDistance(BlockPos knotPos, double newMaxDistance);
|
||||
boolean setMaxDistance(BlockPos knotPos, double newMaxDistance, int newMaxKeepLeashTicks);
|
||||
boolean setElasticDistance(Entity holder, double newElasticDistance);
|
||||
boolean setElasticDistance(UUID holderUUID, double newElasticDistance);
|
||||
boolean setElasticDistance(BlockPos knotPos, double newElasticDistance);
|
||||
// 动态修改弹性距离
|
||||
boolean setElasticDistance(Entity holder, double newElasticDistance, int newMaxKeepLeashTicks);
|
||||
boolean setElasticDistance(UUID holderUUID, double newElasticDistance, int newMaxKeepLeashTicks);
|
||||
boolean setElasticDistance(BlockPos knotPos, double newElasticDistance, int newMaxKeepLeashTicks);
|
||||
|
||||
void applyLeashForces();
|
||||
boolean removeLeash(Entity holder);
|
||||
boolean removeLeash(UUID holderUUID);
|
||||
boolean removeLeash(BlockPos knotPos);
|
||||
void removeAllLeashes();
|
||||
void removeAllHolderLeashes();
|
||||
void removeAllKnotLeashes();
|
||||
|
||||
boolean transferLeash(Entity holder, Entity newHolder);
|
||||
boolean transferLeash(Entity holder, Entity newHolder, ItemStack stack);
|
||||
boolean transferLeash(UUID holderUUID, Entity newHolder);
|
||||
boolean transferLeash(UUID holderUUID, Entity newHolder, ItemStack stack);
|
||||
boolean transferLeash(BlockPos knotPos, Entity newHolder);
|
||||
boolean transferLeash(BlockPos knotPos, Entity newHolder, ItemStack stack);
|
||||
|
||||
// 查询方法
|
||||
boolean hasLeash();
|
||||
boolean hasKnotLeash();
|
||||
boolean hasHolderLeash();
|
||||
Collection<LeashInfo> getAllLeashes();
|
||||
boolean isLeashedBy(Entity holder);
|
||||
boolean isLeashedBy(UUID holderUUID);
|
||||
boolean isLeashedBy(BlockPos knotPos);
|
||||
boolean isInDelayedLeash(UUID holderUUID);
|
||||
Optional<LeashInfo> getLeashInfo(Entity holder);
|
||||
Optional<LeashInfo> getLeashInfo(UUID holderUUID);
|
||||
Optional<LeashInfo> getLeashInfo(BlockPos knotPos);
|
||||
|
||||
boolean canBeLeashed();
|
||||
|
||||
/**
|
||||
* 抢占位(已离线玩家)
|
||||
* 用于解决玩家下线后所持有我对象,会移除持有者的问题(实际上是占用个弱集合)
|
||||
*/
|
||||
Optional<UUID> occupyLeash();
|
||||
boolean canBeAttachedTo(Entity pEntity);
|
||||
void markForSync();
|
||||
void immediateSync();
|
||||
void checkSync();
|
||||
|
||||
record LeashInfo(
|
||||
Optional<BlockPos> blockPosOpt,
|
||||
Optional<UUID> holderUUIDOpt,
|
||||
Optional<Integer> holderIdOpt,//Only for client side use
|
||||
String reserved, //保留字段
|
||||
Vec3 attachOffset,
|
||||
double maxDistance,
|
||||
double elasticDistance,
|
||||
int keepLeashTicks, // 新增:保持拴绳的剩余Tick数
|
||||
int maxKeepLeashTicks // 新增:最大保持Tick数(可配置)
|
||||
) {
|
||||
public static final LeashInfo EMPTY = new LeashInfo(
|
||||
Optional.empty(), Optional.empty(), Optional.empty(),
|
||||
"", Vec3.ZERO, 12.0D, 6.0D, 0, 0
|
||||
);
|
||||
public static LeashInfo CreateLeashInfo(
|
||||
Entity entity,
|
||||
String reserved,
|
||||
Vec3 attachOffset,
|
||||
double maxDistance,
|
||||
double elasticDistance,
|
||||
int keepLeashTicks,
|
||||
int maxKeepLeashTicks
|
||||
) {
|
||||
return entity instanceof SuperLeashKnotEntity superLeashKnot ?
|
||||
new LeashInfo(superLeashKnot.getPos(), entity.getId(), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks) :
|
||||
new LeashInfo(entity.getUUID(), entity.getId(), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks);
|
||||
}
|
||||
public LeashInfo(
|
||||
UUID holderUUID,
|
||||
int holderId,
|
||||
String reserved,
|
||||
Vec3 attachOffset,
|
||||
double maxDistance,
|
||||
double elasticDistance,
|
||||
int keepLeashTicks,
|
||||
int maxKeepLeashTicks
|
||||
) {
|
||||
this(Optional.empty() ,Optional.of(holderUUID), Optional.of(holderId), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks);
|
||||
}
|
||||
public LeashInfo(
|
||||
BlockPos knotPos,
|
||||
int holderId,
|
||||
String reserved,
|
||||
Vec3 attachOffset,
|
||||
double maxDistance,
|
||||
double elasticDistance,
|
||||
int keepLeashTicks,
|
||||
int maxKeepLeashTicks
|
||||
) {
|
||||
this(Optional.of(knotPos), Optional.empty(), Optional.of(holderId), reserved, attachOffset, maxDistance, elasticDistance, keepLeashTicks, maxKeepLeashTicks);
|
||||
}
|
||||
|
||||
// 返回一个减少剩余Tick的新实例
|
||||
public LeashInfo decrementKeepLeashTicks() {
|
||||
return new LeashInfo(
|
||||
blockPosOpt, holderUUIDOpt, holderIdOpt, reserved, attachOffset,
|
||||
maxDistance, elasticDistance,
|
||||
Math.max(0, keepLeashTicks - 1),
|
||||
maxKeepLeashTicks
|
||||
);
|
||||
}
|
||||
|
||||
// 重置Tick为最大值
|
||||
public LeashInfo resetKeepLeashTicks() {
|
||||
return new LeashInfo(
|
||||
blockPosOpt, holderUUIDOpt, holderIdOpt, reserved, attachOffset,
|
||||
maxDistance, elasticDistance,
|
||||
maxKeepLeashTicks,
|
||||
maxKeepLeashTicks
|
||||
);
|
||||
}
|
||||
public LeashInfo transferHolder (Entity entity) {
|
||||
boolean isSuperKnot = entity instanceof SuperLeashKnotEntity;
|
||||
return new LeashInfo(
|
||||
isSuperKnot ? Optional.of(((SuperLeashKnotEntity) entity).getPos()) : Optional.empty(),
|
||||
!isSuperKnot ? Optional.of(entity.getUUID()) : Optional.empty(),
|
||||
Optional.of(entity.getId()),
|
||||
reserved, attachOffset, maxDistance,elasticDistance, keepLeashTicks, maxKeepLeashTicks
|
||||
);
|
||||
}
|
||||
public LeashInfo transferHolder (Entity entity, String reserved) {
|
||||
boolean isSuperKnot = entity instanceof SuperLeashKnotEntity;
|
||||
return new LeashInfo(
|
||||
isSuperKnot ? Optional.of(((SuperLeashKnotEntity) entity).getPos()) : Optional.empty(),
|
||||
!isSuperKnot ? Optional.of(entity.getUUID()) : Optional.empty(),
|
||||
Optional.of(entity.getId()),
|
||||
reserved, attachOffset, maxDistance,elasticDistance, keepLeashTicks, maxKeepLeashTicks
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* 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.capability.inter;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
/**
|
||||
* Capability interface for managing leash states of entities and knots.
|
||||
*/
|
||||
public interface ILeashState extends INBTSerializable<CompoundTag> {
|
||||
|
||||
/* ----------------------
|
||||
* Query leash states
|
||||
* ---------------------- */
|
||||
Map<UUID, LeashState> getHolderLeashStates();
|
||||
Map<BlockPos, LeashState> getKnotLeashStates();
|
||||
|
||||
Optional<LeashState> getLeashState(Entity entity);
|
||||
Optional<LeashState> getLeashState(UUID uuid);
|
||||
Optional<LeashState> getLeashState(BlockPos pos);
|
||||
|
||||
/* ----------------------
|
||||
* Reset holder offsets
|
||||
* ---------------------- */
|
||||
void resetAllLeashHolderLocationsOffset();
|
||||
void resetLeashHolderLocationOffset(Entity holder);
|
||||
void resetLeashHolderLocationOffset(UUID holderUUID);
|
||||
void resetLeashHolderLocationOffset(BlockPos knotPos);
|
||||
|
||||
/* ----------------------
|
||||
* Set holder offsets
|
||||
* ---------------------- */
|
||||
void setLeashHolderLocationOffset(Entity holder, Vec3 offset);
|
||||
void setLeashHolderLocationOffset(UUID holderUUID, Vec3 offset);
|
||||
void setLeashHolderLocationOffset(BlockPos knotPos, Vec3 offset);
|
||||
|
||||
/* ----------------------
|
||||
* Add holder offsets
|
||||
* ---------------------- */
|
||||
void addLeashHolderLocationOffset(Entity holder, Vec3 offset);
|
||||
void addLeashHolderLocationOffset(UUID holderUUID, Vec3 offset);
|
||||
void addLeashHolderLocationOffset(BlockPos knotPos, Vec3 offset);
|
||||
|
||||
/* ----------------------
|
||||
* Remove holder offsets
|
||||
* ---------------------- */
|
||||
void removeLeashHolderLocationOffset(Entity holder);
|
||||
void removeLeashHolderLocationOffset(UUID holderUUID);
|
||||
void removeLeashHolderLocationOffset(BlockPos knotPos);
|
||||
|
||||
/* ----------------------
|
||||
* Apply-entity offset
|
||||
* ---------------------- */
|
||||
Optional<Vec3> getLeashApplyEntityLocationOffset();
|
||||
Vec3 getDefaultLeashApplyEntityLocationOffset();
|
||||
|
||||
void resetAllLeashApplyEntityLocationsOffset();
|
||||
void removeLeashApplyEntityLocationOffset();
|
||||
void setLeashApplyEntityLocationOffset(Vec3 offset);
|
||||
void addLeashApplyEntityLocationOffset(Vec3 offset);
|
||||
|
||||
/* ----------------------
|
||||
* Utility & sync
|
||||
* ---------------------- */
|
||||
void copy(ILeashState other, Entity newEntity);
|
||||
|
||||
void markForSync();
|
||||
void immediateSync();
|
||||
void checkSync();
|
||||
|
||||
/* ----------------------
|
||||
* Data record
|
||||
* ---------------------- */
|
||||
record LeashState(
|
||||
Vec3 holderLocationOffset,
|
||||
Vec3 applyEntityLocationOffset,
|
||||
Vec3 defaultHolderLocationOffset
|
||||
) {
|
||||
public LeashState resetHolderLocationOffset() {
|
||||
return new LeashState(defaultHolderLocationOffset, applyEntityLocationOffset, defaultHolderLocationOffset);
|
||||
}
|
||||
|
||||
public LeashState setHolderLocationOffset(Vec3 holderLocationOffset) {
|
||||
return new LeashState(holderLocationOffset, applyEntityLocationOffset, defaultHolderLocationOffset);
|
||||
}
|
||||
|
||||
public LeashState setApplyEntityLocationOffset(Vec3 applyEntityLocationOffset) {
|
||||
return new LeashState(holderLocationOffset, applyEntityLocationOffset, defaultHolderLocationOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,12 +27,12 @@ import org.jetbrains.annotations.Nullable;
|
|||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
|
||||
public class LeashDataProvider implements ICapabilitySerializable<CompoundTag> {
|
||||
public static final ResourceLocation LEASH_DATA_REL = new ResourceLocation(SuperLeadRope.MOD_ID, "leash_data");
|
||||
private final ILeashDataCapability instance;
|
||||
private final LazyOptional<ILeashDataCapability> optional;
|
||||
private final ILeashData instance;
|
||||
private final LazyOptional<ILeashData> optional;
|
||||
public LeashDataProvider(Entity entity) {
|
||||
this.instance = new LeashDataImpl(entity);
|
||||
this.optional = LazyOptional.of(() -> instance);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.capability.provider;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashStateImpl;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
||||
|
||||
public class LeashStateProvider implements ICapabilitySerializable<CompoundTag> {
|
||||
public static final ResourceLocation LEASH_STATE_REL = new ResourceLocation(SuperLeadRope.MOD_ID, "leash_state");
|
||||
private final ILeashState instance;
|
||||
private final LazyOptional<ILeashState> optional;
|
||||
public LeashStateProvider(Entity entity) {
|
||||
this.instance = new LeashStateImpl(entity);
|
||||
this.optional = LazyOptional.of(() -> instance);
|
||||
}
|
||||
@Override
|
||||
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
||||
return CapabilityHandler.LEASH_STATE_CAP.orEmpty(cap, optional);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag serializeNBT() {
|
||||
return instance.serializeNBT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeNBT(CompoundTag nbt) {
|
||||
instance.deserializeNBT(nbt);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.command;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.superleadrope.config.LeashCommonConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Command {
|
||||
public static final String PREFIX = LeashCommonConfig.COMMON.SLPModCommandPrefix.get();
|
||||
public static boolean SHOULD_USE_PREFIX = LeashCommonConfig.COMMON.EnableSLPModCommandPrefix.get();
|
||||
static LiteralArgumentBuilder<CommandSourceStack> getLiterArgumentBuilderOfCSS(String name, boolean shouldAddToList, @Nullable List<LiteralArgumentBuilder<CommandSourceStack>> list) {
|
||||
LiteralArgumentBuilder<CommandSourceStack> literal = Commands.literal(name);
|
||||
if (shouldAddToList) {
|
||||
assert list != null;
|
||||
list.add(literal);
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
public class LeashDataCommand {
|
||||
// 获取Data
|
||||
// 设置Data
|
||||
// <add/transfer/remove> Holder<BlockPos/Entity<需判断实体类型>>
|
||||
// 设置对应目标的 最大长度 最长断裂距离 保持不断裂时间刻
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
public class LeashStateCommand {
|
||||
// 获取State
|
||||
// 设置State
|
||||
// <add/set/reset> Holder<BlockPos/Entity<需判断实体类型>> <Holder/Entity> <x> <y> <z>
|
||||
// 设置对应目标的 拴绳偏移
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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.command;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.DoubleArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.network.NetworkHandler;
|
||||
import top.r3944realms.superleadrope.network.toClient.UpdatePlayerMovementPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static top.r3944realms.superleadrope.content.command.Command.*;
|
||||
|
||||
|
||||
public class MotionCommand {
|
||||
private final static String SLP_MOTION_MESSAGE_ = SuperLeadRope.MOD_ID + ".command.motion.message.";
|
||||
public final static String MOTION_SETTER_SUCCESSFUL = SLP_MOTION_MESSAGE_ + "setter.successful",
|
||||
MOTION_ADDER_SUCCESSFUL = SLP_MOTION_MESSAGE_ + "adder.successful",
|
||||
MOTION_MULTIPLY_SUCCESSFUL = SLP_MOTION_MESSAGE_ + "multiply.successful";
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
@Nullable List<LiteralArgumentBuilder<CommandSourceStack>> nodeList = SHOULD_USE_PREFIX ? null : new ArrayList<>();
|
||||
LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder = Commands.literal(PREFIX);
|
||||
LiteralArgumentBuilder<CommandSourceStack> $$motionRoot = getLiterArgumentBuilderOfCSS("motion", !SHOULD_USE_PREFIX, nodeList);
|
||||
com.mojang.brigadier.Command<CommandSourceStack> motionVecAdder = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
for(Entity entity : EntityArgument.getEntities(context, "targets")){
|
||||
Vec3 motionVec = new Vec3(
|
||||
DoubleArgumentType.getDouble(context, "vecX"),
|
||||
DoubleArgumentType.getDouble(context, "vecY"),
|
||||
DoubleArgumentType.getDouble(context, "vecZ")
|
||||
);
|
||||
boolean flag = entity instanceof ServerPlayer;
|
||||
if(entity instanceof ServerPlayer player) {
|
||||
NetworkHandler.sendToPlayer(new UpdatePlayerMovementPacket(UpdatePlayerMovementPacket.Operation.ADD, motionVec.x, motionVec.y, motionVec.z), player);
|
||||
} else {
|
||||
entity.addDeltaMovement(motionVec);
|
||||
}
|
||||
Vec3 deltaMovement = entity.getDeltaMovement();
|
||||
double vecX = deltaMovement.x, vecY = deltaMovement.y, vecZ = deltaMovement.z;
|
||||
source.sendSuccess(() ->
|
||||
Component.translatable(
|
||||
MOTION_ADDER_SUCCESSFUL,
|
||||
entity.getDisplayName(),
|
||||
flag ? vecX + motionVec.x : vecX,
|
||||
flag ? vecY + motionVec.y : vecY,
|
||||
flag ? vecZ + motionVec.z : vecZ
|
||||
), true
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> motionVecSetter = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
for(Entity entity : EntityArgument.getEntities(context, "targets")){
|
||||
Vec3 motionVec = new Vec3(
|
||||
DoubleArgumentType.getDouble(context, "vecX"),
|
||||
DoubleArgumentType.getDouble(context, "vecY"),
|
||||
DoubleArgumentType.getDouble(context, "vecZ")
|
||||
);
|
||||
boolean flag = entity instanceof ServerPlayer;
|
||||
if(entity instanceof ServerPlayer player) {
|
||||
NetworkHandler.sendToPlayer(new UpdatePlayerMovementPacket(UpdatePlayerMovementPacket.Operation.SET, motionVec.x, motionVec.y, motionVec.z), player);
|
||||
} else {
|
||||
entity.setDeltaMovement(motionVec);
|
||||
}
|
||||
double vecX = entity.getDeltaMovement().x, vecY = entity.getDeltaMovement().y, vecZ = entity.getDeltaMovement().z;
|
||||
source.sendSuccess(() ->
|
||||
Component.translatable(
|
||||
MOTION_SETTER_SUCCESSFUL,
|
||||
entity.getDisplayName(),
|
||||
flag ? motionVec.x : vecX,
|
||||
flag ? motionVec.y : vecY,
|
||||
flag ? motionVec.z : vecZ
|
||||
), true
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> motionVecMultiply = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
for(Entity entity : EntityArgument.getEntities(context, "targets")){
|
||||
Vec3 motionFactorVec = new Vec3(
|
||||
DoubleArgumentType.getDouble(context, "vecXFactor"),
|
||||
DoubleArgumentType.getDouble(context, "vecYFactor"),
|
||||
DoubleArgumentType.getDouble(context, "vecZFactor")
|
||||
);
|
||||
boolean flag = entity instanceof ServerPlayer;
|
||||
Vec3 deltaMovement = entity.getDeltaMovement();
|
||||
if(entity instanceof ServerPlayer player) {
|
||||
NetworkHandler.sendToPlayer(new UpdatePlayerMovementPacket(UpdatePlayerMovementPacket.Operation.MULTIPLY, motionFactorVec.x, motionFactorVec.y, motionFactorVec.z), player);
|
||||
} else {
|
||||
entity.setDeltaMovement(deltaMovement.multiply(motionFactorVec));
|
||||
}
|
||||
double vecX = deltaMovement.x, vecY = deltaMovement.y, vecZ = deltaMovement.z;
|
||||
source.sendSuccess(() ->
|
||||
Component.translatable(
|
||||
MOTION_MULTIPLY_SUCCESSFUL,
|
||||
entity.getDisplayName(),
|
||||
flag ? vecX * motionFactorVec.x : vecX,
|
||||
flag ? vecY * motionFactorVec.y : vecY,
|
||||
flag ? vecZ * motionFactorVec.z : vecZ
|
||||
), true
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> Motion = $$motionRoot.requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("targets", EntityArgument.entities())
|
||||
.then(Commands.literal("add")
|
||||
.then(Commands.argument("vecX", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecY", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecZ", DoubleArgumentType.doubleArg())
|
||||
.executes(motionVecAdder)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("set")
|
||||
.then(Commands.argument("vecX", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecY", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecZ", DoubleArgumentType.doubleArg())
|
||||
.executes(motionVecSetter)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("multiply")
|
||||
.then(Commands.argument("vecXFactor", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecYFactor", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecZFactor", DoubleArgumentType.doubleArg())
|
||||
.executes(motionVecMultiply)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
if(SHOULD_USE_PREFIX){
|
||||
literalArgumentBuilder.then(Motion);
|
||||
dispatcher.register(literalArgumentBuilder);
|
||||
} else {
|
||||
if (nodeList != null) {
|
||||
nodeList.forEach(dispatcher::register);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +37,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.core.register.SLPEntityTypes;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
|
@ -81,9 +82,9 @@ public class SuperLeashKnotEntity extends LeashFenceKnotEntity {
|
|||
this.markHurt();
|
||||
this.playSound(SoundEvents.LEASH_KNOT_BREAK);
|
||||
List<Entity> entities = LeashDataImpl.leashableInArea(this.level(), pos.getCenter(), entity -> LeashDataImpl.isLeashHolder(entity, this));
|
||||
entities.forEach(entity -> entity
|
||||
.getCapability(CapabilityHandler.LEASH_DATA_CAP)
|
||||
.map(iLeashDataCapability -> iLeashDataCapability.removeLeash(this))
|
||||
entities.forEach(entity ->
|
||||
LeashUtil.getLeashData(entity)
|
||||
.map(iLeashDataCapability -> iLeashDataCapability.removeLeash(this))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -168,11 +169,11 @@ public class SuperLeashKnotEntity extends LeashFenceKnotEntity {
|
|||
List<Entity> entities = LeashDataImpl.leashableInArea(player);
|
||||
for(Entity entity : entities) {
|
||||
if (LeashDataImpl.isLeashHolder(entity, player.getUUID()))
|
||||
entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> {
|
||||
i.transferLeash(player.getUUID(), this);
|
||||
isTransferLeash.set(true);
|
||||
});
|
||||
|
||||
LeashUtil.getLeashData(entity)
|
||||
.ifPresent(i -> {
|
||||
i.transferLeash(player.getUUID(), this);
|
||||
isTransferLeash.set(true);
|
||||
});
|
||||
}
|
||||
AtomicBoolean isRemoveLeashKnot = new AtomicBoolean(false);
|
||||
if (!isTransferLeash.get()) {
|
||||
|
|
@ -180,14 +181,14 @@ public class SuperLeashKnotEntity extends LeashFenceKnotEntity {
|
|||
this.playSound(SoundEvents.LEASH_KNOT_BREAK);
|
||||
this.discard();
|
||||
List<Entity> entities1 = LeashDataImpl.leashableInArea(this);
|
||||
entities1.forEach(
|
||||
entity -> entity
|
||||
.getCapability(CapabilityHandler.LEASH_DATA_CAP)
|
||||
.ifPresent(iLeashDataCapability -> {
|
||||
iLeashDataCapability.removeLeash(this);
|
||||
isRemoveLeashKnot.set(true);
|
||||
}
|
||||
));
|
||||
entities1.forEach(entity ->
|
||||
LeashUtil.getLeashData(entity)
|
||||
.ifPresent(iLeashDataCapability -> {
|
||||
iLeashDataCapability.removeLeash(this);
|
||||
isRemoveLeashKnot.set(true);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.playSound(SoundEvents.LEASH_KNOT_PLACE);
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ public class SLPGamerules {
|
|||
public static final SLPGameruleRegistry GAMERULE_REGISTRY = SLPGameruleRegistry.INSTANCE;
|
||||
public static final HashMap<String, Boolean> gamerulesBooleanValuesClient = new HashMap<>();
|
||||
public static final HashMap<String, Integer> gameruleIntegerValuesClient = new HashMap<>();
|
||||
public static final HashMap<String, Float> gameruleFloatValuesClient = new HashMap<>();
|
||||
public static final String RULE_KEY_PERFix_ = "gamerule." + GAMERULE_PREFIX;
|
||||
public static final String RULE_KEY_PERFix_ = "gamerule." + GAMERULE_PREFIX.toLowerCase();
|
||||
public static String getDescriptionKey(Class<?> gameRuleClass) {
|
||||
return RULE_KEY_PERFix_ + gameRuleClass.getSimpleName() + ".description";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ import top.r3944realms.superleadrope.content.gamerule.SLPGamerules;
|
|||
|
||||
import static top.r3944realms.superleadrope.content.gamerule.SLPGamerules.GAMERULE_REGISTRY;
|
||||
|
||||
public class TeleportWithLeashedPlayers {
|
||||
public class TeleportWithLeashedEntities {
|
||||
public static final boolean DEFAULT_VALUE = true;
|
||||
public static final String ID = SLPGamerules.getGameruleName(TeleportWithLeashedPlayers.class);
|
||||
public static final String DESCRIPTION_KEY = SLPGamerules.getDescriptionKey(TeleportWithLeashedPlayers.class);
|
||||
public static final String NAME_KEY = SLPGamerules.getNameKey(TeleportWithLeashedPlayers.class);
|
||||
public static final String ID = SLPGamerules.getGameruleName(TeleportWithLeashedEntities.class);
|
||||
public static final String DESCRIPTION_KEY = SLPGamerules.getDescriptionKey(TeleportWithLeashedEntities.class);
|
||||
public static final String NAME_KEY = SLPGamerules.getNameKey(TeleportWithLeashedEntities.class);
|
||||
public static final GameRules.Category CATEGORY = GameRules.Category.PLAYER;
|
||||
|
||||
public static void register() {
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
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;
|
||||
|
|
@ -33,11 +34,13 @@ import org.jetbrains.annotations.NotNull;
|
|||
import top.r3944realms.superleadrope.content.SLPToolTier;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.entity.SuperLeashKnotEntity;
|
||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||
import top.r3944realms.superleadrope.util.capability.LeashUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
|
@ -76,7 +79,7 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
|||
return super.use(pLevel, pPlayer, pUsedHand);
|
||||
|
||||
}
|
||||
return InteractionResultHolder.pass(lead);
|
||||
return InteractionResultHolder.success(lead);
|
||||
}
|
||||
|
||||
public static boolean canUse(ItemStack itemStack) {
|
||||
|
|
@ -89,14 +92,14 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
|||
BlockPos pos = context.getClickedPos();
|
||||
BlockState state = level.getBlockState(pos);
|
||||
ItemStack itemStack = context.getItemInHand();
|
||||
if (canUse(itemStack)) return InteractionResult.PASS;
|
||||
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.PASS;
|
||||
return bindToBlock(player, level, pos, itemStack, false) ? InteractionResult.CONSUME : InteractionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
return InteractionResult.PASS;
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
/**
|
||||
* 右键蹲下绑定到另一实体上
|
||||
|
|
@ -119,25 +122,28 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
|||
* @return 是否成功
|
||||
*/
|
||||
public static boolean bindToEntity(Entity newHolder, Player player, Level level, BlockPos pos, ItemStack leashStack) {
|
||||
AtomicBoolean isSuccess = new AtomicBoolean(false);
|
||||
List<Entity> list = LeashDataImpl.leashableInArea(level, pos.getCenter(), entity -> LeashDataImpl.isLeashHolder(entity, player.getUUID()));
|
||||
for(Entity e : list) {
|
||||
AtomicBoolean canBeAttachedTo = new AtomicBoolean(false);
|
||||
LazyOptional<ILeashDataCapability> iLeashDataCapability = e.getCapability(CapabilityHandler.LEASH_DATA_CAP);
|
||||
iLeashDataCapability.ifPresent(i -> canBeAttachedTo.set(i.canBeAttachedTo(newHolder)));
|
||||
if(canBeAttachedTo.get()) {//canBeAttachedTo
|
||||
iLeashDataCapability.ifPresent(i -> {
|
||||
i.transferLeash(player.getUUID(), newHolder, leashStack);
|
||||
isSuccess.set(true);
|
||||
});
|
||||
boolean isSuccess = false;
|
||||
|
||||
// 查找当前玩家持有的可拴生物
|
||||
List<Entity> list = LeashDataImpl.leashableInArea(
|
||||
level, pos.getCenter(),
|
||||
entity -> LeashDataImpl.isLeashHolder(entity, player.getUUID())
|
||||
);
|
||||
|
||||
for (Entity e : list) {
|
||||
Optional<ILeashData> leashDataOpt = LeashUtil.getLeashData(e);
|
||||
|
||||
if (leashDataOpt.map(i -> i.canBeAttachedTo(newHolder)).orElse(false)) {
|
||||
leashDataOpt.ifPresent(i -> i.transferLeash(player.getUUID(), newHolder));
|
||||
isSuccess = true;
|
||||
}
|
||||
}
|
||||
if(!isSuccess.get()) {
|
||||
|
||||
if (!isSuccess) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
level.gameEvent(GameEvent.ENTITY_INTERACT, pos, GameEvent.Context.of(player));
|
||||
newHolder.playSound(SLPSoundEvents.LEAD_TIED.get());
|
||||
level.playSound(null, newHolder.getOnPos(), SLPSoundEvents.LEAD_UNTIED.get(), SoundSource.PLAYERS);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,48 +161,56 @@ public class SuperLeadRopeItem extends TieredItem implements IForgeItem {
|
|||
}
|
||||
/**
|
||||
* 右键蹲下绑定到支持方块上
|
||||
* @param player 明确持有玩家
|
||||
* @param level 维度世界
|
||||
* @param pos 坐标(一般是明确持有玩家的位置)
|
||||
* @param leashStack 拴绳物品实例
|
||||
*
|
||||
* @param player 明确持有玩家
|
||||
* @param level 维度世界
|
||||
* @param pos 坐标(一般是明确持有玩家的位置)
|
||||
* @param leashStack 拴绳物品实例
|
||||
* @param shouldBindSelf 是否应该触发拴自己逻辑检查
|
||||
* @return 是否成功
|
||||
*/
|
||||
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 = LeashDataImpl.leashableInArea(level, pos.getCenter(), entity -> LeashDataImpl.isLeashHolder(entity, uuid));
|
||||
if (shouldBindSelf && list.isEmpty()) {//拴自己 to new knot
|
||||
if (leashStack.isEmpty() || !canUse(leashStack)) return false;
|
||||
knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);;
|
||||
|
||||
List<Entity> list = LeashDataImpl.leashableInArea(level, pos.getCenter(),
|
||||
entity -> LeashDataImpl.isLeashHolder(entity, uuid));
|
||||
|
||||
// 情况一:拴自己到新 knot
|
||||
if (shouldBindSelf && list.isEmpty()) {
|
||||
if (leashStack.isEmpty() || !canUse(leashStack)) {
|
||||
return false;
|
||||
}
|
||||
knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);
|
||||
knot.playPlacementSound();
|
||||
|
||||
SuperLeashKnotEntity finalKnot1 = knot;
|
||||
player.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(i -> {
|
||||
i.addLeash(finalKnot1, leashStack, 8D);
|
||||
SuperLeashKnotEntity finalKnot = knot;
|
||||
LeashUtil.getLeashData(player).ifPresent(i -> {
|
||||
if (i.canBeAttachedTo(finalKnot)) {
|
||||
i.addLeash(finalKnot);
|
||||
isSuccess.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
// 情况二:把已有生物拴到 knot
|
||||
else if (!list.isEmpty()) {
|
||||
for(Entity e : list) {
|
||||
if(knot == null) {
|
||||
for (Entity e : list) {
|
||||
if (knot == null) {
|
||||
knot = SuperLeashKnotEntity.getOrCreateKnot(level, pos);
|
||||
knot.playPlacementSound();
|
||||
}
|
||||
SuperLeashKnotEntity finalKnot = knot;
|
||||
LazyOptional<ILeashDataCapability> iLeashDataCapability = e.getCapability(CapabilityHandler.LEASH_DATA_CAP);
|
||||
iLeashDataCapability.ifPresent(i -> {
|
||||
boolean flag = i.canBeAttachedTo(finalKnot);
|
||||
if (flag) {
|
||||
|
||||
LeashUtil.getLeashData(e).ifPresent(i -> {
|
||||
if (i.canBeAttachedTo(finalKnot)) {
|
||||
i.transferLeash(uuid, finalKnot);
|
||||
isSuccess.set(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (isSuccess.get()) {
|
||||
level.gameEvent(GameEvent.BLOCK_ATTACH, pos, GameEvent.Context.of(player));
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package top.r3944realms.superleadrope.core.leash;
|
||||
|
||||
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
|
@ -28,7 +29,7 @@ import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
|||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.impi.LeashDataImpl;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.item.SuperLeadRopeItem;
|
||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||
import top.r3944realms.superleadrope.core.register.SLPSoundEvents;
|
||||
|
|
@ -45,7 +46,7 @@ public class LeashInteractHandler {
|
|||
player.getItemInHand(InteractionHand.OFF_HAND).is(SLPItems.SUPER_LEAD_ROPE.get()))
|
||||
) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(InteractionResult.CONSUME);
|
||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -56,7 +57,7 @@ public class LeashInteractHandler {
|
|||
if (!LeashDataImpl.isLeashable(target)) {
|
||||
return;
|
||||
}
|
||||
LazyOptional<ILeashDataCapability> LeashCap = target.getCapability(CapabilityHandler.LEASH_DATA_CAP);
|
||||
LazyOptional<ILeashData> LeashCap = target.getCapability(CapabilityHandler.LEASH_DATA_CAP);
|
||||
if (!LeashCap.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -67,14 +68,14 @@ public class LeashInteractHandler {
|
|||
if (
|
||||
mainHandItem.isEmpty() && offHandItem.isEmpty() &&
|
||||
target.isAlive() && player.isSecondaryUseActive() &&
|
||||
LeashCap.map(ILeashDataCapability::canBeLeashed).orElse(false)
|
||||
LeashCap.map(ILeashData::canBeLeashed).orElse(false)
|
||||
|
||||
) {
|
||||
|
||||
boolean isSuccess = SuperLeadRopeItem.bindToEntity(target, player, player.level(), player.getOnPos(), ItemStack.EMPTY);
|
||||
if (isSuccess) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(InteractionResult.CONSUME);
|
||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
}
|
||||
} else {
|
||||
if (LeashDataImpl.isLeashHolder(target, player)) {
|
||||
|
|
@ -82,9 +83,9 @@ public class LeashInteractHandler {
|
|||
iLeashDataCapability -> iLeashDataCapability.removeLeash(player.getUUID())
|
||||
);
|
||||
target.gameEvent(GameEvent.ENTITY_INTERACT, player);
|
||||
target.playSound(SLPSoundEvents.LEAD_UNTIED.get());
|
||||
level.playSound(null, target.getOnPos(), SLPSoundEvents.LEAD_UNTIED.get(), SoundSource.PLAYERS);
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(InteractionResult.CONSUME);
|
||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
return;
|
||||
}
|
||||
ItemStack itemStack;
|
||||
|
|
@ -99,13 +100,13 @@ public class LeashInteractHandler {
|
|||
if (itemStack.getItem() == SLPItems.SUPER_LEAD_ROPE.get()) {
|
||||
LeashCap.ifPresent(iLeashDataCapability -> {
|
||||
if (iLeashDataCapability.canBeAttachedTo(player)) {
|
||||
boolean success = iLeashDataCapability.addLeash(player, itemStack, 12);
|
||||
boolean success = iLeashDataCapability.addLeash(player);
|
||||
if (success) {
|
||||
if(!player.isCreative())
|
||||
itemStack.hurtAndBreak(24, player, e->{});
|
||||
target.playSound(SLPSoundEvents.LEAD_TIED.get());
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(InteractionResult.CONSUME);
|
||||
level.playSound(null, target.getOnPos(), SLPSoundEvents.LEAD_TIED.get(), SoundSource.PLAYERS);
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(InteractionResult.SUCCESS);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -124,11 +125,12 @@ public class LeashInteractHandler {
|
|||
if (flag) {
|
||||
target.getCapability(CapabilityHandler.LEASH_DATA_CAP).ifPresent(leashDataCapability -> {
|
||||
if (leashDataCapability.hasLeash()){
|
||||
int size = leashDataCapability.getAllLeashes().size();
|
||||
if (player.isSecondaryUseActive())
|
||||
leashDataCapability.removeAllLeashes();
|
||||
else
|
||||
leashDataCapability.removeAllHolderLeashes();
|
||||
target.playSound(SLPSoundEvents.LEAD_UNTIED.get());
|
||||
leashDataCapability.removeAllKnotLeashes();
|
||||
if(size > leashDataCapability.getAllLeashes().size()) level.playSound(null, target.getOnPos(), SLPSoundEvents.LEAD_UNTIED.get(), SoundSource.PLAYERS);
|
||||
}
|
||||
event.setCanceled(true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@
|
|||
|
||||
package top.r3944realms.superleadrope.core.leash;
|
||||
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashDataCapability;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
|
@ -24,16 +25,29 @@ import java.util.function.Consumer;
|
|||
|
||||
// 全局LeashData同步管理器
|
||||
public class LeashSyncManager {
|
||||
static final Set<ILeashDataCapability> INSTANCES = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
|
||||
public static void track(ILeashDataCapability instance) {
|
||||
INSTANCES.add(instance);
|
||||
static final Set<ILeashData> LEASH_DATA = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
static final Set<ILeashState> LEASH_STATES = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
public static class Data {
|
||||
public static void track(ILeashData instance) {
|
||||
LEASH_DATA.add(instance);
|
||||
}
|
||||
public static void untrack(ILeashData instance) {
|
||||
LEASH_DATA.remove(instance);
|
||||
}
|
||||
public static void forEach(Consumer<ILeashData> consumer) {
|
||||
LEASH_DATA.forEach(consumer);
|
||||
}
|
||||
}
|
||||
public static void untrack(ILeashDataCapability instance) {
|
||||
INSTANCES.remove(instance);
|
||||
}
|
||||
public static void forEach(Consumer<ILeashDataCapability> consumer) {
|
||||
INSTANCES.forEach(consumer);
|
||||
public static class State {
|
||||
public static void track(ILeashState instance) {
|
||||
LEASH_STATES.add(instance);
|
||||
}
|
||||
public static void untrack(ILeashState instance) {
|
||||
LEASH_STATES.remove(instance);
|
||||
}
|
||||
public static void forEach(Consumer<ILeashState> consumer) {
|
||||
LEASH_STATES.forEach(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ import net.minecraft.server.MinecraftServer;
|
|||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
import top.r3944realms.superleadrope.content.gamerule.SLPGamerules;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedPlayers;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedEntities;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -70,7 +70,7 @@ public enum SLPGameruleRegistry {
|
|||
gameruleDataTypes.put(gameruleName, RuleDataType.INTEGER);
|
||||
}
|
||||
public static void register() {
|
||||
TeleportWithLeashedPlayers.register();
|
||||
TeleportWithLeashedEntities.register();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -18,7 +18,8 @@ package top.r3944realms.superleadrope.datagen.data;
|
|||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedPlayers;
|
||||
import top.r3944realms.superleadrope.content.command.MotionCommand;
|
||||
import top.r3944realms.superleadrope.content.gamerule.server.TeleportWithLeashedEntities;
|
||||
import top.r3944realms.superleadrope.content.item.EternalPotatoItem;
|
||||
import top.r3944realms.superleadrope.core.register.SLPEntityTypes;
|
||||
import top.r3944realms.superleadrope.core.register.SLPItems;
|
||||
|
|
@ -187,15 +188,38 @@ public enum SLPLangKeyValue {
|
|||
SLPEntityTypes.getEntityNameKey("super_lead_knot"), ModPartEnum.ENTITY,
|
||||
"Super Lead Knot", "超级拴绳结", "超級拴繩結", "神駒羈縻索結"
|
||||
),
|
||||
TELEPORT_WITH_LEASHED_PLAYERS_NAME(TeleportWithLeashedPlayers.NAME_KEY, ModPartEnum.GAME_RULE,
|
||||
TELEPORT_WITH_LEASHED_ENTITIES_NAME(TeleportWithLeashedEntities.NAME_KEY, ModPartEnum.GAME_RULE,
|
||||
"Teleport leashed player with player holder",
|
||||
"被拴实体随玩家持有者传送",
|
||||
"被拴实体随玩家持有者傳送"
|
||||
"被拴实体随玩家持有者傳送",
|
||||
"繫畜隨持者傳送"
|
||||
),
|
||||
TELEPORT_WITH_LEASHED_DESCRIPTION(TeleportWithLeashedPlayers.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION,
|
||||
TELEPORT_WITH_LEASHED_DESCRIPTION(TeleportWithLeashedEntities.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION,
|
||||
"Holder will teleport with their leashed players ",
|
||||
"传送时将被拴玩家与持有者一起传送",
|
||||
"將被拴玩家將隨持有者一起傳送"
|
||||
"传送时将被拴实体与持有者一起传送",
|
||||
"將被拴实体將隨持有者一起傳送",
|
||||
"傳送時繫畜隨持者同傳"
|
||||
),
|
||||
MESSAGE_MOTION_ADDER_SUCCESSFUL(
|
||||
MotionCommand.MOTION_ADDER_SUCCESSFUL, ModPartEnum.COMMAND,
|
||||
"§bAdd Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r",
|
||||
"§b添加成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"§b添加成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"§b增益既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r"
|
||||
),
|
||||
MESSAGE_MOTION_SETTER_SUCCESSFUL(
|
||||
MotionCommand.MOTION_SETTER_SUCCESSFUL, ModPartEnum.COMMAND,
|
||||
"§bSet Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r",
|
||||
"§b设置成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"§b設置成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"§b定值既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r"
|
||||
),
|
||||
MESSAGE_MOTION_MULTIPLY_SUCCESSFUL(
|
||||
MotionCommand.MOTION_MULTIPLY_SUCCESSFUL, ModPartEnum.COMMAND,
|
||||
"§bMultiply Successfully.§a%s§7:§f[§eVec§7:§a(§f%.2f§7,§f%.2f§7,§f%.2f§7)§f]§r",
|
||||
"§b倍乘成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"§b倍乘成功.§a%s§7:§f[§e加速§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r",
|
||||
"§b倍乘既成.§a%s§7:§f[§e速勢§7:(§a%.2f§7,§a%.2f§7,§a%.2f§7)§f]§r"
|
||||
),
|
||||
|
||||
;
|
||||
|
|
|
|||
|
|
@ -22,20 +22,16 @@ import net.minecraftforge.network.NetworkRegistry;
|
|||
import net.minecraftforge.network.PacketDistributor;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
import top.r3944realms.superleadrope.SuperLeadRope;
|
||||
import top.r3944realms.superleadrope.network.toClient.EternalPotatoSyncCapPacket;
|
||||
import top.r3944realms.superleadrope.network.toClient.LeashDataSyncPacket;
|
||||
import top.r3944realms.superleadrope.network.toClient.PacketEternalPotatoRemovePacket;
|
||||
import top.r3944realms.superleadrope.network.toClient.UpdatePlayerMovementPacket;
|
||||
import top.r3944realms.superleadrope.network.toClient.*;
|
||||
|
||||
|
||||
public class NetworkHandler {
|
||||
private static final String PROTOCOL_VERSION = "1";
|
||||
private static int cid = 0;
|
||||
public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(
|
||||
new ResourceLocation(SuperLeadRope.MOD_ID, "main"),
|
||||
() -> PROTOCOL_VERSION,
|
||||
PROTOCOL_VERSION::equals,
|
||||
PROTOCOL_VERSION::equals
|
||||
() -> SuperLeadRope.ModInfo.VERSION,
|
||||
SuperLeadRope.ModInfo.VERSION::equals,
|
||||
SuperLeadRope.ModInfo.VERSION::equals
|
||||
);
|
||||
public static void register() {
|
||||
INSTANCE.messageBuilder(LeashDataSyncPacket.class, cid++, NetworkDirection.PLAY_TO_CLIENT)
|
||||
|
|
@ -58,6 +54,11 @@ public class NetworkHandler {
|
|||
.encoder(PacketEternalPotatoRemovePacket::encode)
|
||||
.consumerNetworkThread(PacketEternalPotatoRemovePacket::handle)
|
||||
.add();
|
||||
INSTANCE.messageBuilder(LeashStateSyncPacket.class, cid++, NetworkDirection.PLAY_TO_CLIENT)
|
||||
.decoder(LeashStateSyncPacket::decode)
|
||||
.encoder(LeashStateSyncPacket::encode)
|
||||
.consumerNetworkThread(LeashStateSyncPacket::handle)
|
||||
.add();
|
||||
}
|
||||
public static <MSG> void sendToPlayer(MSG message, ServerPlayer player){
|
||||
INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), message);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.network.toClient;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record LeashStateSyncPacket(int entityId, CompoundTag leashState) {
|
||||
public static void encode(LeashStateSyncPacket msg, FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(msg.entityId);
|
||||
buffer.writeNbt(msg.leashState);
|
||||
}
|
||||
|
||||
public static LeashStateSyncPacket decode(FriendlyByteBuf buffer) {
|
||||
return new LeashStateSyncPacket(buffer.readInt(), buffer.readNbt());
|
||||
}
|
||||
|
||||
public static void handle(LeashStateSyncPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
if (level != null) {
|
||||
Entity entity = level.getEntity(msg.entityId);
|
||||
if (entity != null) {
|
||||
entity.getCapability(CapabilityHandler.LEASH_STATE_CAP).ifPresent(cap -> {
|
||||
// 只在数据确实变化时更新
|
||||
CompoundTag current = cap.serializeNBT();
|
||||
if (!current.equals(msg.leashState)) {
|
||||
cap.deserializeNBT(msg.leashState);//更新
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.util.capability;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.r3944realms.superleadrope.content.capability.CapabilityHandler;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashData;
|
||||
import top.r3944realms.superleadrope.content.capability.inter.ILeashState;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class LeashUtil {
|
||||
public static Optional<ILeashData> getLeashData(@NotNull Entity entity) {
|
||||
Objects.requireNonNull(entity, "Entity cannot be null");
|
||||
return entity.getCapability(CapabilityHandler.LEASH_DATA_CAP).resolve();
|
||||
}
|
||||
public static Optional<ILeashState> getLeashState(@NotNull Entity entity) {
|
||||
Objects.requireNonNull(entity, "Entity cannot be null");
|
||||
return entity.getCapability(CapabilityHandler.LEASH_STATE_CAP).resolve();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.util.nbt;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class NBTReader {
|
||||
public static Vec3 readVec3(CompoundTag nbt) {
|
||||
if (nbt.contains("X") && nbt.contains("Y") && nbt.contains("Z")) {
|
||||
return new Vec3(
|
||||
nbt.getDouble("X"),
|
||||
nbt.getDouble("Y"),
|
||||
nbt.getDouble("Z")
|
||||
);
|
||||
} else {
|
||||
throw new IllegalArgumentException("NBT is missing X, Y, or Z value for Vec3");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.util.nbt;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class NBTWriter {
|
||||
public static CompoundTag writeVec3(Vec3 vec) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
if (vec == null) throw new IllegalArgumentException("Vec3 cannot be null");
|
||||
|
||||
nbt.putDouble("X", vec.x);
|
||||
nbt.putDouble("Y", vec.y);
|
||||
nbt.putDouble("Z", vec.z);
|
||||
return nbt;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
package top.r3944realms.superleadrope.util.riding;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import top.r3944realms.superleadrope.config.LeashCommonConfig;
|
||||
|
|
@ -26,17 +29,34 @@ public class RidingValidator {
|
|||
/**
|
||||
* 是否在配置白名单里
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean isInWhitelist(EntityType<?> type) {
|
||||
//noinspection deprecation
|
||||
String key = type.builtInRegistryHolder().key().location().toString();
|
||||
String modid = key.split(":")[0];
|
||||
|
||||
for (String entry : LeashCommonConfig.COMMON.teleportWhitelist.get()) {
|
||||
if (entry.startsWith("#")) {
|
||||
if (modid.equals(entry.substring(1))) {
|
||||
String body = entry.substring(1);
|
||||
|
||||
// Case 1: #modid → allow all entities from this mod
|
||||
if (!body.contains(":")) {
|
||||
if (modid.equals(body)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Case 2: #modid:tag_name → allow all entities under this tag
|
||||
else {
|
||||
ResourceLocation tagId = new ResourceLocation(body);
|
||||
TagKey<EntityType<?>> tag = TagKey.create(Registries.ENTITY_TYPE, tagId);
|
||||
if (type.builtInRegistryHolder().is(tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Case 3: modid:entity_name → allow a specific entity
|
||||
if (entry.equals(key)) {
|
||||
return true;
|
||||
}
|
||||
} else if (entry.equals(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user