Wu_tian 发表于 2022-7-19 14:31:28

【1.19Modding】如何利用事件系统检测玩家附近的所有物品

本帖最后由 Wu_tian 于 2022-7-19 14:49 编辑

Hello,我是Wu_tian,最近在尝试制作某个特定物品经过一定时间被腐蚀的功能。其中被一个功能卡壳了很久,也就是获取世界上的物品实体并且给他们修改数值。因此我打算把我此次的经验分享给大家
“在我的世界模组开发的过程中,时常要体验戴着脚镣跳舞的感觉”
一开始我在研究模组时,是因为指令的某些局限性限制了一些想法的发挥(更多体现在计算和穷举上面)。所以一开始我是从事件系统下手,看卡能不能找到“每一刻的实体”的事件,从EntityEvent下手找了半天,发现根本没有,做多也只找到了两个跟ItemEntity有关的事件:(其中第一个是ItemTossEvent,是当物品被玩家抛出时触发事件,第二个是ItemExpireEvent,顾名思义,也就是物品消失时触发的事件)
结果我愣是硬着头皮用ItemTossEvent来尝试获取物品

因为这个事件只会在被丢出来的时候触发一次,所以我要时刻获取这个物品,就必须手动循环,于是我用了while循环。
@SubscribeEvent
public static void ItemOnCorroding(ItemTossEvent event){    while(event.getEntity().isAlive())    {      ....    }}结果也毫不意外,我只要一丢出物品直接卡壳。
于是我想了另一种方法,也许开个多线程可以解决?
@SubscribeEvent
public static void ItemOnCorroding(ItemTossEvent event){   Thread thread = new Thread(new Runnable() {    @Override
    public void run() {
            while(event.getEntity().isAlive())            {            ....            }      
      }
})thread.start();}

这个方法也许可行,但是在实践后却仍然发现一些小问题,比如物品必须是丢出去的才会被检测到。还有就是这个isAlive()似乎有些问题,即使物品被捡了,甚至退出了这个世界,这个isAlive()的条件仍是true
正当我快绝望时,我突然想起了以前玩指令时的思路,如果我用指令来检测的话,那一定是用execute指令。
execute as @e run ...
但是目前我没有任何方法直接获得这个物品,那不妨将上述的指令变形?
execute as @a at @s run execute as @e run ...
通过这种方式,我们可以先找到玩家,再获取玩家附近所有的物品,就这样,我受到了启发,因为这个游戏确实是有“每Tick的玩家”的事件的。
于是我写了以下代码
@SubscribeEvent
public static void ItemOnCorroding(TickEvent.PlayerTickEvent event)
{
    Logger logger = LogUtils.getLogger();
    //nearby -100 - +100 itemEntity Corroding
    entities= event.player.getLevel().getEntities(null,new AABB(event.player.getBlockX()-100,event.player.getBlockY()-100,event.player.getBlockZ()-100,event.player.getBlockX()+100,event.player.getBlockY()+100,event.player.getBlockZ()+100));
    entities.forEach((entity ->
    {
      if(entity instanceof ItemEntity && ! entity.getLevel().isClientSide())      {         ...      }
    }));
    //Replace Player Item
}
这里,我们先通过玩家每tick的事件时时获取一个玩家的信息,然后通过玩家我们可以获取这个世界和这个世界的实体。
但是获取实体需要一个必要条件,即一定的范围(AABB就是用来确定范围的,AABB具体就是如fill指令中2个对角的坐标所框出来的矩形范围)
我将玩家附近的范围框出来后,再通过instanceof确定实体是物品实体,并且信息是在服务端的,进一步执行接下来我要的内容。
这也便是我最后的解决方案

页: [1]
查看完整版本: 【1.19Modding】如何利用事件系统检测玩家附近的所有物品