Hi, I made a plugin that drops heads as one of its features, but apparently the part of "adding the skin to the head" has terrible performance for something surprisingly simple. It's just get the item meta, set the skull owner and put it back. (and put it into the drops list)
I made the report on the fly on my local pc (windows), so it's very likely that it affected the results.
I made this code as an alternative, and while it gets good performance, it kinda looks horrible creating an async task and a sync one inside for each player death. Not sure if someone has a better tip for this, or if I it will be negligeable once on linux (I won't be able to test this on linux for a couple of days).
private fun handleHeadDrops(event: PlayerDeathEvent) { if (Random.nextDouble() > RootConfig.HEAD.CHANCE) return val location = event.player.location val world = event.player.world Bukkit.getScheduler().runTaskAsynchronously(this.plugin) { _ -> val head = ItemStack(Material.PLAYER_HEAD) val meta = (head.itemMeta as SkullMeta).apply { owningPlayer = event.player } head.itemMeta = meta Bukkit.getScheduler().runTask(this.plugin) { _ -> val item = world.dropItem(location, head) } } }
private fun handleHeadDrops(event: PlayerDeathEvent) { if (Random.nextDouble() > RootConfig.HEAD.CHANCE) return val location = event.player.location val world = event.player.world Bukkit.getScheduler().runTaskAsynchronously(this.plugin) { _ -> val head = ItemStack(Material.PLAYER_HEAD) val meta = (head.itemMeta as SkullMeta).apply { owningPlayer = event.player } head.itemMeta = meta Bukkit.getScheduler().runTask(this.plugin) { _ -> val item = world.dropItem(location, head) } } }
This probably will sound silly, but I also don't know how the bukkit scheduler works internally, so idk if it's literally a scheduler, with a separate single thread to run scheduled tasks, or if it creates a different new thread everytime something is scheduled.
spark is a performance profiler for Minecraft clients, servers, and proxies.
Solution
I really like to use coroutines, like this
private fun handleHeadDrops_old(event: PlayerDeathEvent) { CoroutineScope(ioDispatcher).launch { val head = ItemStack(Material.PLAYER_HEAD) val meta = (head.itemMeta as SkullMeta).apply { owningPlayer = event.player } head.itemMeta = meta withContext(bukkitDispatcher) { event.drops.add(head) } }}
private fun handleHeadDrops_old(event: PlayerDeathEvent) { CoroutineScope(ioDispatcher).launch { val head = ItemStack(Material.PLAYER_HEAD) val meta = (head.itemMeta as SkullMeta).apply { owningPlayer = event.player } head.itemMeta = meta withContext(bukkitDispatcher) { event.drops.add(head) } }}