UID505714性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2022-7-19最后登录1970-1-1
| 本帖最后由 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[type=item] run ... 但是目前我没有任何方法直接获得这个物品,那不妨将上述的指令变形? execute as @a at @s run execute as @e[type=item,distance=..100] 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确定实体是物品实体,并且信息是在服务端的,进一步执行接下来我要的内容。 这也便是我最后的解决方案
|
|