狡诈师
本帖最后由 狡诈师 于 2022-9-28 01:24 编辑

TabooLib/ProtocolLib 实现无需NMS的实体坐骑



首先让驾驶员获得运动控制权,有以下办法
禁用默认移动AI或者添加缓慢药水效果
TabooLib提供了顶级函数clearGoalAi()

TabooLib + Kotlin
添加监听器对数据包接收进行监听
  1. @SubscribeEvent
  2. fun receive(ev: PacketReceiveEvent) {
  3. }
复制代码

对数据包处理前确认
  1. if (ev.isCancelled) { // 如果被拦截
  2.     return
  3. }
  4. if (ev.packet.name != "PacketPlayInSteerVehicle") { // 数据包
  5.     return
  6. }
复制代码

反编译分析目的获取横向速度、前进速度,跳跃
1.17+
  1. package net.minecraft.network.protocol.game;

  2. import net.minecraft.network.PacketDataSerializer;
  3. import net.minecraft.network.protocol.Packet;

  4. public class PacketPlayInSteerVehicle implements Packet<PacketListenerPlayIn> {
  5.     private static final int FLAG_JUMPING = 1;  // a
  6.     private static final int FLAG_SHIFT_KEY_DOWN = 2; // b
  7.     private final float xxa;  // c
  8.     private final float zza;  // d
  9.     private final boolean isJumping;  // e
  10.     private final boolean isShiftKeyDown;
复制代码
从上面分析可知我们需要的是float类型的xxa和zza,以及boolean类型isJumping,从第一个开始数标注了a,b,c,d,e...也就是说我们取出c,d,e就好了

但是,1.17以下版本有所不同,继续反编译分析
  1. public class PacketPlayInSteerVehicle implements Packet<PacketListenerPlayIn> {
  2.     private float a;
  3.     private float b;
  4.     private boolean c;
  5.     private boolean d;
复制代码
相当简洁,显而易见a,b是我们所需的(float类型容易知道),跳跃是c

总结
版本范围 前进速度 横向速度 跳跃
1.17及以上 c d e
1.16及以下 a b c

赋值变量
  1. val swSpeed = ev.packet.read<Float>(c)?: return // 前进速度(1.17+)
  2. val adSpeed = ev.packet.read<Float>(d)?: return // 横向速度(1.17+)
  3. val jumping = ev.packet.read<Boolean>(e)?: return // 跳跃(1.17+)
复制代码

为被乘骑的实体通过数据包拦截监听玩家控制wasd赋值数据包事件中玩家的位置
  1. val pLoc = ev.player.location
复制代码

设置被乘骑的实体方向与玩家方向相同

复制了玩家的偏航yaw和俯仰pitch
  1. vehicle.setRotation(pLoc.yaw, pLoc.pitch)
复制代码

为计算运动矢量做准备,需要获取前进方向、横向方向
获取前进方向,这一点很容易,得到玩家的方向即可
  1. val dir = pLoc.direction
复制代码

那么怎么获取横向方向呢?答案是向量积,在API中Vector提供了crossProduct方法
直立的玩家代表了一个向量,这个向量总是垂直于平面,该向量的特征为[0, ±1, 0]


根据图中方法,将得到一个指向右侧的横向向量
  1. val sideways = dir.clone().crossProduct(Vector(0, -1, 0))
复制代码

有了前进方向和横向方向后,可以进行矢量计算了前进方向乘积前进速度并对横向方向乘积横向速度
  1. val all = dir.multiply(adSpeed).add(sideways.multiply(swSpeed))
复制代码

然后设置被乘骑的实体的速度
  1. vehicle.velocity = vehicle.velocity.add(all)
复制代码

测试以上代码后会发现这些问题
速度过快
可以对前进方向和横向方向进行除法运算,适当降低速度
  1. adSpeed/10
  2. swSpeed/5
复制代码

如何跳跃
对变量all设置向上y坐标,首先判断被乘骑的实体是否在地面,否则给予0.0
  1. all.y = (if (jumping && vehicle.isOnGround) 0.5 else 0.0)
复制代码

为了减缓在空中降落速度,适当调整一下

  1. if (!vehicle.isOnGround) all.multiply(0.4)
复制代码



ProtocolLib

ProtocolLib根据文档中,ProtocolLib相关监听类似于此
  1. ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(<main instance>, PacketType.Play.Client.STEER_VEHICLE){

  2.     @Override
  3.     public void onPacketReceiving(PacketEvent event) {
  4.        // TODO
  5.     }

  6. });
复制代码

剩下的方法相对于TabooLib基本差不多
不过读取字段不一样
第一个float:0
第二个float:1
第一个boolean:0
前进速度 横向速度 跳跃
010







2302728048
楼主有taboolib下载地址吗

GinirohikoCha
1.12.2的vehicle没有setRotation方法,坐骑不会跟着转向,这个有办法解决吗?

狡诈师
GinirohikoCha 发表于 2023-3-25 14:54
1.12.2的vehicle没有setRotation方法,坐骑不会跟着转向,这个有办法解决吗?

发包旋转实体