如何通过Runnable修改事件

时间:2014-11-21 00:07:29

标签: java runnable bukkit

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

注意:这个类在implements中,并且是一个事件监听器。

@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<ItemStack>被放入生成的烟花元数据中。

1 个答案:

答案 0 :(得分:2)

你在打电话:

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

简而言之:不要。编写自定义事件处理程序以在fireworks爆炸时检查元数据值,并相应地对其进行操作。