【问题标题】:How to modify an event through a Runnable如何通过 Runnable 修改事件
【发布时间】:2014-11-21 00:07:29
【问题描述】:

我有一个可触发事件的可运行文件。我正在尝试从事件中获取列表并将其清除,但将列表放在事件期间创建的实体中的元数据存储中。到目前为止,我已经尝试过:

注意:这个类实现并且是一个事件监听器。

@EventHandler
public synchronized void playerDeathEvent(final EntityDeathEvent event) {

    Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
        public void run() {
            Entity p = event.getEntity();
            // Spawn the Firework, get the FireworkMeta.
            Firework fw = (Firework) p.getWorld().spawnEntity(p.getLocation(), EntityType.FIREWORK);
            FireworkMeta fwm = fw.getFireworkMeta();

            // Our random generator
            Random r = new Random();   

            // Get the type
            int rt = r.nextInt(4) + 1;
            Type type = Type.BALL;       
            if (rt == 1) type = Type.BALL;
            if (rt == 2) type = Type.BALL_LARGE;
            if (rt == 3) type = Type.BURST;
            if (rt == 4) type = Type.CREEPER;
            if (rt == 5) type = Type.STAR;

            //Get our random colors   
            int r1i = r.nextInt(15) + 1;
            int r2i = r.nextInt(15) + 1;
            Color c1 = getColor(r1i);
            Color c2 = getColor(r2i);

            // Create our effect with this
            FireworkEffect effect = FireworkEffect.builder().flicker(r.nextBoolean()).withColor(c1).withFade(c2).with(type).trail(r.nextBoolean()).build();

            // Then apply the effect to the meta
            fwm.addEffect(effect);

            // Generate some random power and set it
            int rp = r.nextInt(2) + 1;
            fwm.setPower(rp);

            // Then apply this to our rocket
            fw.setFireworkMeta(fwm);  
            // Clear drops and set the drops to be released on explosion

            //TODO: fix problem where list is cleared before put into Metadata
            List<ItemStack> list = new ArrayList<ItemStack>();
            for (ItemStack stack : event.getDrops())
                list.add(stack);
            fw.setMetadata("dropItems", new FixedMetadataValue(GLDPlugin, list));
            event.getDrops().clear();
            forceDelete(event);
        }
    });

}

public void forceDelete(EntityDeathEvent event) {
    for (int i = 0; i < event.getDrops().size(); i++)
        event.getDrops().remove(i);
}

并且(只是最后一部分):

            @EventHandler
            public synchronized void onEntityDeath(EntityDeathEvent evt)
            final EntityDeathEvent event = evt;

            //No code in this section was changed from the code above.

            //TODO: fix problem where list is cleared before put into Metadata
            List<ItemStack> list = new ArrayList<ItemStack>();
            for (ItemStack stack : event.getDrops())
                list.add(stack);
            fw.setMetadata("dropItems", new FixedMetadataValue(GLDPlugin, list));

        }
    });
    evt = event;
    evt.getDrops().clear();
    forceDelete(evt);
}

在顶部,它不会清除 event.getDrops() 并将 list 放入实体的元数据中,复制 event.getDrops()。在下面的示例中,它将清除event.getDrops(),但不会将list 放入实体的元数据中,从而消除event.getDrops()。这两种输出都是不可接受的,因为这会导致没有物品或双重物品被生成。有什么想法吗?

编辑:为那些更精通 bukkit 的人提供更好的解释:

我正在努力让玩家在死亡时不会掉落物品,但它们仍会从他们的库存中移除。我还需要它,以便将 List&lt;ItemStack&gt; 放入生成的烟花的元数据中。

【问题讨论】:

  • event.getDrops() 可能会向您传递List 的副本
  • @MadProgrammer 这就是当EntityDeathEvent 是最终的时候它正在做的事情,但是当它不是我可以清除它时。我知道 final 使它保持不变,但我需要解决它。

标签: java runnable bukkit


【解决方案1】:

你来电:

Firework.setMetadata(String, MetadataValue);

这本质上是Metadatable.setMetadata() 方法。这是此方法的文档:

/**
 * Sets a metadata value in the implementing object's metadata store.
 *
 * @param metadataKey A unique key to identify this metadata.
 * @param newMetadataValue The metadata value to apply.
 * @throws IllegalArgumentException If value is null, or the owning plugin
 *     is null
 */
public void setMetadata(String metadataKey, MetadataValue newMetadataValue);

因此,不能保证在设置项目的"dropItems" 元数据后,任何事情都会发生。您必须实现一个监听器来检查烟花何时被销毁,如果烟花包含此元数据,则删除这些项目。 MetadataValue 不是 NBT 值。

要修改 NBT 值,您必须通过反射直接从 CraftBukkit 中检索,如下所示:

Firework fw = (Firework) p.getWorld().spawnEntity(p.getLocation(), EntityType.FIREWORK);
java.lang.reflect.Field _entity_ = CraftEntity.class.getField("entity");
_entity_.setAccessible(true);
net.minecraft.server.Entity entity = _entity_.get(fw);
// et cetera

简而言之:不要。编写一个自定义事件处理程序来检查烟花爆炸时的元数据值,并采取相应的行动。

【讨论】:

  • 我想你误解了我的问题。我不认为简单地将元数据命名为dropItems 会使其产生项目。我确实有一个监听器(使用protocollib,因为没有实现烟花爆炸),并且在与我的测试命令一起使用时效果很好,它基本上做同样的事情,但不必清除列表。我的问题是我可以清除列表而不产生任何东西,或者不清除列表并且无法制作此插件。不过感谢您的回复!
  • @itrollin98 我想我不明白你想在这里表达什么。
  • 我正在努力使实体在死亡时不会掉落物品,但烟花有一个包含掉落列表的元数据值。
猜你喜欢
  • 2015-08-10
  • 1970-01-01
  • 2011-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-19
  • 2018-06-25
  • 1970-01-01
相关资源
最近更新 更多