LeashedPlayer/src/main/java/com/r3944realms/leashedplayer/modInterface/PlayerLeashable.java
2025-04-10 09:03:09 +08:00

226 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

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

package com.r3944realms.leashedplayer.modInterface;
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
import com.r3944realms.leashedplayer.content.criteriaTriggers.ModCriteriaTriggers;
import com.r3944realms.leashedplayer.utils.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.Optional;
import java.util.UUID;
public interface PlayerLeashable extends Leashable {
/**
* 获取拴绳的持有者实体 可能不存在
*/
@Nullable
Entity getLeashHolder();
/**
* 获取拴绳的持有者数据 从EntityData中获取
*/
LeashData getLeashDataFromEntityData();
/**
* 是否立即可被拴住
*/
boolean canBeLeashedInstantly(Player player);
/**
* 设置栓绳数据
* @param pLeashHolder 拴绳持有者
* @param pBroadcastPacket 是否广播包
*/
default void setLeashedTo(@NotNull Entity pLeashHolder, boolean pBroadcastPacket) {
setLeashedTo((Entity & Leashable)this, pLeashHolder, pBroadcastPacket);
if(this instanceof ServerPlayer) {
ModCriteriaTriggers.LEASH_PLAYER_TRIGGER.get().trigger((ServerPlayer) this, pLeashHolder);
}
}
static <E extends Entity & Leashable> void setLeashedTo(E pEntity, Entity pLeashHolder, boolean pBroadcastPacket) {
LeashData leashable$leashdata = pEntity.getLeashData();
if (leashable$leashdata == null) {
leashable$leashdata = new LeashData(pLeashHolder);
pEntity.setLeashData(leashable$leashdata);
} else {
leashable$leashdata.setLeashHolder(pLeashHolder);
}
if (pBroadcastPacket && pEntity.level() instanceof ServerLevel serverlevel) {
serverlevel.getChunkSource().broadcast(pEntity, new ClientboundSetEntityLinkPacket(pEntity, pLeashHolder));
}
//这边覆写去掉了乘坐相关的逻辑,即乘坐状态下也可以正常被栓住,不影响其乘坐状态
}
static void legacyElasticRangeLeashBehaviour(Entity holderEntity, Entity restrainedEntity) {
float leashLength = LeashCommand.MIN_VALUE;
if (restrainedEntity instanceof ILivingEntityExtension iEntity) {
// 获取绳长
float leashLengthFormValue = iEntity.getLeashLength();
leashLength = leashLengthFormValue > LeashCommand.MIN_VALUE ? leashLengthFormValue : LeashCommand.MIN_VALUE;
}
// 两者距离
float distance = holderEntity.distanceTo(restrainedEntity);
Entity applyMovementEntity = restrainedEntity.isPassenger() ? restrainedEntity.getVehicle() : restrainedEntity;
// 仅当距离大于绳长时施加拉力
if (applyMovementEntity != null && distance > leashLength) {
MethodA(holderEntity, applyMovementEntity, distance, leashLength);
// 控制速度不要过快,避免偏激移动
Util.MovementBrake(applyMovementEntity, entity -> {
Vec3 deltaMovement = entity.getDeltaMovement();
entity.setDeltaMovement(
Math.min(Math.abs(deltaMovement.x), 1.0) * Math.signum(deltaMovement.x),
Math.min(Math.abs(deltaMovement.y), 1.0) * Math.signum(deltaMovement.y),
Math.min(Math.abs(deltaMovement.z), 1.0) * Math.signum(deltaMovement.z)
);
entity.hurtMarked = true;
});
}
}
private static void MethodA(Entity holderEntity, Entity applyMovementEntity, float distance, float leashLength) {
// 计算朝向持有者的拉力方向
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
double dY = (holderEntity.getY() - applyMovementEntity.getY()) / (double) distance;
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
// 拉力大小,距离越远拉力越强,但施加一个最大限制
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
applyMovementEntity.setDeltaMovement(
applyMovementEntity.getDeltaMovement().add(
dX * pullStrength,
dY * pullStrength,
dZ * pullStrength
)
);
}
private static void MethodB(Entity holderEntity, Entity applyMovementEntity, float distance, float leashLength) {
// 计算朝向持有者的拉力方向
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
// 稳定点的目标高度
double targetY = holderEntity.getY() + 1.0; // 根据需要调整目标高度
double currentY = applyMovementEntity.getY();
double heightDifference = targetY - currentY;
// 控制垂直方向的拉力
double dY = heightDifference > 0.5 ? 0.1 : (heightDifference < -0.5 ? -0.1 : 0);
// 拉力大小,距离越远拉力越强,但施加一个最大限制
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
applyMovementEntity.setDeltaMovement(
applyMovementEntity.getDeltaMovement().add(
dX * pullStrength,
dY,
dZ * pullStrength
)
);
}
@Nullable
static Entity getLeashDataEntity(@NotNull ServerPlayer serverPlayer , @NotNull ServerLevel serverLevel) {
LeashData leashDataFromEntityData = ((PlayerLeashable) serverPlayer).getLeashDataFromEntityData();
if (leashDataFromEntityData != null) {
return getLeashDataEntity(leashDataFromEntityData, serverLevel);
}
else return null;
}
static Entity getLeashDataEntityOrThrown(@NotNull ServerPlayer serverPlayer ,@NotNull ServerLevel serverLevel) throws Exception {
Entity leashedEntity = getLeashDataEntity(serverPlayer, serverLevel);
if(leashedEntity == null) throw new Exception("invalid");
else return leashedEntity;
}
@Nullable
static Entity getLeashDataEntity(@NotNull Leashable.LeashData leashDataFromEntityData, @NotNull ServerLevel level) {
if(leashDataFromEntityData.delayedLeashInfo != null) {
Optional<UUID> UUID = leashDataFromEntityData.delayedLeashInfo.left();
Optional<BlockPos> BlockPos = leashDataFromEntityData.delayedLeashInfo.right();
if (UUID.isPresent()) {
return level.getEntity(UUID.get());
} else return BlockPos.map(pos -> LeashFenceKnotEntity.getOrCreateKnot(level, pos)).orElse(null);
}
else if(leashDataFromEntityData.leashHolder != null) {
return leashDataFromEntityData.leashHolder;
}
else if(leashDataFromEntityData.delayedLeashHolderId != 0) {
return level.getEntity(leashDataFromEntityData.delayedLeashHolderId);
}
else return null;
}
static Entity getLeashDataEntityOrThrown(@NotNull Leashable.LeashData leashDataFromEntityData, @NotNull ServerLevel level) throws Exception {
if(leashDataFromEntityData.delayedLeashInfo != null) {
Optional<UUID> UUID = leashDataFromEntityData.delayedLeashInfo.left();
Optional<BlockPos> BlockPos = leashDataFromEntityData.delayedLeashInfo.right();
if (UUID.isPresent()) {
return level.getEntity(UUID.get());
} else if(BlockPos.isPresent()) {
return LeashFenceKnotEntity.getOrCreateKnot(level, BlockPos.get());
} else {
throw new Exception("invalid delayedLeashInfo");
}
}
else if(leashDataFromEntityData.leashHolder != null) {
return leashDataFromEntityData.leashHolder;
}
else if(leashDataFromEntityData.delayedLeashHolderId != 0) {
Entity entity = level.getEntity(leashDataFromEntityData.delayedLeashHolderId);
if(entity == null) {
throw new Exception("Not found Entity. maybe the pId is invalid");
}
return entity;
}
else {
throw new Exception("invalid leash data");
}
}
static boolean isLeashFenceKnotEntityExisted(ServerLevel pLevel, BlockPos pPos) {
int i = pPos.getX();
int j = pPos.getY();
int k = pPos.getZ();
for (LeashFenceKnotEntity leashfenceknotentity : pLevel.getEntitiesOfClass(
LeashFenceKnotEntity.class, new AABB((double)i - 1.0, (double)j - 1.0, (double)k - 1.0, (double)i + 1.0, (double)j + 1.0, (double)k + 1.0)
)) {
if (leashfenceknotentity.getPos().equals(pPos)) {
return true;
}
}
return false;
}
@Nullable
static Entity getLeashFenceKnotEntity(ServerLevel pLevel, BlockPos pPos) {
int i = pPos.getX();
int j = pPos.getY();
int k = pPos.getZ();
for (LeashFenceKnotEntity leashfenceknotentity : pLevel.getEntitiesOfClass(
LeashFenceKnotEntity.class, new AABB((double)i - 1.0, (double)j - 1.0, (double)k - 1.0, (double)i + 1.0, (double)j + 1.0, (double)k + 1.0)
)) {
if (leashfenceknotentity.getPos().equals(pPos)) {
return leashfenceknotentity;
}
}
return null;
}
static Entity createLeashKnotFence(ServerLevel pLevel, BlockPos pPos) {
LeashFenceKnotEntity leashfenceknotentity = new LeashFenceKnotEntity(pLevel, pPos);
pLevel.addFreshEntity(leashfenceknotentity);
return leashfenceknotentity;
}
}