mirror of
https://github.com/Artillex-Studios/AxMinions.git
synced 2025-01-08 19:07:41 +01:00
Major optimisations to minion ticking
This commit is contained in:
parent
24f5e29381
commit
00090ce56e
@ -93,4 +93,8 @@ interface Minion : InventoryHolder {
|
||||
fun getChestLocationId(): Int
|
||||
|
||||
fun removeOpenInventory(inventory: Inventory)
|
||||
|
||||
fun isTicking(): Boolean
|
||||
|
||||
fun setTicking(ticking: Boolean)
|
||||
}
|
@ -25,16 +25,20 @@ abstract class MinionType(private val name: String, private val defaults: InputS
|
||||
return this.name
|
||||
}
|
||||
|
||||
open fun onToolDirty(minion: Minion) {
|
||||
|
||||
}
|
||||
|
||||
open fun shouldRun(minion: Minion): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun isChunkLoaded(location: Location): Boolean {
|
||||
return location.world?.isChunkLoaded(location.blockX shr 4, location.blockZ shr 4) ?: return false
|
||||
fun isTicking(minion: Minion): Boolean {
|
||||
return minion.isTicking()
|
||||
}
|
||||
|
||||
fun tick(minion: Minion) {
|
||||
if (!isChunkLoaded(minion.getLocation())) return
|
||||
if (!minion.isTicking()) return
|
||||
if (!shouldRun(minion)) return
|
||||
|
||||
run(minion)
|
||||
|
@ -0,0 +1,8 @@
|
||||
package com.artillexstudios.axminions.api.minions.utils
|
||||
|
||||
data class ChunkPos(var x: Int, var z: Int) {
|
||||
|
||||
fun clone(): ChunkPos {
|
||||
return ChunkPos(x, z)
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ import com.artillexstudios.axminions.api.minions.miniontype.MinionType
|
||||
import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes
|
||||
import com.artillexstudios.axminions.commands.AxMinionsCommand
|
||||
import com.artillexstudios.axminions.data.H2DataHandler
|
||||
import com.artillexstudios.axminions.listeners.ChunkListener
|
||||
import com.artillexstudios.axminions.listeners.LinkingListener
|
||||
import com.artillexstudios.axminions.listeners.MinionInventoryListener
|
||||
import com.artillexstudios.axminions.listeners.MinionPlaceListener
|
||||
@ -80,6 +81,7 @@ class AxMinionsPlugin : AxPlugin() {
|
||||
Bukkit.getPluginManager().registerEvents(MinionPlaceListener(), this)
|
||||
Bukkit.getPluginManager().registerEvents(LinkingListener(), this)
|
||||
Bukkit.getPluginManager().registerEvents(MinionInventoryListener(), this)
|
||||
Bukkit.getPluginManager().registerEvents(ChunkListener(), this)
|
||||
|
||||
MinionTicker.startTicking()
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ class AxMinionsCommand {
|
||||
val total = minions.size
|
||||
|
||||
minions.fastFor {
|
||||
if (it.getType().isChunkLoaded(it.getLocation())) {
|
||||
if (it.getType().isTicking(it)) {
|
||||
loaded++
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.artillexstudios.axminions.listeners
|
||||
|
||||
import com.artillexstudios.axminions.minions.Minions
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.world.ChunkLoadEvent
|
||||
import org.bukkit.event.world.ChunkUnloadEvent
|
||||
|
||||
class ChunkListener : Listener {
|
||||
|
||||
@EventHandler
|
||||
fun onChunkLoadEvent(event: ChunkLoadEvent) {
|
||||
Minions.addTicking(event.chunk)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onChunkUnloadEvent(event: ChunkUnloadEvent) {
|
||||
Minions.removeTicking(event.chunk)
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ class MinionPlaceListener : Listener {
|
||||
}
|
||||
|
||||
val minion = Minion(location, event.player.uniqueId, event.player, minionType, 1, ItemStack(Material.AIR), null, Direction.NORTH, 0, 0.0, AxMinionsPlugin.dataHandler.getLocationID(location), 0)
|
||||
minion.setTicking(true)
|
||||
AxMinionsPlugin.dataHandler.saveMinion(minion)
|
||||
|
||||
event.player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.PLACE_SUCCESS(), Placeholder.unparsed("type", minionType.getName()), Placeholder.unparsed("placed", (placed + 1).toString()), Placeholder.unparsed("max", (maxMinions).toString())))
|
||||
|
@ -25,14 +25,12 @@ import com.artillexstudios.axminions.utils.fastFor
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.block.Container
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import org.bukkit.entity.EntityType
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.Inventory
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.util.EulerAngle
|
||||
import java.util.UUID
|
||||
import kotlin.math.roundToInt
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
@ -52,8 +50,8 @@ class Minion(
|
||||
private var chestLocationId: Int
|
||||
) : Minion {
|
||||
private lateinit var entity: PacketArmorStand
|
||||
private var nextAction = 0
|
||||
private var range = 0.0
|
||||
internal var nextAction = 0
|
||||
internal var range = 0.0
|
||||
private var dirty = true
|
||||
private var armTick = 2.0
|
||||
private var warning: Warning? = null
|
||||
@ -61,6 +59,8 @@ class Minion(
|
||||
private val extraData = hashMapOf<String, String>()
|
||||
private var linkedInventory: Inventory? = null
|
||||
private val openInventories = mutableListOf<Inventory>()
|
||||
@Volatile
|
||||
private var ticking = false
|
||||
|
||||
init {
|
||||
spawn()
|
||||
@ -95,9 +95,7 @@ class Minion(
|
||||
override fun tick() {
|
||||
if (dirty) {
|
||||
dirty = false
|
||||
range = type.getDouble("range", level)
|
||||
val efficiency = 1.0 - (getTool()?.getEnchantmentLevel(Enchantment.DIG_SPEED)?.div(10.0) ?: 0.1)
|
||||
nextAction = (type.getLong("speed", level) * efficiency).roundToInt()
|
||||
type.onToolDirty(this)
|
||||
}
|
||||
|
||||
type.tick(this)
|
||||
@ -342,6 +340,14 @@ class Minion(
|
||||
openInventories.remove(inventory)
|
||||
}
|
||||
|
||||
override fun isTicking(): Boolean {
|
||||
return ticking
|
||||
}
|
||||
|
||||
override fun setTicking(ticking: Boolean) {
|
||||
this.ticking = ticking
|
||||
}
|
||||
|
||||
override fun getInventory(): Inventory {
|
||||
return Bukkit.createInventory(this, 9)
|
||||
}
|
||||
|
@ -7,9 +7,12 @@ object MinionTicker {
|
||||
private var tick = 0L
|
||||
|
||||
private inline fun tickAll() {
|
||||
Minions.getMinions().fastFor { minion ->
|
||||
minion.tick()
|
||||
Minions.get().values.forEach { list ->
|
||||
list.fastFor {
|
||||
it.tick()
|
||||
}
|
||||
}
|
||||
|
||||
tick++
|
||||
}
|
||||
|
||||
|
@ -1,21 +1,81 @@
|
||||
package com.artillexstudios.axminions.minions
|
||||
|
||||
import com.artillexstudios.axminions.api.minions.Minion
|
||||
import com.artillexstudios.axminions.api.minions.utils.ChunkPos
|
||||
import com.artillexstudios.axminions.utils.fastFor
|
||||
import java.util.Collections
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import org.bukkit.Chunk
|
||||
|
||||
object Minions {
|
||||
private val entities = ConcurrentLinkedQueue<Minion>()
|
||||
private val mutex = Object()
|
||||
private val minions = hashMapOf<ChunkPos, ArrayList<Minion>>()
|
||||
private val mutableChunkPos = ChunkPos(0, 0)
|
||||
|
||||
fun addTicking(chunk: Chunk) {
|
||||
synchronized(mutex) {
|
||||
mutableChunkPos.x = chunk.x
|
||||
mutableChunkPos.z = chunk.z
|
||||
|
||||
minions[mutableChunkPos]?.fastFor {
|
||||
it.setTicking(true)
|
||||
} ?: return
|
||||
}
|
||||
}
|
||||
|
||||
fun removeTicking(chunk: Chunk) {
|
||||
synchronized(mutex) {
|
||||
mutableChunkPos.x = chunk.x
|
||||
mutableChunkPos.z = chunk.z
|
||||
|
||||
val minions = this.minions[mutableChunkPos] ?: return
|
||||
|
||||
minions.fastFor {
|
||||
it.setTicking(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun load(minion: Minion) {
|
||||
entities.add(minion)
|
||||
synchronized(mutex) {
|
||||
mutableChunkPos.x = round(minion.getLocation().x) shr 4
|
||||
mutableChunkPos.z = round(minion.getLocation().z) shr 4
|
||||
val pos = minions[mutableChunkPos] ?: arrayListOf()
|
||||
|
||||
pos.add(minion)
|
||||
minions[mutableChunkPos] = pos
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(minion: Minion) {
|
||||
entities.remove(minion)
|
||||
synchronized(mutex) {
|
||||
mutableChunkPos.x = minion.getLocation().blockX shr 4
|
||||
mutableChunkPos.z = minion.getLocation().blockZ shr 4
|
||||
val pos = minions[mutableChunkPos] ?: return
|
||||
|
||||
pos.remove(minion)
|
||||
if (pos.isEmpty()) {
|
||||
minions.remove(mutableChunkPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMinions(): List<Minion> {
|
||||
return Collections.unmodifiableList(entities.toList())
|
||||
synchronized(mutex) {
|
||||
val list = mutableListOf<Minion>()
|
||||
minions.forEach { (_, value) ->
|
||||
list.addAll(value)
|
||||
}
|
||||
return Collections.unmodifiableList(list)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun get(): HashMap<ChunkPos, ArrayList<Minion>> {
|
||||
synchronized(mutex) {
|
||||
return minions
|
||||
}
|
||||
}
|
||||
|
||||
private infix fun round(double: Double): Int {
|
||||
return (double + 0.5).toInt()
|
||||
}
|
||||
}
|
@ -5,7 +5,9 @@ import com.artillexstudios.axminions.api.minions.Minion
|
||||
import com.artillexstudios.axminions.api.minions.miniontype.MinionType
|
||||
import com.artillexstudios.axminions.api.warnings.Warnings
|
||||
import com.artillexstudios.axminions.minions.MinionTicker
|
||||
import kotlin.math.roundToInt
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import org.bukkit.entity.Item
|
||||
|
||||
class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.getResource("minions/collector.yml")!!) {
|
||||
@ -14,6 +16,13 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
|
||||
return MinionTicker.getTick() % minion.getNextAction() == 0L
|
||||
}
|
||||
|
||||
override fun onToolDirty(minion: Minion) {
|
||||
val minionImpl = minion as com.artillexstudios.axminions.minions.Minion
|
||||
minionImpl.range = getDouble("range", minion.getLevel())
|
||||
val efficiency = 1.0 - (minion.getTool()?.getEnchantmentLevel(Enchantment.DIG_SPEED)?.div(10.0) ?: 0.1)
|
||||
minionImpl.nextAction = (getLong("speed", minion.getLevel()) * efficiency).roundToInt()
|
||||
}
|
||||
|
||||
override fun run(minion: Minion) {
|
||||
minion.resetAnimation()
|
||||
if (minion.getLinkedChest() == null) {
|
||||
@ -22,7 +31,7 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
|
||||
}
|
||||
|
||||
val type = minion.getLinkedChest()!!.block.type
|
||||
if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL && !type.name.lowercase().contains("shulker_box")) {
|
||||
if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) {
|
||||
Warnings.NO_CONTAINER.display(minion)
|
||||
minion.setLinkedChest(null)
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user