Something is really broken with the minions

This commit is contained in:
TomTom 2023-10-14 21:07:11 +02:00
parent 8b83c4867f
commit f34b153da2
43 changed files with 1190 additions and 142 deletions

View File

@ -38,6 +38,8 @@ class Config(file: File, stream: InputStream) {
fun PRICES_HOOK() = AxMinionsAPI.INSTANCE.getConfig().get("hooks.prices", "ShopGUIPlus") fun PRICES_HOOK() = AxMinionsAPI.INSTANCE.getConfig().get("hooks.prices", "ShopGUIPlus")
@JvmStatic @JvmStatic
fun GUI_SIZE() = AxMinionsAPI.INSTANCE.getConfig().get<Int>("gui.size") fun GUI_SIZE() = AxMinionsAPI.INSTANCE.getConfig().get<Int>("gui.size")
@JvmStatic
fun DEBUG() = AxMinionsAPI.INSTANCE.getConfig().get<Boolean>("debug")
} }
private val config = Config( private val config = Config(

View File

@ -1,8 +1,10 @@
package com.artillexstudios.axminions.api.minions package com.artillexstudios.axminions.api.minions
enum class Direction(val yaw: Float) { import org.bukkit.block.BlockFace
NORTH(180f),
WEST(90f), enum class Direction(val yaw: Float, val facing: BlockFace) {
SOUTH(0f), NORTH(180f, BlockFace.NORTH),
EAST(-90f); WEST(90f, BlockFace.WEST),
SOUTH(0f, BlockFace.SOUTH),
EAST(-90f, BlockFace.EAST);
} }

View File

@ -103,4 +103,10 @@ interface Minion : InventoryHolder {
fun setRange(range: Double) fun setRange(range: Double)
fun setNextAction(nextAction: Int) fun setNextAction(nextAction: Int)
fun markDirty()
fun damageTool(amount: Int = 1)
fun canUseTool(): Boolean
} }

View File

@ -6,6 +6,7 @@ import com.artillexstudios.axapi.libs.kyori.adventure.text.minimessage.tag.resol
import com.artillexstudios.axapi.utils.ItemBuilder import com.artillexstudios.axapi.utils.ItemBuilder
import com.artillexstudios.axminions.api.AxMinionsAPI import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.utils.Keys
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
@ -41,13 +42,14 @@ abstract class MinionType(private val name: String, private val defaults: InputS
if (!minion.isTicking()) return if (!minion.isTicking()) return
if (!shouldRun(minion)) return if (!shouldRun(minion)) return
minion.resetAnimation()
run(minion) run(minion)
} }
fun getItem(level: Int = 1): ItemStack { fun getItem(level: Int = 1, actions: Long = 0): ItemStack {
val builder = ItemBuilder(config.getSection("item"), Placeholder.unparsed("level", level.toString()), Placeholder.unparsed("actions", "0")) val builder = ItemBuilder(config.getSection("item"), Placeholder.unparsed("level", level.toString()), Placeholder.unparsed("actions", actions.toString()))
builder.storePersistentData(MinionTypes.getMinionKey(), PersistentDataType.STRING, name) builder.storePersistentData(Keys.MINION_TYPE, PersistentDataType.STRING, name)
builder.storePersistentData(MinionTypes.getLevelKey(), PersistentDataType.INTEGER, level) builder.storePersistentData(Keys.LEVEL, PersistentDataType.INTEGER, level)
return builder.clonedGet() return builder.clonedGet()
} }

View File

@ -7,9 +7,7 @@ import java.util.Collections
object MinionTypes { object MinionTypes {
private val TYPES = hashMapOf<String, MinionType>() private val TYPES = hashMapOf<String, MinionType>()
private val MINION_KEY = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "minion_type")
private val LEVEL_KEY = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "level")
private val GUI_KEY = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "gui_item")
@JvmStatic @JvmStatic
fun register(type: MinionType): MinionType { fun register(type: MinionType): MinionType {
@ -32,21 +30,6 @@ object MinionTypes {
return TYPES[name] return TYPES[name]
} }
@JvmStatic
fun getMinionKey(): NamespacedKey {
return MINION_KEY
}
@JvmStatic
fun getLevelKey(): NamespacedKey {
return LEVEL_KEY
}
@JvmStatic
fun getGuiKey(): NamespacedKey {
return GUI_KEY
}
@JvmStatic @JvmStatic
fun getMinionTypes(): Map<String, MinionType> { fun getMinionTypes(): Map<String, MinionType> {
return Collections.unmodifiableMap(TYPES) return Collections.unmodifiableMap(TYPES)

View File

@ -1,4 +1,4 @@
package com.artillexstudios.axminions.utils package com.artillexstudios.axminions.api.utils
inline fun <T> Array<T>.fastFor(action: (T) -> Unit) { inline fun <T> Array<T>.fastFor(action: (T) -> Unit) {
val indices = indices val indices = indices

View File

@ -0,0 +1,36 @@
package com.artillexstudios.axminions.api.utils
class CoolDown<T> : HashMap<T, Long>() {
fun add(value: T, time: Long) {
expire()
put(value, System.currentTimeMillis() + time)
}
override fun containsKey(key: T): Boolean {
expire()
return super.containsKey(key)
}
fun contains(value: T): Boolean {
return containsKey(value)
}
override fun remove(key: T): Long? {
expire()
return super.remove(key)
}
private fun expire() {
val currentTime = System.currentTimeMillis()
val iterator = iterator()
while (iterator.hasNext()) {
val next = iterator.next()
if (next.value <= currentTime) {
iterator.remove()
}
}
}
}

View File

@ -0,0 +1,15 @@
package com.artillexstudios.axminions.api.utils
import com.artillexstudios.axminions.api.AxMinionsAPI
import org.bukkit.NamespacedKey
object Keys {
@JvmField
val MINION_TYPE = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "minion_type")
@JvmField
val LEVEL = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "level")
@JvmField
val GUI = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "gui_item")
@JvmField
val STATISTICS = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "statistics")
}

View File

@ -1,6 +1,9 @@
package com.artillexstudios.axminions.utils package com.artillexstudios.axminions.api.utils
import kotlin.math.roundToInt
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.block.BlockFace
object LocationUtils { object LocationUtils {
@JvmStatic @JvmStatic
@ -34,4 +37,17 @@ object LocationUtils {
return blocks return blocks
} }
fun getAllBlocksFacing(location: Location, radius: Double, face: BlockFace): ArrayList<Location> {
val blocks = ArrayList<Location>(radius.toInt())
val modX = face.modX
val modZ = face.modZ
for (i in 1..radius.roundToInt()) {
blocks.add(location.clone().add(i * modX.toDouble(), 0.0, i * modZ.toDouble()))
}
return blocks
}
} }

View File

@ -0,0 +1,91 @@
package com.artillexstudios.axminions.api.utils
import java.util.LinkedList
import java.util.Queue
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.block.Block
import org.bukkit.block.BlockFace
object MinionUtils {
private val FACES =
arrayOf(BlockFace.DOWN, BlockFace.UP, BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST)
@JvmStatic
fun getPlant(block: Block): ArrayList<Block> {
val blocks = arrayListOf<Block>()
var loc = block.location.clone()
for (i in block.y downTo -65) {
loc.add(0.0, -1.0, 0.0)
val locBlock = loc.block
if (!(locBlock.type == block.type && locBlock.getRelative(BlockFace.DOWN) == block)) break
blocks.add(locBlock)
}
loc = block.location.clone()
for (i in block.y..328) {
loc.add(0.0, 1.0, 0.0)
val locBlock = loc.block
if (locBlock.type != block.type) break
blocks.add(locBlock)
}
return blocks
}
@JvmStatic
fun isStoneGenerator(location: Location): Boolean {
var lava = false
var water = false
FACES.fastFor {
val relative = location.block.getRelative(it)
val type = relative.type
if (!lava) {
lava = type == Material.LAVA
}
if (!water) {
water = type == Material.WATER
}
if (water && lava) {
return true
}
}
return false
}
@JvmStatic
fun getTree(startBlock: Block): List<Block> {
val queue: Queue<Block> = LinkedList()
val visited = mutableSetOf<Block>()
val tree = mutableListOf<Block>()
queue.add(startBlock)
while (queue.isNotEmpty()) {
val block = queue.poll()
val type = block.type.toString()
if (type.endsWith("_WOOD") || type.endsWith("_LOG")) {
tree.add(block)
FACES.fastFor {
val relative = block.getRelative(it)
if (!visited.contains(relative)) {
queue.add(relative)
visited.add(relative)
}
}
}
}
return tree
}
}

View File

@ -1,4 +1,4 @@
package com.artillexstudios.axminions.utils package com.artillexstudios.axminions.api.utils
// Thanks a lot to this hero! https://stackoverflow.com/a/44332139 // Thanks a lot to this hero! https://stackoverflow.com/a/44332139
infix fun ClosedRange<Double>.step(step: Double): Iterable<Double> { infix fun ClosedRange<Double>.step(step: Double): Iterable<Double> {

View File

@ -15,7 +15,7 @@ abstract class Warning(private val name: String) {
fun display(minion: Minion) { fun display(minion: Minion) {
if (minion.getWarning() == null) { if (minion.getWarning() == null) {
val hologram = HologramFactory.get() val hologram = HologramFactory.get()
.spawnHologram(minion.getLocation().clone().add(0.0, 1.15, 0.0), minion.getLocation().toString()) .spawnHologram(minion.getLocation().clone().add(0.0, 1.35, 0.0), minion.getLocation().toString())
hologram.addLine(getContent()) hologram.addLine(getContent())
minion.setWarning(this) minion.setWarning(this)
minion.setWarningHologram(hologram) minion.setWarningHologram(hologram)

View File

@ -61,6 +61,30 @@ allprojects {
maven { maven {
url = uri('https://repo.alessiodp.com/releases/') url = uri('https://repo.alessiodp.com/releases/')
} }
maven {
url = uri('https://repo.rosewooddev.io/repository/public/')
}
maven {
url = uri('https://repo.bg-software.com/repository/api/')
}
maven {
url = uri('https://repo.essentialsx.net/releases/')
}
maven {
url = uri('https://maven.enginehub.org/repo/')
}
maven {
url = uri('https://repo.codemc.org/repository/maven-snapshots')
}
maven {
url = uri('https://repo.codemc.org/repository/maven-public/')
}
} }
dependencies { dependencies {
@ -71,6 +95,20 @@ allprojects {
compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0' compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0'
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0' compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0'
compileOnly 'com.h2database:h2:2.2.220' compileOnly 'com.h2database:h2:2.2.220'
compileOnly 'dev.rosewood:rosestacker:1.5.9'
compileOnly 'com.bgsoftware:WildStackerAPI:2023.2'
compileOnly 'net.essentialsx:EssentialsX:2.19.0'
compileOnly 'com.github.Gypopo:EconomyShopGUI-API:1.6.0'
compileOnly 'com.github.Gypopo:EconomyShopGUI-API:1.6.0'
compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0'
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT'
compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:2023.2'
compileOnly 'world.bentobox:bentobox:1.24.0-SNAPSHOT'
compileOnly 'com.github.TechFortress:GriefPrevention:16.18'
compileOnly 'com.github.angeschossen:LandsAPI:6.29.12'
compileOnly 'com.intellectualsites.plotsquared:plotsquared-core:7.0.0-rc.4'
compileOnly 'com.intellectualsites.plotsquared:plotsquared-bukkit:7.0.0-rc.4'
implementation platform('com.intellectualsites.bom:bom-newest:1.35')
implementation files('../libs/AxAPI-1.0-SNAPSHOT.jar') implementation files('../libs/AxAPI-1.0-SNAPSHOT.jar')
} }

View File

@ -22,6 +22,8 @@ import com.artillexstudios.axminions.listeners.MinionPlaceListener
import com.artillexstudios.axminions.minions.MinionTicker import com.artillexstudios.axminions.minions.MinionTicker
import com.artillexstudios.axminions.minions.miniontype.CollectorMinionType import com.artillexstudios.axminions.minions.miniontype.CollectorMinionType
import com.artillexstudios.axminions.minions.miniontype.FarmerMinionType import com.artillexstudios.axminions.minions.miniontype.FarmerMinionType
import com.artillexstudios.axminions.minions.miniontype.LumberMinionType
import com.artillexstudios.axminions.minions.miniontype.MinerMinionType
import org.bukkit.Bukkit import org.bukkit.Bukkit
import java.io.File import java.io.File
@ -47,12 +49,13 @@ class AxMinionsPlugin : AxPlugin() {
override fun load() { override fun load() {
INSTANCE = this INSTANCE = this
AxMinionsAPI.INSTANCE = AxMinionsAPIImpl(this) AxMinionsAPI.INSTANCE = AxMinionsAPIImpl(this)
integrations = Integrations()
} }
override fun enable() { override fun enable() {
AxMinionsPlugin.config = Config(File(dataFolder, "config.yml"), getResource("config.yml")!!) AxMinionsPlugin.config = Config(File(dataFolder, "config.yml"), getResource("config.yml")!!)
messages = Messages(File(dataFolder, "messages.yml"), getResource("messages.yml")!!) messages = Messages(File(dataFolder, "messages.yml"), getResource("messages.yml")!!)
integrations = Integrations()
integrations.reload()
loadDataHandler() loadDataHandler()
dataQueue = ThreadedQueue("AxMinions-Database-Queue") dataQueue = ThreadedQueue("AxMinions-Database-Queue")
@ -60,6 +63,8 @@ class AxMinionsPlugin : AxPlugin() {
MinionTypes.also { MinionTypes.also {
it.register(CollectorMinionType()) it.register(CollectorMinionType())
it.register(FarmerMinionType()) it.register(FarmerMinionType())
it.register(MinerMinionType())
it.register(LumberMinionType())
} }
val handler = BukkitCommandHandler.create(this) val handler = BukkitCommandHandler.create(this)

View File

@ -14,7 +14,7 @@ import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.config.Messages import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.minions.miniontype.MinionType import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes
import com.artillexstudios.axminions.utils.fastFor import com.artillexstudios.axminions.api.utils.fastFor
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
import org.bukkit.entity.Player import org.bukkit.entity.Player
@ -50,6 +50,10 @@ class AxMinionsCommand {
it.value.getConfig().reload() it.value.getConfig().reload()
} }
AxMinionsAPI.INSTANCE.getMinions().fastFor {
it.markDirty()
}
sender.sendMessage( sender.sendMessage(
StringUtils.formatToString( StringUtils.formatToString(
Messages.PREFIX() + Messages.RELOAD_SUCCESS(), Messages.PREFIX() + Messages.RELOAD_SUCCESS(),

View File

@ -16,6 +16,11 @@ import com.artillexstudios.axminions.integrations.prices.CMIIntegration
import com.artillexstudios.axminions.integrations.prices.EconomyShopGUIIntegration import com.artillexstudios.axminions.integrations.prices.EconomyShopGUIIntegration
import com.artillexstudios.axminions.integrations.prices.EssentialsIntegration import com.artillexstudios.axminions.integrations.prices.EssentialsIntegration
import com.artillexstudios.axminions.integrations.prices.ShopGUIPlusIntegration import com.artillexstudios.axminions.integrations.prices.ShopGUIPlusIntegration
import com.artillexstudios.axminions.integrations.protection.BentoBoxIntegration
import com.artillexstudios.axminions.integrations.protection.GriefPreventionIntegration
import com.artillexstudios.axminions.integrations.protection.LandsIntegration
import com.artillexstudios.axminions.integrations.protection.SuperiorSkyBlock2Integration
import com.artillexstudios.axminions.integrations.protection.WorldGuardIntegration
import com.artillexstudios.axminions.integrations.stacker.DefaultStackerIntegration import com.artillexstudios.axminions.integrations.stacker.DefaultStackerIntegration
import com.artillexstudios.axminions.integrations.stacker.RoseStackerIntegration import com.artillexstudios.axminions.integrations.stacker.RoseStackerIntegration
import com.artillexstudios.axminions.integrations.stacker.WildStackerIntegration import com.artillexstudios.axminions.integrations.stacker.WildStackerIntegration
@ -26,7 +31,7 @@ class Integrations : Integrations {
private lateinit var stackerIntegration: StackerIntegration private lateinit var stackerIntegration: StackerIntegration
private lateinit var pricesIntegration: PricesIntegration private lateinit var pricesIntegration: PricesIntegration
private lateinit var economyIntegration: EconomyIntegration private lateinit var economyIntegration: EconomyIntegration
private lateinit var protectionIntegrations: ProtectionIntegrations private val protectionIntegrations = com.artillexstudios.axminions.integrations.protection.ProtectionIntegrations()
override fun getStackerIntegration(): StackerIntegration { override fun getStackerIntegration(): StackerIntegration {
return stackerIntegration return stackerIntegration
@ -107,7 +112,27 @@ class Integrations : Integrations {
} }
} }
protectionIntegrations.clear()
if (Bukkit.getPluginManager().getPlugin("SuperiorSkyblock2") != null) {
register(SuperiorSkyBlock2Integration())
}
if (Bukkit.getPluginManager().getPlugin("WorldGuard") != null) {
register(WorldGuardIntegration())
}
if (Bukkit.getPluginManager().getPlugin("BentoBox") != null) {
register(BentoBoxIntegration())
}
if (Bukkit.getPluginManager().getPlugin("GriefPrevention") != null) {
register(GriefPreventionIntegration())
}
if (Bukkit.getPluginManager().getPlugin("Lands") != null) {
register(LandsIntegration())
}
} }
override fun register(integration: Integration) { override fun register(integration: Integration) {
@ -117,7 +142,7 @@ class Integrations : Integrations {
} }
is ProtectionIntegration -> { is ProtectionIntegration -> {
// Hook into protection protectionIntegrations.register(integration)
} }
is EconomyIntegration -> { is EconomyIntegration -> {
@ -132,6 +157,7 @@ class Integrations : Integrations {
throw InvalidIntegrationException("There is no builtin integration that the following class extends: ${integration::class.java}") throw InvalidIntegrationException("There is no builtin integration that the following class extends: ${integration::class.java}")
} }
} }
integration.register()
} }
private fun isPluginLoaded(pluginName: String): Boolean { private fun isPluginLoaded(pluginName: String): Boolean {
@ -147,6 +173,14 @@ class Integrations : Integrations {
} }
override fun deregister(integration: Integration) { override fun deregister(integration: Integration) {
TODO("Not yet implemented") when (integration) {
is ProtectionIntegration -> {
protectionIntegrations.deregister(integration)
}
else -> {
throw InvalidIntegrationException("You can only unregister a protection integration!")
}
}
} }
} }

View File

@ -4,6 +4,7 @@ import com.artillexstudios.axminions.api.integrations.types.EconomyIntegration
import org.bukkit.entity.Player import org.bukkit.entity.Player
class PlayerPointsIntegration : EconomyIntegration { class PlayerPointsIntegration : EconomyIntegration {
override fun getBalance(player: Player): Double { override fun getBalance(player: Player): Double {
TODO("Not yet implemented") TODO("Not yet implemented")
} }

View File

@ -1,22 +1,28 @@
package com.artillexstudios.axminions.integrations.economy package com.artillexstudios.axminions.integrations.economy
import com.artillexstudios.axminions.api.integrations.types.EconomyIntegration import com.artillexstudios.axminions.api.integrations.types.EconomyIntegration
import net.milkbowl.vault.economy.Economy
import org.bukkit.Bukkit
import org.bukkit.entity.Player import org.bukkit.entity.Player
class VaultIntegration : EconomyIntegration { class VaultIntegration : EconomyIntegration {
private lateinit var economy: Economy
override fun getBalance(player: Player): Double { override fun getBalance(player: Player): Double {
TODO("Not yet implemented") return economy.getBalance(player)
} }
override fun giveBalance(player: Player, amount: Double) { override fun giveBalance(player: Player, amount: Double) {
TODO("Not yet implemented") economy.depositPlayer(player, amount)
} }
override fun takeBalance(player: Player, amount: Double) { override fun takeBalance(player: Player, amount: Double) {
TODO("Not yet implemented") economy.withdrawPlayer(player, amount)
} }
override fun register() { override fun register() {
TODO("Not yet implemented") val rsp = Bukkit.getServicesManager().getRegistration(Economy::class.java) ?: return
economy = rsp.provider
} }
} }

View File

@ -4,6 +4,7 @@ import com.artillexstudios.axminions.api.integrations.types.PricesIntegration
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class CMIIntegration : PricesIntegration { class CMIIntegration : PricesIntegration {
override fun getPrice(itemStack: ItemStack): Double { override fun getPrice(itemStack: ItemStack): Double {
TODO("Not yet implemented") TODO("Not yet implemented")
} }

View File

@ -1,14 +1,17 @@
package com.artillexstudios.axminions.integrations.prices package com.artillexstudios.axminions.integrations.prices
import com.artillexstudios.axminions.api.integrations.types.PricesIntegration import com.artillexstudios.axminions.api.integrations.types.PricesIntegration
import me.gypopo.economyshopgui.api.EconomyShopGUIHook
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class EconomyShopGUIIntegration : PricesIntegration { class EconomyShopGUIIntegration : PricesIntegration {
override fun getPrice(itemStack: ItemStack): Double { override fun getPrice(itemStack: ItemStack): Double {
TODO("Not yet implemented") val item = EconomyShopGUIHook.getShopItem(itemStack) ?: return 0.0
return EconomyShopGUIHook.getItemSellPrice(item, itemStack) ?: 0.0
} }
override fun register() { override fun register() {
TODO("Not yet implemented")
} }
} }

View File

@ -1,14 +1,18 @@
package com.artillexstudios.axminions.integrations.prices package com.artillexstudios.axminions.integrations.prices
import com.artillexstudios.axminions.api.integrations.types.PricesIntegration import com.artillexstudios.axminions.api.integrations.types.PricesIntegration
import com.earth2me.essentials.IEssentials
import org.bukkit.Bukkit
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class EssentialsIntegration : PricesIntegration { class EssentialsIntegration : PricesIntegration {
private lateinit var manager: IEssentials;
override fun getPrice(itemStack: ItemStack): Double { override fun getPrice(itemStack: ItemStack): Double {
TODO("Not yet implemented") return manager.worth.getPrice(manager, itemStack).toDouble() * itemStack.amount
} }
override fun register() { override fun register() {
TODO("Not yet implemented") manager = Bukkit.getPluginManager().getPlugin("Essentials") as IEssentials
} }
} }

View File

@ -1,15 +1,16 @@
package com.artillexstudios.axminions.integrations.prices package com.artillexstudios.axminions.integrations.prices
import com.artillexstudios.axminions.api.integrations.types.PricesIntegration import com.artillexstudios.axminions.api.integrations.types.PricesIntegration
import net.brcdev.shopgui.ShopGuiPlusApi
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class ShopGUIPlusIntegration : PricesIntegration { class ShopGUIPlusIntegration : PricesIntegration {
override fun getPrice(itemStack: ItemStack): Double { override fun getPrice(itemStack: ItemStack): Double {
TODO("Not yet implemented") return ShopGuiPlusApi.getItemStackPriceSell(itemStack)
} }
override fun register() { override fun register() {
TODO("Not yet implemented")
} }
} }

View File

@ -0,0 +1,21 @@
package com.artillexstudios.axminions.integrations.protection
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration
import org.bukkit.Location
import org.bukkit.entity.Player
import world.bentobox.bentobox.BentoBox
class BentoBoxIntegration : ProtectionIntegration {
override fun canBuildAt(player: Player, location: Location): Boolean {
val island = BentoBox.getInstance().islands.getIslandAt(location)
return island.map {
player.uniqueId in it.memberSet
}.orElse(true)
}
override fun register() {
}
}

View File

@ -0,0 +1,17 @@
package com.artillexstudios.axminions.integrations.protection
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration
import me.ryanhamshire.GriefPrevention.GriefPrevention
import org.bukkit.Location
import org.bukkit.entity.Player
class GriefPreventionIntegration : ProtectionIntegration {
override fun canBuildAt(player: Player, location: Location): Boolean {
return GriefPrevention.instance.allowBuild(player, location) == null
}
override fun register() {
}
}

View File

@ -0,0 +1,22 @@
package com.artillexstudios.axminions.integrations.protection
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration
import me.angeschossen.lands.api.LandsIntegration
import me.angeschossen.lands.api.flags.type.Flags
import org.bukkit.Location
import org.bukkit.entity.Player
class LandsIntegration : ProtectionIntegration {
override fun canBuildAt(player: Player, location: Location): Boolean {
val api = LandsIntegration.of(AxMinionsPlugin.INSTANCE)
val world = api.getWorld(location.world ?: return true) ?: return true
return world.hasRoleFlag(player.uniqueId, location, Flags.BLOCK_PLACE);
}
override fun register() {
}
}

View File

@ -0,0 +1,38 @@
package com.artillexstudios.axminions.integrations.protection
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegrations
import com.artillexstudios.axminions.api.utils.fastFor
import java.util.Collections
import org.bukkit.Location
import org.bukkit.entity.Player
class ProtectionIntegrations : ProtectionIntegrations {
private val integrations = arrayListOf<ProtectionIntegration>()
override fun getProtectionIntegrations(): List<ProtectionIntegration> {
return Collections.unmodifiableList(integrations)
}
override fun canBuildAt(player: Player, location: Location): Boolean {
integrations.fastFor {
if (!it.canBuildAt(player, location)) {
return false
}
}
return true
}
fun clear() {
integrations.clear()
}
fun register(integration: ProtectionIntegration) {
integrations.add(integration)
}
fun deregister(integration: ProtectionIntegration) {
integrations.remove(integration)
}
}

View File

@ -0,0 +1,21 @@
package com.artillexstudios.axminions.integrations.protection
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration
import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI
import org.bukkit.Location
import org.bukkit.entity.Player
class SuperiorSkyBlock2Integration : ProtectionIntegration {
override fun canBuildAt(player: Player, location: Location): Boolean {
val localPlayer = SuperiorSkyblockAPI.getPlayer(player.uniqueId)
val island = SuperiorSkyblockAPI.getIslandAt(location) ?: return true
return island.isMember(localPlayer)
}
override fun register() {
}
}

View File

@ -0,0 +1,30 @@
package com.artillexstudios.axminions.integrations.protection
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration
import com.sk89q.worldedit.bukkit.BukkitAdapter
import com.sk89q.worldguard.WorldGuard
import com.sk89q.worldguard.bukkit.WorldGuardPlugin
import com.sk89q.worldguard.protection.flags.Flags
import org.bukkit.Location
import org.bukkit.entity.Player
class WorldGuardIntegration : ProtectionIntegration {
override fun canBuildAt(player: Player, location: Location): Boolean {
val localPlayer = WorldGuardPlugin.inst().wrapPlayer(player)
val world = BukkitAdapter.adapt(player.world)
if (WorldGuard.getInstance().platform.sessionManager.hasBypass(localPlayer, world)) {
return true
}
val container = WorldGuard.getInstance().platform.regionContainer
val query = container.createQuery()
return query.testState(BukkitAdapter.adapt(location), localPlayer, Flags.BUILD)
}
override fun register() {
}
}

View File

@ -1,25 +1,28 @@
package com.artillexstudios.axminions.integrations.stacker package com.artillexstudios.axminions.integrations.stacker
import com.artillexstudios.axminions.api.integrations.types.StackerIntegration import com.artillexstudios.axminions.api.integrations.types.StackerIntegration
import dev.rosewood.rosestacker.api.RoseStackerAPI
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.entity.Item import org.bukkit.entity.Item
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
class RoseStackerIntegration : StackerIntegration { class RoseStackerIntegration : StackerIntegration {
lateinit var instance: RoseStackerAPI
override fun getStackSize(entity: LivingEntity): Long { override fun getStackSize(entity: LivingEntity): Long {
TODO("Not yet implemented") return instance.getStackedEntity(entity)?.stackSize?.toLong() ?: 1
} }
override fun getStackSize(item: Item): Long { override fun getStackSize(item: Item): Long {
TODO("Not yet implemented") return instance.getStackedItem(item)?.stackSize?.toLong() ?: 1
} }
override fun dropItemAt(itemStack: ItemStack, amount: Int, location: Location) { override fun dropItemAt(itemStack: ItemStack, amount: Int, location: Location) {
TODO("Not yet implemented") instance.dropItemStack(itemStack, amount, location, false)
} }
override fun register() { override fun register() {
TODO("Not yet implemented") instance = RoseStackerAPI.getInstance()
} }
} }

View File

@ -1,6 +1,7 @@
package com.artillexstudios.axminions.integrations.stacker package com.artillexstudios.axminions.integrations.stacker
import com.artillexstudios.axminions.api.integrations.types.StackerIntegration import com.artillexstudios.axminions.api.integrations.types.StackerIntegration
import com.bgsoftware.wildstacker.api.WildStackerAPI
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.entity.Item import org.bukkit.entity.Item
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
@ -9,18 +10,18 @@ import org.bukkit.inventory.ItemStack
class WildStackerIntegration : StackerIntegration { class WildStackerIntegration : StackerIntegration {
override fun getStackSize(entity: LivingEntity): Long { override fun getStackSize(entity: LivingEntity): Long {
TODO("Not yet implemented") return WildStackerAPI.getStackedEntity(entity)?.stackAmount?.toLong() ?: 1
} }
override fun getStackSize(item: Item): Long { override fun getStackSize(item: Item): Long {
TODO("Not yet implemented") return WildStackerAPI.getStackedItem(item)?.stackAmount?.toLong() ?: 1
} }
override fun dropItemAt(itemStack: ItemStack, amount: Int, location: Location) { override fun dropItemAt(itemStack: ItemStack, amount: Int, location: Location) {
TODO("Not yet implemented") WildStackerAPI.getWildStacker().systemManager.spawnItemWithAmount(location, itemStack, amount);
} }
override fun register() { override fun register() {
TODO("Not yet implemented")
} }
} }

View File

@ -5,8 +5,11 @@ import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.config.Messages import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.minions.Direction import com.artillexstudios.axminions.api.minions.Direction
import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes import com.artillexstudios.axminions.api.utils.CoolDown
import com.artillexstudios.axminions.utils.fastFor import com.artillexstudios.axminions.api.utils.Keys
import com.artillexstudios.axminions.api.utils.fastFor
import java.util.UUID
import java.util.concurrent.TimeUnit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
@ -18,6 +21,7 @@ import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
class MinionInventoryListener : Listener { class MinionInventoryListener : Listener {
private val coolDown = CoolDown<UUID>()
@EventHandler @EventHandler
fun onInventoryDragEvent(event: InventoryDragEvent) { fun onInventoryDragEvent(event: InventoryDragEvent) {
@ -33,6 +37,12 @@ class MinionInventoryListener : Listener {
event.isCancelled = true event.isCancelled = true
val player = event.whoClicked as Player val player = event.whoClicked as Player
if (coolDown.contains(player.uniqueId)) {
return
}
coolDown.add(player.uniqueId, 250)
val allowedTools = arrayListOf<Material>() val allowedTools = arrayListOf<Material>()
minion.getType().getConfig().getStringList("tool.material").fastFor { minion.getType().getConfig().getStringList("tool.material").fastFor {
allowedTools.add(Material.matchMaterial(it) ?: return@fastFor) allowedTools.add(Material.matchMaterial(it) ?: return@fastFor)
@ -48,6 +58,7 @@ class MinionInventoryListener : Listener {
val current = event.currentItem!!.clone() val current = event.currentItem!!.clone()
val tool = minion.getTool()?.clone() val tool = minion.getTool()?.clone()
minion.setTool(current) minion.setTool(current)
minion.updateArmour()
event.currentItem!!.amount = 0 event.currentItem!!.amount = 0
event.clickedInventory!!.addItem(tool) event.clickedInventory!!.addItem(tool)
} else { } else {
@ -68,8 +79,9 @@ class MinionInventoryListener : Listener {
val tool = minion.getTool()?.clone() ?: return val tool = minion.getTool()?.clone() ?: return
minion.setTool(ItemStack(Material.AIR)) minion.setTool(ItemStack(Material.AIR))
minion.updateArmour()
val toolMeta = tool.itemMeta ?: return val toolMeta = tool.itemMeta ?: return
toolMeta.persistentDataContainer.remove(MinionTypes.getGuiKey()) toolMeta.persistentDataContainer.remove(Keys.GUI)
tool.setItemMeta(toolMeta) tool.setItemMeta(toolMeta)
player.inventory.addItem(tool) player.inventory.addItem(tool)
@ -82,16 +94,16 @@ class MinionInventoryListener : Listener {
} }
val meta = event.clickedInventory?.getItem(event.slot)?.itemMeta ?: return val meta = event.clickedInventory?.getItem(event.slot)?.itemMeta ?: return
if (!meta.persistentDataContainer.has(MinionTypes.getGuiKey(), PersistentDataType.STRING)) return if (!meta.persistentDataContainer.has(Keys.GUI, PersistentDataType.STRING)) return
val type = meta.persistentDataContainer.get(MinionTypes.getGuiKey(), PersistentDataType.STRING) val type = meta.persistentDataContainer.get(Keys.GUI, PersistentDataType.STRING)
when (type) { when (type) {
"rotate" -> { "rotate" -> {
when (minion.getDirection()) { when (minion.getDirection()) {
Direction.NORTH -> minion.setDirection(Direction.WEST) Direction.NORTH -> minion.setDirection(Direction.WEST)
Direction.EAST -> minion.setDirection(Direction.NORTH) Direction.EAST -> minion.setDirection(Direction.NORTH)
Direction.SOUTH -> minion.setDirection(Direction.EAST) Direction.SOUTH -> minion.setDirection(Direction.EAST)
Direction.WEST -> minion.setDirection(Direction.SOUTH) Direction.WEST -> minion.setDirection(Direction.SOUTH)
} }
} }

View File

@ -1,13 +1,16 @@
package com.artillexstudios.axminions.listeners package com.artillexstudios.axminions.listeners
import com.artillexstudios.axapi.libs.kyori.adventure.text.minimessage.tag.resolver.Placeholder import com.artillexstudios.axapi.libs.kyori.adventure.text.minimessage.tag.resolver.Placeholder
import com.artillexstudios.axapi.scheduler.Scheduler
import com.artillexstudios.axapi.utils.StringUtils import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.AxMinionsAPI import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.config.Messages import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.minions.Direction import com.artillexstudios.axminions.api.minions.Direction
import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes
import com.artillexstudios.axminions.api.utils.Keys
import com.artillexstudios.axminions.minions.Minion import com.artillexstudios.axminions.minions.Minion
import com.artillexstudios.axminions.minions.Minions
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
import org.bukkit.event.Listener import org.bukkit.event.Listener
@ -25,10 +28,13 @@ class MinionPlaceListener : Listener {
if (event.item == null) return if (event.item == null) return
if (!event.item!!.hasItemMeta()) return if (!event.item!!.hasItemMeta()) return
val type = event.item!!.itemMeta!!.persistentDataContainer.get(MinionTypes.getMinionKey(), PersistentDataType.STRING) ?: return val type = event.item!!.itemMeta!!.persistentDataContainer.get(Keys.MINION_TYPE, PersistentDataType.STRING) ?: return
val minionType = MinionTypes.valueOf(type) ?: return val minionType = MinionTypes.valueOf(type) ?: return
event.isCancelled = true event.isCancelled = true
val level = event.item!!.itemMeta!!.persistentDataContainer.get(Keys.LEVEL, PersistentDataType.INTEGER) ?: 0
val stats = event.item!!.itemMeta!!.persistentDataContainer.get(Keys.STATISTICS, PersistentDataType.LONG) ?: 0
val location = event.clickedBlock!!.getRelative(event.blockFace).location val location = event.clickedBlock!!.getRelative(event.blockFace).location
val maxMinions = AxMinionsAPI.INSTANCE.getMinionLimit(event.player) val maxMinions = AxMinionsAPI.INSTANCE.getMinionLimit(event.player)
@ -46,9 +52,16 @@ class MinionPlaceListener : Listener {
return@submit return@submit
} }
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) val locationId = AxMinionsPlugin.dataHandler.getLocationID(location)
minion.setTicking(true) Scheduler.get().run {
AxMinionsPlugin.dataHandler.saveMinion(minion) val minion = Minion(location, event.player.uniqueId, event.player, minionType, 1, ItemStack(Material.AIR), null, Direction.NORTH, 0, 0.0, locationId, 0)
minion.setLevel(level)
minion.setActions(stats)
minion.setTicking(true)
Minions.addTicking(location.chunk)
event.player.sendMessage("Placed minion $minion. Ticking? ${minion.isTicking()} Is chunk ticking? ${Minions.isTicking(location.chunk)}")
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()))) 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())))
} }

View File

@ -4,6 +4,7 @@ import com.artillexstudios.axapi.entity.PacketEntityFactory
import com.artillexstudios.axapi.entity.impl.PacketArmorStand import com.artillexstudios.axapi.entity.impl.PacketArmorStand
import com.artillexstudios.axapi.entity.impl.PacketEntity import com.artillexstudios.axapi.entity.impl.PacketEntity
import com.artillexstudios.axapi.hologram.Hologram import com.artillexstudios.axapi.hologram.Hologram
import com.artillexstudios.axapi.hologram.HologramFactory
import com.artillexstudios.axapi.libs.kyori.adventure.text.minimessage.tag.resolver.Placeholder import com.artillexstudios.axapi.libs.kyori.adventure.text.minimessage.tag.resolver.Placeholder
import com.artillexstudios.axapi.scheduler.Scheduler import com.artillexstudios.axapi.scheduler.Scheduler
import com.artillexstudios.axapi.serializers.Serializers import com.artillexstudios.axapi.serializers.Serializers
@ -18,23 +19,25 @@ import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.minions.Direction import com.artillexstudios.axminions.api.minions.Direction
import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes import com.artillexstudios.axminions.api.utils.Keys
import com.artillexstudios.axminions.api.utils.fastFor
import com.artillexstudios.axminions.api.warnings.Warning import com.artillexstudios.axminions.api.warnings.Warning
import com.artillexstudios.axminions.api.warnings.Warnings import com.artillexstudios.axminions.api.warnings.Warnings
import com.artillexstudios.axminions.listeners.LinkingListener import com.artillexstudios.axminions.listeners.LinkingListener
import com.artillexstudios.axminions.utils.fastFor import java.util.UUID
import org.bukkit.Bukkit
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.OfflinePlayer import org.bukkit.OfflinePlayer
import org.bukkit.block.Container import org.bukkit.block.Container
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.EntityType import org.bukkit.entity.EntityType
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.Inventory import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.util.EulerAngle import org.bukkit.inventory.meta.Damageable
import java.util.UUID
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import org.bukkit.util.EulerAngle
class Minion( class Minion(
private var location: Location, private var location: Location,
@ -61,6 +64,7 @@ class Minion(
private var linkedInventory: Inventory? = null private var linkedInventory: Inventory? = null
private val openInventories = mutableListOf<Inventory>() private val openInventories = mutableListOf<Inventory>()
private var ticking = false private var ticking = false
private var debugHologram: Hologram? = null
init { init {
spawn() spawn()
@ -79,6 +83,18 @@ class Minion(
entity.setHasBasePlate(false) entity.setHasBasePlate(false)
entity.setSmall(true) entity.setSmall(true)
entity.setHasArms(true) entity.setHasArms(true)
entity.name = StringUtils.format(
type.getConfig().get("entity.name"),
Placeholder.unparsed("owner", owner.name ?: "???"),
Placeholder.unparsed("level", level.toString()),
Placeholder.parsed("level_color", Messages.LEVEL_COLOR(level))
)
if (Config.DEBUG()) {
debugHologram = HologramFactory.get().spawnHologram(location.clone().add(0.0, 2.0, 0.0), "$locationID")
debugHologram?.addLine(StringUtils.format("ticking: $ticking"))
}
setDirection(direction) setDirection(direction)
updateArmour() updateArmour()
entity.onClick { event -> entity.onClick { event ->
@ -98,6 +114,10 @@ class Minion(
type.onToolDirty(this) type.onToolDirty(this)
} }
if (Config.DEBUG() && debugHologram != null) {
debugHologram?.setLine(0, StringUtils.format("Ticking: $ticking Chunk ticking: ${Minions.isTicking(location.chunk)} CHUNK X: ${location.chunk.x} CHUNK Z: ${location.chunk.z}"))
}
type.tick(this) type.tick(this)
animate() animate()
} }
@ -118,10 +138,12 @@ class Minion(
val item: ItemStack val item: ItemStack
if (it.equals("upgrade", true) || it.equals("statistics", true)) { if (it.equals("upgrade", true) || it.equals("statistics", true)) {
val level = Placeholder.unparsed("level", level.toString()) val level = Placeholder.unparsed("level", level.toString())
val nextLevel = Placeholder.unparsed("next_level", when (type.hasReachedMaxLevel(this)) { val nextLevel = Placeholder.unparsed(
true -> Messages.UPGRADES_MAX_LEVEL_REACHED() "next_level", when (type.hasReachedMaxLevel(this)) {
else -> (this.level + 1).toString() true -> Messages.UPGRADES_MAX_LEVEL_REACHED()
}) else -> (this.level + 1).toString()
}
)
val range = Placeholder.unparsed("range", type.getString("range", this.level)) val range = Placeholder.unparsed("range", type.getString("range", this.level))
val nextRange = Placeholder.unparsed("next_range", type.getString("range", this.level + 1)) val nextRange = Placeholder.unparsed("next_range", type.getString("range", this.level + 1))
val extra = Placeholder.unparsed("extra", type.getString("extra", this.level)) val extra = Placeholder.unparsed("extra", type.getString("extra", this.level))
@ -129,22 +151,45 @@ class Minion(
val speed = Placeholder.unparsed("speed", type.getString("speed", this.level)) val speed = Placeholder.unparsed("speed", type.getString("speed", this.level))
val nextSpeed = Placeholder.unparsed("next_speed", type.getString("speed", this.level + 1)) val nextSpeed = Placeholder.unparsed("next_speed", type.getString("speed", this.level + 1))
val price = Placeholder.unparsed("price", type.getString("requirements.money", this.level + 1)) val price = Placeholder.unparsed("price", type.getString("requirements.money", this.level + 1))
val requiredActions = Placeholder.unparsed("required_actions", type.getString("requirements.actions", this.level + 1)) val requiredActions =
Placeholder.unparsed("required_actions", type.getString("requirements.actions", this.level + 1))
val stored = Placeholder.unparsed("storage", storage.toString()) val stored = Placeholder.unparsed("storage", storage.toString())
val actions = Placeholder.unparsed("actions", actions.toString()) val actions = Placeholder.unparsed("actions", actions.toString())
item = ItemBuilder(type.getConfig().getSection("gui.$it"), level, nextLevel, range, nextRange, extra, nextExtra, speed, nextSpeed, price, requiredActions, stored, actions).storePersistentData( item = ItemBuilder(
MinionTypes.getGuiKey(), PersistentDataType.STRING, it).get() type.getConfig().getSection("gui.$it"),
level,
nextLevel,
range,
nextRange,
extra,
nextExtra,
speed,
nextSpeed,
price,
requiredActions,
stored,
actions
).storePersistentData(
Keys.GUI, PersistentDataType.STRING, it
).get()
} else if (it.equals("item")) { } else if (it.equals("item")) {
item = tool?.clone() ?: ItemStack(Material.AIR) item = tool?.clone() ?: ItemStack(Material.AIR)
} else { } else {
val rotation = Placeholder.unparsed("direction", Messages.ROTATION_NAME(direction)) val rotation = Placeholder.unparsed("direction", Messages.ROTATION_NAME(direction))
val linked = Placeholder.unparsed("linked", when (linkedChest) { val linked = Placeholder.unparsed(
null -> "---" "linked", when (linkedChest) {
else -> Serializers.LOCATION.serialize(linkedChest) null -> "---"
}) else -> Serializers.LOCATION.serialize(linkedChest)
item = ItemBuilder(AxMinionsAPI.INSTANCE.getConfig().getConfig().getSection("gui.items.$it"), rotation, linked).storePersistentData( }
MinionTypes.getGuiKey(), PersistentDataType.STRING, it).get() )
item = ItemBuilder(
AxMinionsAPI.INSTANCE.getConfig().getConfig().getSection("gui.items.$it"),
rotation,
linked
).storePersistentData(
Keys.GUI, PersistentDataType.STRING, it
).get()
} }
inventory.setItem(AxMinionsAPI.INSTANCE.getConfig().get("gui.items.$it.slot"), item) inventory.setItem(AxMinionsAPI.INSTANCE.getConfig().get("gui.items.$it.slot"), item)
@ -153,10 +198,19 @@ class Minion(
override fun openInventory(player: Player) { override fun openInventory(player: Player) {
LinkingListener.linking.remove(player.uniqueId) LinkingListener.linking.remove(player.uniqueId)
val inventory = Bukkit.createInventory(this, Config.GUI_SIZE(), StringUtils.formatToString(type.getConfig().get("name"), Placeholder.unparsed("level_color", Messages.LEVEL_COLOR(level)), Placeholder.unparsed("level", level.toString()), Placeholder.unparsed("owner", owner.name ?: "???"))) val inventory = Bukkit.createInventory(
this,
Config.GUI_SIZE(),
StringUtils.formatToString(
type.getConfig().get("name"),
Placeholder.parsed("level_color", Messages.LEVEL_COLOR(level)),
Placeholder.unparsed("level", level.toString()),
Placeholder.unparsed("owner", owner.name ?: "???")
)
)
val filler = ItemBuilder(AxMinionsAPI.INSTANCE.getConfig().getConfig().getSection("gui.items.filler")).get() val filler = ItemBuilder(AxMinionsAPI.INSTANCE.getConfig().getConfig().getSection("gui.items.filler")).get()
for (i in 0..< Config.GUI_SIZE()) { for (i in 0..<Config.GUI_SIZE()) {
inventory.setItem(i, filler) inventory.setItem(i, filler)
} }
@ -166,7 +220,7 @@ class Minion(
} }
override fun getAsItem(): ItemStack { override fun getAsItem(): ItemStack {
return type.getItem(level) return type.getItem(level, actions)
} }
override fun getLevel(): Int { override fun getLevel(): Int {
@ -207,7 +261,7 @@ class Minion(
override fun setTool(tool: ItemStack) { override fun setTool(tool: ItemStack) {
this.tool = tool.clone() this.tool = tool.clone()
updateInventories() dirty = true
if (tool.type == Material.AIR) { if (tool.type == Material.AIR) {
entity.setItem(EquipmentSlot.MAIN_HAND, null) entity.setItem(EquipmentSlot.MAIN_HAND, null)
@ -230,6 +284,17 @@ class Minion(
override fun setLevel(level: Int) { override fun setLevel(level: Int) {
this.level = level this.level = level
entity.name = StringUtils.format(
type.getConfig().get("entity.name"),
Placeholder.unparsed("owner", owner.name ?: "???"),
Placeholder.unparsed("level", level.toString()),
Placeholder.parsed("level_color", Messages.LEVEL_COLOR(level))
)
AxMinionsPlugin.dataQueue.submit {
AxMinionsPlugin.dataHandler.saveMinion(this)
}
} }
override fun getData(key: String): String? { override fun getData(key: String): String? {
@ -306,10 +371,15 @@ class Minion(
} }
override fun addToContainerOrDrop(itemStack: ItemStack) { override fun addToContainerOrDrop(itemStack: ItemStack) {
if (linkedInventory == null) {
AxMinionsPlugin.integrations.getStackerIntegration().dropItemAt(itemStack, itemStack.amount, location)
return
}
val remaining = linkedInventory?.addItem(itemStack) val remaining = linkedInventory?.addItem(itemStack)
remaining?.forEach { (_, u) -> remaining?.forEach { (_, u) ->
location.world?.dropItem(location, u) AxMinionsPlugin.integrations.getStackerIntegration().dropItemAt(u, u.amount, location)
} }
} }
@ -371,6 +441,46 @@ class Minion(
this.nextAction = nextAction this.nextAction = nextAction
} }
override fun markDirty() {
dirty = true
}
override fun damageTool(amount: Int) {
val meta = this.tool?.itemMeta as? Damageable ?: return
if (Math.random() > 1f / (meta.getEnchantLevel(Enchantment.DURABILITY) + 1)) return
if ((tool?.type?.maxDurability ?: return) <= meta.damage + amount) {
if (Config.CAN_BREAK_TOOLS()) {
setTool(ItemStack(Material.AIR))
}
} else {
meta.damage += amount
tool?.itemMeta = meta
}
}
override fun canUseTool(): Boolean {
val meta = this.tool?.itemMeta ?: return false
if (!Config.USE_DURABILITY() && meta is Damageable) {
return true
}
if (meta is Damageable) {
if ((tool?.type?.maxDurability ?: return false) <= meta.damage + 1) {
if (Config.CAN_BREAK_TOOLS()) {
setTool(ItemStack(Material.AIR))
}
return false
} else {
return true
}
}
return false
}
override fun getInventory(): Inventory { override fun getInventory(): Inventory {
return Bukkit.createInventory(this, 9) return Bukkit.createInventory(this, 9)
} }

View File

@ -1,7 +1,7 @@
package com.artillexstudios.axminions.minions package com.artillexstudios.axminions.minions
import com.artillexstudios.axapi.scheduler.Scheduler import com.artillexstudios.axapi.scheduler.Scheduler
import com.artillexstudios.axminions.utils.fastFor import com.artillexstudios.axminions.api.utils.fastFor
object MinionTicker { object MinionTicker {
private var tick = 0L private var tick = 0L

View File

@ -2,77 +2,70 @@ package com.artillexstudios.axminions.minions
import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.utils.ChunkPos import com.artillexstudios.axminions.api.minions.utils.ChunkPos
import com.artillexstudios.axminions.utils.fastFor import com.artillexstudios.axminions.api.utils.fastFor
import java.util.Collections import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import org.bukkit.Chunk import org.bukkit.Chunk
object Minions { object Minions {
private val mutex = Object() private val minions = ConcurrentHashMap<ChunkPos, ArrayList<Minion>>()
private val minions = hashMapOf<ChunkPos, ArrayList<Minion>>()
private val mutableChunkPos = ChunkPos(0, 0)
fun addTicking(chunk: Chunk) { fun addTicking(chunk: Chunk) {
synchronized(mutex) { val pos = ChunkPos(chunk.x, chunk.z)
mutableChunkPos.x = chunk.x
mutableChunkPos.z = chunk.z
minions[mutableChunkPos]?.fastFor { minions[pos]?.fastFor {
it.setTicking(true) it.setTicking(true)
} ?: return } ?: return
} println("LOADING CHUNK! X: ${chunk.x} Z: ${chunk.z}")
}
fun isTicking(chunk: Chunk): Boolean {
val pos = ChunkPos(chunk.x, chunk.z)
return minions.contains(pos)
} }
fun removeTicking(chunk: Chunk) { fun removeTicking(chunk: Chunk) {
synchronized(mutex) { val pos = ChunkPos(chunk.x, chunk.z)
mutableChunkPos.x = chunk.x
mutableChunkPos.z = chunk.z
val minions = this.minions[mutableChunkPos] ?: return val minions = this.minions[pos] ?: return
minions.fastFor { minions.fastFor {
it.setTicking(false) it.setTicking(false)
}
} }
} }
fun load(minion: Minion) { fun load(minion: Minion) {
synchronized(mutex) { println("LOADING MINION!!")
mutableChunkPos.x = round(minion.getLocation().x) shr 4 val chunkPos = ChunkPos(minion.getLocation().chunk.x, minion.getLocation().chunk.z)
mutableChunkPos.z = round(minion.getLocation().z) shr 4 val pos = minions[chunkPos] ?: arrayListOf()
val pos = minions[mutableChunkPos] ?: arrayListOf()
pos.add(minion) pos.add(minion)
minions[mutableChunkPos] = pos minions[chunkPos] = pos
}
} }
fun remove(minion: Minion) { fun remove(minion: Minion) {
synchronized(mutex) { val chunkPos = ChunkPos(minion.getLocation().chunk.x, minion.getLocation().chunk.z)
mutableChunkPos.x = minion.getLocation().blockX shr 4
mutableChunkPos.z = minion.getLocation().blockZ shr 4
val pos = minions[mutableChunkPos] ?: return
pos.remove(minion) val pos = minions[chunkPos] ?: return
if (pos.isEmpty()) {
minions.remove(mutableChunkPos) pos.remove(minion)
} if (pos.isEmpty()) {
minions.remove(chunkPos)
} }
} }
fun getMinions(): List<Minion> { fun getMinions(): List<Minion> {
synchronized(mutex) { val list = mutableListOf<Minion>()
val list = mutableListOf<Minion>() minions.forEach { (_, value) ->
minions.forEach { (_, value) -> list.addAll(value)
list.addAll(value)
}
return Collections.unmodifiableList(list)
} }
return Collections.unmodifiableList(list)
} }
internal fun get(): HashMap<ChunkPos, ArrayList<Minion>> { internal fun get(): ConcurrentHashMap<ChunkPos, ArrayList<Minion>> {
synchronized(mutex) { return minions
return minions
}
} }
private infix fun round(double: Double): Int { private infix fun round(double: Double): Int {

View File

@ -24,7 +24,6 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
} }
override fun run(minion: Minion) { override fun run(minion: Minion) {
minion.resetAnimation()
if (minion.getLinkedChest() == null) { if (minion.getLinkedChest() == null) {
Warnings.NO_CONTAINER.display(minion) Warnings.NO_CONTAINER.display(minion)
return return
@ -45,6 +44,13 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
Warnings.remove(minion) Warnings.remove(minion)
if (!minion.canUseTool()) {
Warnings.NO_TOOL.display(minion)
return
}
Warnings.remove(minion)
val entities = minion.getLocation().world?.getNearbyEntities( val entities = minion.getLocation().world?.getNearbyEntities(
minion.getLocation(), minion.getLocation(),
minion.getRange(), minion.getRange(),
@ -58,7 +64,14 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
return return
} }
//TODO: Add to inventory and remove items val amount = AxMinionsPlugin.integrations.getStackerIntegration().getStackSize(item)
val stack = item.itemStack.clone()
stack.amount = amount.toInt()
minion.addToContainerOrDrop(stack)
minion.setActions(minion.getActionAmount() + 1)
minion.damageTool()
item.remove()
} }
} }
} }

View File

@ -4,8 +4,10 @@ import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.minions.MinionTicker import com.artillexstudios.axminions.minions.MinionTicker
import com.artillexstudios.axminions.utils.LocationUtils import com.artillexstudios.axminions.api.utils.LocationUtils
import com.artillexstudios.axminions.utils.fastFor import com.artillexstudios.axminions.api.utils.MinionUtils
import com.artillexstudios.axminions.api.utils.fastFor
import com.artillexstudios.axminions.api.warnings.Warnings
import kotlin.math.roundToInt import kotlin.math.roundToInt
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.block.data.Ageable import org.bukkit.block.data.Ageable
@ -26,16 +28,41 @@ class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResour
} }
override fun run(minion: Minion) { override fun run(minion: Minion) {
minion.resetAnimation() if (minion.getLinkedChest() != null) {
val type = minion.getLinkedChest()!!.block.type
if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) {
minion.setLinkedChest(null)
}
}
if (minion.getLinkedInventory() == null) {
minion.setLinkedChest(null)
}
if (!minion.canUseTool()) {
Warnings.NO_TOOL.display(minion)
return
}
Warnings.remove(minion)
LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location -> LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location ->
val block = location.block val block = location.block
val drops = arrayListOf<ItemStack>() val drops = arrayListOf<ItemStack>()
when (block.type) { when (block.type) {
Material.CACTUS, Material.SUGAR_CANE, Material.BAMBOO, Material.MELON, Material.PUMPKIN -> { Material.CACTUS, Material.SUGAR_CANE, Material.BAMBOO -> {
MinionUtils.getPlant(block).fastFor {
drops.addAll(it.getDrops(minion.getTool()))
it.type = Material.AIR
}
}
Material.MELON, Material.PUMPKIN -> {
drops.addAll(block.getDrops(minion.getTool())) drops.addAll(block.getDrops(minion.getTool()))
block.type = Material.AIR block.type = Material.AIR
} }
Material.COCOA_BEANS, Material.COCOA, Material.NETHER_WART, Material.WHEAT, Material.CARROTS, Material.BEETROOTS, Material.POTATOES -> { Material.COCOA_BEANS, Material.COCOA, Material.NETHER_WART, Material.WHEAT, Material.CARROTS, Material.BEETROOTS, Material.POTATOES -> {
val ageable = block.blockData as Ageable val ageable = block.blockData as Ageable
if (ageable.age != ageable.maximumAge) return@fastFor if (ageable.age != ageable.maximumAge) return@fastFor
@ -43,6 +70,7 @@ class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResour
ageable.age = 0 ageable.age = 0
block.blockData = ageable block.blockData = ageable
} }
Material.SWEET_BERRY_BUSH -> { Material.SWEET_BERRY_BUSH -> {
val ageable = block.blockData as Ageable val ageable = block.blockData as Ageable
if (ageable.age != ageable.maximumAge) return@fastFor if (ageable.age != ageable.maximumAge) return@fastFor
@ -50,10 +78,14 @@ class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResour
ageable.age = 1 ageable.age = 1
block.blockData = ageable block.blockData = ageable
} }
else -> return@fastFor else -> return@fastFor
} }
minion.addToContainerOrDrop(drops) minion.addToContainerOrDrop(drops)
val dropsSize = drops.size
minion.damageTool(dropsSize)
minion.setActions(minion.getActionAmount() + dropsSize)
} }
} }
} }

View File

@ -3,10 +3,92 @@ package com.artillexstudios.axminions.minions.miniontype
import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.api.utils.LocationUtils
import com.artillexstudios.axminions.api.utils.MinionUtils
import com.artillexstudios.axminions.api.utils.fastFor
import com.artillexstudios.axminions.api.warnings.Warnings
import com.artillexstudios.axminions.minions.MinionTicker
import kotlin.math.roundToInt
import org.bukkit.Material
import org.bukkit.block.BlockFace
import org.bukkit.enchantments.Enchantment
import org.bukkit.inventory.ItemStack
class LumberMinionType : MinionType("lumber", AxMinionsPlugin.INSTANCE.getResource("minions/lumber.yml")!!) { class LumberMinionType : MinionType("lumber", AxMinionsPlugin.INSTANCE.getResource("minions/lumber.yml")!!) {
override fun run(minion: Minion) { override fun shouldRun(minion: Minion): Boolean {
return MinionTicker.getTick() % minion.getNextAction() == 0L
}
override fun onToolDirty(minion: Minion) {
val minionImpl = minion as com.artillexstudios.axminions.minions.Minion
minionImpl.setRange(getDouble("range", minion.getLevel()))
val efficiency = 1.0 - (minion.getTool()?.getEnchantmentLevel(Enchantment.DIG_SPEED)?.div(10.0) ?: 0.1)
minionImpl.setNextAction((getLong("speed", minion.getLevel()) * efficiency).roundToInt())
}
override fun run(minion: Minion) {
if (minion.getLinkedChest() != null) {
val type = minion.getLinkedChest()!!.block.type
if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) {
minion.setLinkedChest(null)
}
}
if (minion.getLinkedInventory() == null) {
minion.setLinkedChest(null)
}
if (!minion.canUseTool()) {
Warnings.NO_TOOL.display(minion)
return
}
Warnings.remove(minion)
val loot = ArrayList<ItemStack>()
LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location ->
MinionUtils.getTree(location.block).fastFor {
val down = it.getRelative(BlockFace.DOWN).type
loot.addAll(it.getDrops(minion.getTool()))
if (down == Material.DIRT || down == Material.GRASS_BLOCK || down == Material.COARSE_DIRT || down == Material.ROOTED_DIRT || down == Material.DIRT_PATH) {
it.type = getSaplingType(it.type)
} else {
it.type = Material.AIR
}
}
}
val lootSize = loot.size
minion.damageTool(lootSize)
minion.setActions(minion.getActionAmount() + lootSize)
minion.addToContainerOrDrop(loot)
}
private fun getSaplingType(material: Material): Material {
return when (material) {
Material.DARK_OAK_LOG -> {
Material.DARK_OAK_SAPLING
}
Material.BIRCH_LOG -> {
Material.BIRCH_SAPLING
}
Material.ACACIA_LOG -> {
Material.ACACIA_SAPLING
}
Material.JUNGLE_LOG -> {
Material.JUNGLE_SAPLING
}
Material.SPRUCE_LOG -> {
Material.SPRUCE_SAPLING
}
else -> Material.OAK_SAPLING
}
} }
} }

View File

@ -1,12 +1,110 @@
package com.artillexstudios.axminions.minions.miniontype package com.artillexstudios.axminions.minions.miniontype
import com.artillexstudios.axapi.scheduler.Scheduler
import com.artillexstudios.axminions.AxMinionsPlugin import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.minions.Minion import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.api.utils.LocationUtils
import com.artillexstudios.axminions.api.utils.MinionUtils
import com.artillexstudios.axminions.api.utils.fastFor
import com.artillexstudios.axminions.api.warnings.Warnings
import com.artillexstudios.axminions.minions.MinionTicker
import java.util.Locale
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.roundToInt
import org.bukkit.Material
import org.bukkit.block.BlockFace
import org.bukkit.enchantments.Enchantment
class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource("minions/miner.yml")!!) { class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource("minions/miner.yml")!!) {
private var asyncExecutor: ExecutorService? = null
private val faces = arrayOf(BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST)
override fun shouldRun(minion: Minion): Boolean {
return MinionTicker.getTick() % minion.getNextAction() == 0L
}
override fun onToolDirty(minion: Minion) {
val minionImpl = minion as com.artillexstudios.axminions.minions.Minion
minionImpl.setRange(getDouble("range", minion.getLevel()))
val efficiency = 1.0 - (minion.getTool()?.getEnchantmentLevel(Enchantment.DIG_SPEED)?.div(10.0) ?: 0.1)
minionImpl.setNextAction((getLong("speed", minion.getLevel()) * efficiency).roundToInt())
}
override fun run(minion: Minion) { override fun run(minion: Minion) {
if (minion.getLinkedChest() != null) {
val type = minion.getLinkedChest()!!.block.type
if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) {
minion.setLinkedChest(null)
}
}
if (minion.getLinkedInventory() == null) {
minion.setLinkedChest(null)
}
if (!minion.canUseTool()) {
Warnings.NO_TOOL.display(minion)
return
}
Warnings.remove(minion)
when (getConfig().getString("mode").lowercase(Locale.ENGLISH)) {
"sphere" -> {
LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location ->
val isStoneGenerator = MinionUtils.isStoneGenerator(location)
if (isStoneGenerator) {
minion.addToContainerOrDrop(location.block.getDrops(minion.getTool()))
location.block.type = Material.AIR
}
}
}
"asphere" -> {
if (asyncExecutor == null) {
asyncExecutor = Executors.newFixedThreadPool(3)
}
asyncExecutor!!.execute {
LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location ->
val isStoneGenerator = MinionUtils.isStoneGenerator(location)
if (isStoneGenerator) {
Scheduler.get().run {
minion.addToContainerOrDrop(location.block.getDrops(minion.getTool()))
location.block.type = Material.AIR
}
}
}
}
}
"line" -> {
faces.fastFor {
LocationUtils.getAllBlocksFacing(minion.getLocation(), minion.getRange(), it).fastFor { location ->
val isStoneGenerator = MinionUtils.isStoneGenerator(location)
if (isStoneGenerator) {
minion.addToContainerOrDrop(location.block.getDrops(minion.getTool()))
location.block.type = Material.AIR
}
}
}
}
"face" -> {
LocationUtils.getAllBlocksFacing(minion.getLocation(), minion.getRange(), minion.getDirection().facing).fastFor { location ->
val isStoneGenerator = MinionUtils.isStoneGenerator(location)
if (isStoneGenerator) {
minion.addToContainerOrDrop(location.block.getDrops(minion.getTool()))
location.block.type = Material.AIR
}
}
}
}
} }
} }

View File

@ -77,5 +77,9 @@ gui:
statistics: statistics:
slot: 16 slot: 16
# Only change this, if you are asked to! This will make your performance worse, and will spam messages in your console!
# Requires restart!
debug: false
# Do not change! # Do not change!
config-version: 1 config-version: 1

View File

@ -0,0 +1,138 @@
name: "<#00AAFF>Lumberjack <white>Minion"
entity:
name: "<level_color>[<level>] <#00AAFF>Lumberjack <white>Minion <gray>[<owner>]"
tool:
material:
- "WOODEN_AXE"
- "STONE_AXE"
- "GOLDEN_AXE"
- "IRON_AXE"
- "DIAMOND_AXE"
- "NETHERITE_AXE"
item:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk2MjdiZTYyY2VkNzE0MTEzOWQzZjE1NTc5MGE1ZDQzNTZlYjdiOWVlOTVlNTA0YjMzMjI5NzRjYmM1MTVlYSJ9fX0="
name: "<#00AAFF>Lumberjack <white>Minion"
lore:
- ""
- " <gray>- <white>Collects all items around itself."
- ""
- "<#00AAFF>Statistics"
- " <#00AAFF>❙ <white>Level: <#FFEEAA><level>"
- " <#00AAFF>❙ <white>Broken blocks: <#FFEEAA><actions>"
- ""
- "<#00AAFF><b>(!)</b> Place the minion and give it an axe!"
gui:
upgrade:
type: "gold_ingot"
name: "<#00CCFF><b>Upgrade minion"
lore:
- ""
- " <gray>- <white>Level: <green><level> » <dark_green><next_level>"
- " <gray>- <white>Range: <green><range> » <dark_green><next_range>"
- " <gray>- <white>Speed: <green><speed> » <dark_green><next_speed>"
- ""
- "<#00CCFF>Requirements:"
- " <gray>- <white>Money: <#33FF33><price>$"
- " <gray>- <white>Collected items: <#33FF33><required_actions>"
- ""
- "<#00CCFF><b>(!)</b> Click here to upgrade your minion!"
statistics:
type: "paper"
name: "<#00AAFF><b>Statistics"
lore:
- ""
- " <gray>- <white>Broken blocks: <#00AAFF><actions>"
- ""
upgrades:
1:
range: 3
speed: 200
items:
helmet:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk2MjdiZTYyY2VkNzE0MTEzOWQzZjE1NTc5MGE1ZDQzNTZlYjdiOWVlOTVlNTA0YjMzMjI5NzRjYmM1MTVlYSJ9fX0="
chestplate:
type: "leather_chestplate"
color: "0, 150, 255"
glow: false
leggings:
type: "leather_leggings"
color: "0, 150, 255"
glow: false
boots:
type: "leather_boots"
color: "0, 150, 255"
glow: false
2:
range: 4
speed: 190
requirements:
money: 1000
actions: 100
3:
range: 5
speed: 175
requirements:
money: 3000
actions: 300
4:
range: 6
speed: 160
requirements:
money: 10000
actions: 1000
5:
range: 7
speed: 150
requirements:
money: 20000
actions: 3000
6:
range: 8
speed: 130
requirements:
money: 50000
actions: 6000
7:
range: 9
speed: 115
requirements:
money: 150000
actions: 10000
8:
range: 10
speed: 100
requirements:
money: 500000
actions: 17500
9:
range: 11
speed: 85
requirements:
money: 1000000
actions: 25000
10:
range: 12
speed: 60
requirements:
money: 5000000
actions: 50000
items:
chestplate:
type: LEATHER_CHESTPLATE
color: "255, 200, 0"
glow: true
leggings:
type: LEATHER_LEGGINGS
color: "255, 200, 0"
glow: true
boots:
type: LEATHER_BOOTS
color: "255, 200, 0"
glow: true

View File

@ -0,0 +1,147 @@
name: "<#00AAFF>Miner <white>Minion"
entity:
name: "<level_color>[<level>] <#00AAFF>Miner <white>Minion <gray>[<owner>]"
tool:
material:
- "WOODEN_PICKAXE"
- "STONE_PICKAXE"
- "GOLDEN_PICKAXE"
- "IRON_PICKAXE"
- "DIAMOND_PICKAXE"
- "NETHERITE_PICKAXE"
# Can be: sphere, line, face, asphere
# If set to sphere: checks blocks in a sphere with the range of the minion as radius (Most resource intensive, the larger the radius, the worse)
# If set to line: checks blocks in all 4 directions from the minion in the range of the minion
# If set to face: checks blocks only in the facing of the minion (Least resource intensive)
# If set to asphere: checks blocks in a sphere with the range of the minion as the radius, around the minion
# Only switch to asphere mode, if you know what you're doing,
# as it may cause some issues due to states being concurrently modified!
mode: line
item:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk2MjdiZTYyY2VkNzE0MTEzOWQzZjE1NTc5MGE1ZDQzNTZlYjdiOWVlOTVlNTA0YjMzMjI5NzRjYmM1MTVlYSJ9fX0="
name: "<#00AAFF>Miner <white>Minion"
lore:
- ""
- " <gray>- <white>Collects all items around itself."
- ""
- "<#00AAFF>Statistics"
- " <#00AAFF>❙ <white>Level: <#FFEEAA><level>"
- " <#00AAFF>❙ <white>Broken blocks: <#FFEEAA><actions>"
- ""
- "<#00AAFF><b>(!)</b> Place the minion and give it a pickaxe!"
gui:
upgrade:
type: "gold_ingot"
name: "<#00CCFF><b>Upgrade minion"
lore:
- ""
- " <gray>- <white>Level: <green><level> » <dark_green><next_level>"
- " <gray>- <white>Range: <green><range> » <dark_green><next_range>"
- " <gray>- <white>Speed: <green><speed> » <dark_green><next_speed>"
- ""
- "<#00CCFF>Requirements:"
- " <gray>- <white>Money: <#33FF33><price>$"
- " <gray>- <white>Collected items: <#33FF33><required_actions>"
- ""
- "<#00CCFF><b>(!)</b> Click here to upgrade your minion!"
statistics:
type: "paper"
name: "<#00AAFF><b>Statistics"
lore:
- ""
- " <gray>- <white>Broken blocks: <#00AAFF><actions>"
- ""
upgrades:
1:
range: 3
speed: 200
items:
helmet:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk2MjdiZTYyY2VkNzE0MTEzOWQzZjE1NTc5MGE1ZDQzNTZlYjdiOWVlOTVlNTA0YjMzMjI5NzRjYmM1MTVlYSJ9fX0="
chestplate:
type: "leather_chestplate"
color: "0, 150, 255"
glow: false
leggings:
type: "leather_leggings"
color: "0, 150, 255"
glow: false
boots:
type: "leather_boots"
color: "0, 150, 255"
glow: false
2:
range: 4
speed: 190
requirements:
money: 1000
actions: 100
3:
range: 5
speed: 175
requirements:
money: 3000
actions: 300
4:
range: 6
speed: 160
requirements:
money: 10000
actions: 1000
5:
range: 7
speed: 150
requirements:
money: 20000
actions: 3000
6:
range: 8
speed: 130
requirements:
money: 50000
actions: 6000
7:
range: 9
speed: 115
requirements:
money: 150000
actions: 10000
8:
range: 10
speed: 100
requirements:
money: 500000
actions: 17500
9:
range: 11
speed: 85
requirements:
money: 1000000
actions: 25000
10:
range: 12
speed: 60
requirements:
money: 5000000
actions: 50000
items:
chestplate:
type: LEATHER_CHESTPLATE
color: "255, 200, 0"
glow: true
leggings:
type: LEATHER_LEGGINGS
color: "255, 200, 0"
glow: true
boots:
type: LEATHER_BOOTS
color: "255, 200, 0"
glow: true

View File

@ -1,4 +1,7 @@
name: "AxMinions" name: "AxMinions"
main: "com.artillexstudios.axminions.AxMinionsPlugin" main: "com.artillexstudios.axminions.AxMinionsPlugin"
version: "1.0" version: "1.0"
api-version: 1.19 api-version: 1.19
softdepend:
- RoseStacker
- WildStacker