This commit is contained in:
TomTom 2023-10-04 20:30:39 +02:00
parent 985af5f6b6
commit 5495652ea9
31 changed files with 575 additions and 78 deletions

View File

@ -1,8 +1,11 @@
package com.artillexstudios.axminions.api
import com.artillexstudios.axapi.AxPlugin
import com.artillexstudios.axminions.api.config.Config
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.data.DataHandler
import com.artillexstudios.axminions.api.minions.Minion
import org.bukkit.entity.Player
import java.io.File
interface AxMinionsAPI {
@ -15,6 +18,12 @@ interface AxMinionsAPI {
fun getDataHandler(): DataHandler
fun getMinions(): List<Minion>
fun getAxMinionsInstance(): AxPlugin
fun getMinionLimit(player: Player): Int
companion object {
@JvmStatic
lateinit var INSTANCE: AxMinionsAPI

View File

@ -12,30 +12,30 @@ import java.io.InputStream
class Config(file: File, stream: InputStream) {
companion object {
@JvmField
val AUTO_SAVE_MINUTES = AxMinionsAPI.INSTANCE.getConfig().get("autosave-minutes", 3L)
@JvmField
val MAX_LINKING_DISTANCE = AxMinionsAPI.INSTANCE.getConfig().get("max-linking-distance", 30)
@JvmField
val DEFAULT_MINION_LIMIT = AxMinionsAPI.INSTANCE.getConfig().get("default-minion-limit", 5)
@JvmField
val ALLOW_FLOATING_MINIONS = AxMinionsAPI.INSTANCE.getConfig().get("allow-floating-minions", false)
@JvmField
val ONLY_OWNER_BREAK = AxMinionsAPI.INSTANCE.getConfig().get("only-owner-break", true)
@JvmField
val DISPLAY_WARNINGS = AxMinionsAPI.INSTANCE.getConfig().get("display-warnings", true)
@JvmField
val CAN_BREAK_TOOLS = AxMinionsAPI.INSTANCE.getConfig().get("can-break-tools", true)
@JvmField
val USE_DURABILITY = AxMinionsAPI.INSTANCE.getConfig().get("use-durability", true)
@JvmField
val DATABASE_TYPE = AxMinionsAPI.INSTANCE.getConfig().get("database.type", "H2")
@JvmField
val STACKER_HOOK = AxMinionsAPI.INSTANCE.getConfig().get("hooks.stacker", "none")
@JvmField
val ECONOMY_HOOK = AxMinionsAPI.INSTANCE.getConfig().get("hooks.economy", "Vault")
@JvmField
val PRICES_HOOK = AxMinionsAPI.INSTANCE.getConfig().get("hooks.prices", "ShopGUIPlus")
@JvmStatic
fun AUTO_SAVE_MINUTES() = AxMinionsAPI.INSTANCE.getConfig().get("autosave-minutes", 3L)
@JvmStatic
fun MAX_LINKING_DISTANCE() = AxMinionsAPI.INSTANCE.getConfig().get("max-linking-distance", 30)
@JvmStatic
fun DEFAULT_MINION_LIMIT() = AxMinionsAPI.INSTANCE.getConfig().get("default-minion-limit", 5)
@JvmStatic
fun ALLOW_FLOATING_MINIONS() = AxMinionsAPI.INSTANCE.getConfig().get("allow-floating-minions", false)
@JvmStatic
fun ONLY_OWNER_BREAK() = AxMinionsAPI.INSTANCE.getConfig().get("only-owner-break", true)
@JvmStatic
fun DISPLAY_WARNINGS() = AxMinionsAPI.INSTANCE.getConfig().get("display-warnings", true)
@JvmStatic
fun CAN_BREAK_TOOLS() = AxMinionsAPI.INSTANCE.getConfig().get("can-break-tools", true)
@JvmStatic
fun USE_DURABILITY() = AxMinionsAPI.INSTANCE.getConfig().get("use-durability", true)
@JvmStatic
fun DATABASE_TYPE() = AxMinionsAPI.INSTANCE.getConfig().get("database.type", "H2")
@JvmStatic
fun STACKER_HOOK() = AxMinionsAPI.INSTANCE.getConfig().get("hooks.stacker", "none")
@JvmStatic
fun ECONOMY_HOOK() = AxMinionsAPI.INSTANCE.getConfig().get("hooks.economy", "Vault")
@JvmStatic
fun PRICES_HOOK() = AxMinionsAPI.INSTANCE.getConfig().get("hooks.prices", "ShopGUIPlus")
}
private val config = Config(

View File

@ -13,16 +13,16 @@ import java.io.InputStream
class Messages(file: File, stream: InputStream) {
companion object {
@JvmField
var PREFIX = AxMinionsAPI.INSTANCE.getMessages().get<String>("prefix")
@JvmField
var NO_CONTAINER_WARNING = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.no-container")
@JvmField
var NO_TOOL_WARNING = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.no-tool")
@JvmField
var NO_WATER_NEARBY_WARNING = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.no-water-nearby")
@JvmField
var CONTAINER_FULL_WARNING = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.container-full")
@JvmStatic
fun PREFIX() = AxMinionsAPI.INSTANCE.getMessages().get<String>("prefix")
@JvmStatic
fun NO_CONTAINER_WARNING() = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.no-container")
@JvmStatic
fun NO_TOOL_WARNING() = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.no-tool")
@JvmStatic
fun NO_WATER_NEARBY_WARNING() = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.no-water-nearby")
@JvmStatic
fun CONTAINER_FULL_WARNING() = AxMinionsAPI.INSTANCE.getMessages().get<String>("warnings.container-full")
}
private val config = Config(

View File

@ -72,4 +72,12 @@ interface Minion {
fun setDirection(direction: Direction)
fun getDirection(): Direction
fun remove()
fun getLinkedInventory(): Inventory?
fun addToContainerOrDrop(itemStack: ItemStack)
fun addToContainerOrDrop(itemStack: Iterable<ItemStack>)
}

View File

@ -1,9 +1,13 @@
package com.artillexstudios.axminions.api.minions.miniontype
import com.artillexstudios.axapi.config.Config
import com.artillexstudios.axapi.utils.ItemBuilder
import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.minions.Minion
import dev.dejvokep.boostedyaml.block.implementation.Section
import org.bukkit.Location
import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
import java.io.File
import java.io.InputStream
@ -11,7 +15,7 @@ abstract class MinionType(private val name: String, private val defaults: InputS
private lateinit var config: Config
fun load() {
config = Config(File(AxMinionsAPI.INSTANCE.getAxMinionsDataFolder(), "$name.yml"), defaults)
config = Config(File(AxMinionsAPI.INSTANCE.getAxMinionsDataFolder(), "/minions/$name.yml"), defaults)
AxMinionsAPI.INSTANCE.getDataHandler().loadMinionsOfType(this)
}
@ -34,9 +38,50 @@ abstract class MinionType(private val name: String, private val defaults: InputS
run(minion)
}
fun getItem(): ItemStack {
val builder = ItemBuilder(config.getSection("item"))
val itemStack = builder.clonedGet()
val itemMeta = itemStack.itemMeta ?: return itemStack
itemMeta.persistentDataContainer.set(MinionTypes.getMinionKey(), PersistentDataType.STRING, name)
itemStack.setItemMeta(itemMeta)
return itemStack
}
fun getConfig(): Config {
return this.config
}
fun getString(key: String, level: Int): String {
return get(key, level, "---", String::class.java)!!
}
fun getDouble(key: String, level: Int): Double {
return get(key, level, -1.0, Double::class.java)!!
}
fun getLong(key: String, level: Int): Long {
return get(key, level, -1, Long::class.java)!!
}
fun getSection(key: String, level: Int): Section? {
return get(key, level, null, Section::class.java)
}
private fun <T> get(key: String, level: Int, defaultValue: T?, clazz: Class<T>): T? {
var n = defaultValue
config.getSection("upgrades").getRoutesAsStrings(false).forEach {
if (it.toInt() > level) return n
if (config.backingDocument.getAsOptional("upgrades.$it.$key", clazz).isEmpty) return@forEach
n = config.get("upgrades.$it.$key")
}
return n
}
abstract fun run(minion: Minion)
}

View File

@ -1,11 +1,15 @@
package com.artillexstudios.axminions.api.minions.miniontype
import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.exception.MinionTypeAlreadyRegisteredException
import org.bukkit.NamespacedKey
import java.util.Collections
object MinionTypes {
private val TYPES = hashMapOf<String, MinionType>()
private val MINION_KEY = NamespacedKey(AxMinionsAPI.INSTANCE.getAxMinionsInstance(), "minion_type")
@JvmStatic
fun register(type: MinionType): MinionType {
if (TYPES.containsKey(type.getName())) {
throw MinionTypeAlreadyRegisteredException("A minion with type ${type.getName()} has already been registered!")
@ -16,10 +20,22 @@ object MinionTypes {
return type
}
@JvmStatic
fun unregister(key: String) {
TYPES.remove(key)
}
@JvmStatic
fun valueOf(name: String): MinionType? {
return TYPES[name]
}
@JvmStatic
fun getMinionKey(): NamespacedKey {
return MINION_KEY
}
@JvmStatic
fun getMinionTypes(): Map<String, MinionType> {
return Collections.unmodifiableMap(TYPES)
}

View File

@ -8,6 +8,6 @@ import net.kyori.adventure.text.Component
class WarningContainerFull : Warning("container_full") {
override fun getContent(): Component {
return StringUtils.format(Messages.CONTAINER_FULL_WARNING)
return StringUtils.format(Messages.CONTAINER_FULL_WARNING())
}
}

View File

@ -8,6 +8,6 @@ import net.kyori.adventure.text.Component
class WarningNoContainer : Warning("no_container") {
override fun getContent(): Component {
return StringUtils.format(Messages.NO_CONTAINER_WARNING)
return StringUtils.format(Messages.NO_CONTAINER_WARNING())
}
}

View File

@ -8,6 +8,6 @@ import net.kyori.adventure.text.Component
class WarningNoTool : Warning("no_tool") {
override fun getContent(): Component {
return StringUtils.format(Messages.NO_TOOL_WARNING)
return StringUtils.format(Messages.NO_TOOL_WARNING())
}
}

View File

@ -8,6 +8,6 @@ import net.kyori.adventure.text.Component
class WarningNoWaterNearby : Warning("no_water_nearby") {
override fun getContent(): Component {
return StringUtils.format(Messages.NO_WATER_NEARBY_WARNING)
return StringUtils.format(Messages.NO_WATER_NEARBY_WARNING())
}
}

View File

@ -19,6 +19,7 @@ repositories {
dependencies {
implementation project(path: ":api")
implementation project(path: ":common")
}
allprojects {
@ -61,11 +62,9 @@ allprojects {
compileOnly 'dev.rosewood:rosestacker:1.5.11'
compileOnly 'com.bgsoftware:WildStackerAPI:2023.2'
compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
compileOnly 'com.h2database:h2:2.2.220'
compileOnly 'com.github.NEZNAMY:YamlAssist:1.0.5'
compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0'
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0'
implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4'
compileOnly 'com.h2database:h2:2.2.220'
implementation files('../libs/AxAPI-1.0-SNAPSHOT.jar')
}

View File

@ -1,12 +1,39 @@
package com.artillexstudios.axminions
import com.artillexstudios.axapi.AxPlugin
import com.artillexstudios.axapi.data.ThreadedQueue
import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.AxMinionsAPIImpl
import com.artillexstudios.axminions.api.config.Config
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.data.DataHandler
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.minions.miniontype.CollectorMinionType
import com.artillexstudios.axminions.minions.miniontype.FarmerMinionType
import net.byteflux.libby.BukkitLibraryManager
import net.byteflux.libby.Library
import revxrsal.commands.bukkit.BukkitCommandHandler
import java.io.File
class AxMinionsPlugin : AxPlugin() {
companion object {
lateinit var INSTANCE: AxMinionsPlugin
lateinit var messages: Messages
lateinit var config: Config
lateinit var dataHandler: DataHandler
lateinit var dataQueue: ThreadedQueue<Runnable>
}
init {
val manager = BukkitLibraryManager(this)
val stdLib = Library.builder().groupId("org.jetbrains.kotlin").artifactId("kotlin-stdlib").relocate("org.jetbrains.kotlin", "com.artillexstudios.axminions.libs.kotlin").version("1.9.0").build()
val h2 = Library.builder().groupId("com.h2database").artifactId("h2").version("2.2.220").relocate("org.h2", "com.artillexstudios.axminions.libs.h2").build()
manager.addMavenCentral()
manager.loadLibrary(stdLib)
manager.loadLibrary(h2)
}
override fun load() {
@ -15,6 +42,43 @@ class AxMinionsPlugin : AxPlugin() {
}
override fun enable() {
AxMinionsPlugin.config = Config(File(dataFolder, "config.yml"), getResource("config.yml")!!)
messages = Messages(File(dataFolder, "messages.yml"), getResource("messages.yml")!!)
loadDataHandler()
dataQueue = ThreadedQueue("AxMinions-Database-Queue")
MinionTypes.also {
it.register(CollectorMinionType())
it.register(FarmerMinionType())
}
val handler = BukkitCommandHandler.create(this)
handler.registerValueResolver(MinionType::class.java) { c ->
val type = c.popForParameter()
val minionType = MinionTypes.valueOf(type) ?: return@registerValueResolver MinionTypes.valueOf("collector")
return@registerValueResolver minionType
}
handler.autoCompleter.registerSuggestion("minionTypes") { _, _, _ ->
return@registerSuggestion MinionTypes.getMinionTypes().values.map { it.getName() }
}
handler.register(AxMinionsCommand())
handler.registerBrigadier()
}
private fun loadDataHandler() {
if (Config.DATABASE_TYPE().equals("H2", true)) {
dataHandler = H2DataHandler()
dataHandler.setup()
} else {
}
}
}

View File

@ -1,28 +1,58 @@
package com.artillexstudios.axminions.api
import com.artillexstudios.axapi.AxPlugin
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.config.Config
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.data.DataHandler
import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.minions.Minions
import org.bukkit.entity.Player
import java.io.File
class AxMinionsAPIImpl(private val plugin: AxMinionsPlugin) : AxMinionsAPI {
private val messages = Messages(File(getAxMinionsDataFolder(), "messages.yml"), plugin.getResource("messages.yml")!!)
private val config = Config(File(getAxMinionsDataFolder(), "config.yml"), plugin.getResource("config.yml")!!)
override fun getAxMinionsDataFolder(): File {
return plugin.dataFolder
}
override fun getMessages(): Messages {
return messages
return AxMinionsPlugin.messages
}
override fun getConfig(): Config {
return config
return AxMinionsPlugin.config
}
override fun getDataHandler(): DataHandler {
TODO("Not yet implemented")
return AxMinionsPlugin.dataHandler
}
override fun getMinions(): List<Minion> {
return Minions.getMinions()
}
override fun getAxMinionsInstance(): AxPlugin {
return plugin
}
override fun getMinionLimit(player: Player): Int {
var limit = Config.DEFAULT_MINION_LIMIT()
player.effectivePermissions.forEach {
val permission = it.permission
if (!permission.startsWith("axminions.limit.")) return@forEach
if (permission.contains("*")) {
return Int.MAX_VALUE
}
val value = permission.substring(permission.lastIndexOf('.') + 1).toInt()
if (value > limit) {
limit = value
}
}
return limit
}
}

View File

@ -0,0 +1,32 @@
package com.artillexstudios.axminions.commands
import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import revxrsal.commands.annotation.AutoComplete
import revxrsal.commands.annotation.Command
import revxrsal.commands.annotation.Default
import revxrsal.commands.annotation.Description
import revxrsal.commands.annotation.Range
import revxrsal.commands.annotation.Subcommand
import revxrsal.commands.bukkit.annotation.CommandPermission
@Command("axminions", "minion", "minions")
class AxMinionsCommand {
@Subcommand("give")
@CommandPermission("axminions.command.give")
@Description("Give a minion to a player")
@AutoComplete("* @minionTypes * *")
fun give(sender: CommandSender, @Default("me") receiver: Player, @Default("collector") minionType: MinionType, @Default("1") level: Int, @Default("1") @Range(min = 1.0, max = 64.0) amount: Int) {
receiver.inventory.addItem(minionType.getItem())
}
@Subcommand("reload")
@CommandPermission("axminions.command.reload")
@Description("Reload the configurations of the plugin")
fun reload(sender: CommandSender) {
}
}

View File

@ -3,10 +3,8 @@ package com.artillexstudios.axminions.data
import com.artillexstudios.axapi.serializers.Serializers
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.minions.Direction
import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.api.data.DataHandler
import com.artillexstudios.axminions.minions.MinionImpl
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.Material
@ -58,7 +56,7 @@ class H2DataHandler : DataHandler {
itemStack = Serializers.ITEM_STACK.deserialize(tool)
}
MinionImpl(
com.artillexstudios.axminions.minions.Minion(
Serializers.LOCATION.deserialize(location),
uuid,
ownerPlayer,
@ -74,7 +72,7 @@ class H2DataHandler : DataHandler {
}
}
override fun saveMinion(minion: Minion) {
override fun saveMinion(minion: com.artillexstudios.axminions.api.minions.Minion) {
connection.prepareStatement("MERGE INTO `axminions_data`(`location`, `owner`, `linked-chest-location`, `extra_data`, `direction`, `type`, `level`, `tool`) KEY(`location`) VALUES(?,?,?,?,?,?,?,?);")
.use { preparedStatement ->
preparedStatement.setString(1, Serializers.LOCATION.serialize(minion.getLocation()))
@ -96,7 +94,7 @@ class H2DataHandler : DataHandler {
}
}
override fun deleteMinion(minion: Minion) {
override fun deleteMinion(minion: com.artillexstudios.axminions.api.minions.Minion) {
connection.prepareStatement("DELETE FROM `axminions_data` WHERE `location` = ?;").use { preparedStatement ->
preparedStatement.setString(1, Serializers.LOCATION.serialize(minion.getLocation()))
preparedStatement.executeUpdate()

View File

@ -9,9 +9,12 @@ import com.artillexstudios.axminions.api.minions.Direction
import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.api.warnings.Warning
import com.artillexstudios.axminions.api.warnings.Warnings
import com.artillexstudios.axminions.utils.fastFor
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.OfflinePlayer
import org.bukkit.block.Container
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.EntityType
import org.bukkit.entity.Player
@ -21,7 +24,7 @@ import org.bukkit.util.EulerAngle
import java.util.UUID
import kotlin.math.roundToInt
class MinionImpl(
class Minion(
private val location: Location,
private val ownerUUID: UUID,
private val owner: OfflinePlayer,
@ -40,10 +43,13 @@ class MinionImpl(
private var warning: Warning? = null
private var hologram: Hologram? = null
private val extraData = hashMapOf<String, String>()
private var linkedInventory: Inventory? = null
init {
spawn()
loadExtraData(savedExtraData)
Minions.load(this)
linkedInventory = (linkedChest?.block?.blockData as? Container)?.inventory
}
override fun getType(): MinionType {
@ -54,14 +60,21 @@ class MinionImpl(
entity = PacketEntityFactory.get().spawnEntity(location, EntityType.ARMOR_STAND) as PacketArmorStand
entity.setHasBasePlate(false)
entity.setSmall(true)
entity.onClick { event ->
if (event.isAttack) {
println("LEFT CLICKED!")
} else {
println("RIGHT CLICKED!")
}
}
}
override fun tick() {
if (dirty) {
dirty = false
range = type.getConfig().get("range", 0.0)
range = type.getDouble("range", level)
val efficiency = 1.0 - (getTool()?.getEnchantmentLevel(Enchantment.DIG_SPEED)?.div(10.0) ?: 0.1)
nextAction = (type.getConfig().get("speed", 0L) * efficiency).roundToInt()
nextAction = (type.getLong("speed", level) * efficiency).roundToInt()
}
type.tick(this)
@ -73,15 +86,15 @@ class MinionImpl(
}
override fun updateInventory(inventory: Inventory) {
TODO("Not yet implemented")
}
override fun openInventory(player: Player) {
TODO("Not yet implemented")
}
override fun getAsItem(): ItemStack {
TODO("Not yet implemented")
return ItemStack(Material.STONE)
}
override fun getLevel(): Int {
@ -166,6 +179,7 @@ class MinionImpl(
override fun setLinkedChest(location: Location?) {
this.linkedChest = location?.clone()
linkedInventory = (linkedChest?.block?.blockData as? Container)?.inventory
}
override fun getLinkedChest(): Location? {
@ -194,6 +208,30 @@ class MinionImpl(
return this.direction
}
override fun remove() {
Warnings.remove(this)
Minions.remove(this)
entity.remove()
}
override fun getLinkedInventory(): Inventory? {
return linkedInventory
}
override fun addToContainerOrDrop(itemStack: ItemStack) {
val remaining = linkedInventory?.addItem(itemStack)
remaining?.forEach { (_, u) ->
location.world?.dropItem(location, u)
}
}
override fun addToContainerOrDrop(itemStack: Iterable<ItemStack>) {
itemStack.forEach {
addToContainerOrDrop(it)
}
}
private fun loadExtraData(data: String) {
data.split("|").fastFor { split ->
val secondSplit = split.split("=")

View File

@ -1,5 +1,7 @@
package com.artillexstudios.axminions.minions
import com.artillexstudios.axapi.scheduler.Scheduler
object MinionTicker {
private var tick = 0L
@ -9,6 +11,12 @@ object MinionTicker {
tick++
}
fun startTicking() {
Scheduler.get().runTimer({ task ->
}, 0, 0)
}
fun getTick(): Long {
return this.tick
}

View File

@ -0,0 +1,20 @@
package com.artillexstudios.axminions.minions
import com.artillexstudios.axminions.api.minions.Minion
import java.util.Collections
object Minions {
private val entities = mutableListOf<Minion>()
fun load(minion: Minion) {
entities.add(minion)
}
fun remove(minion: Minion) {
entities.remove(minion)
}
fun getMinions(): List<Minion> {
return Collections.unmodifiableList(entities)
}
}

View File

@ -5,7 +5,7 @@ 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 org.bukkit.block.Container
import org.bukkit.Material
import org.bukkit.entity.Item
class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.getResource("minions/collector.yml")!!) {
@ -21,8 +21,14 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
return
}
val state = minion.getLinkedChest()?.block?.state
if (state !is Container) {
val type = minion.getLinkedChest()!!.block.type
if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL && !type.name.lowercase().contains("shulker_box")) {
Warnings.NO_CONTAINER.display(minion)
minion.setLinkedChest(null)
return
}
if (minion.getLinkedInventory() == null) {
Warnings.NO_CONTAINER.display(minion)
minion.setLinkedChest(null)
return
@ -38,7 +44,7 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
)
entities?.filterIsInstance<Item>()?.forEach { item ->
if (state.inventory.firstEmpty() == -1) {
if (minion.getLinkedInventory()?.firstEmpty() == -1) {
Warnings.CONTAINER_FULL.display(minion)
return
}

View File

@ -3,10 +3,42 @@ package com.artillexstudios.axminions.minions.miniontype
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import com.artillexstudios.axminions.utils.LocationUtils
import com.artillexstudios.axminions.utils.fastFor
import org.bukkit.Material
import org.bukkit.block.data.Ageable
import org.bukkit.inventory.ItemStack
class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResource("minions/farmer.yml")!!) {
override fun run(minion: Minion) {
TODO("Not yet implemented")
LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location ->
val block = location.block
val drops = arrayListOf<ItemStack>()
when (block.type) {
Material.CACTUS, Material.SUGAR_CANE, Material.BAMBOO, Material.MELON, Material.PUMPKIN -> {
drops.addAll(block.getDrops(minion.getTool()))
block.type = Material.AIR
}
Material.COCOA_BEANS, Material.COCOA, Material.NETHER_WART, Material.WHEAT, Material.CARROTS, Material.BEETROOTS, Material.POTATOES -> {
val ageable = block.blockData as Ageable
if (ageable.age != ageable.maximumAge) return@fastFor
drops.addAll(block.getDrops(minion.getTool()))
ageable.age = 0
block.blockData = ageable
}
Material.SWEET_BERRY_BUSH -> {
val ageable = block.blockData as Ageable
if (ageable.age != ageable.maximumAge) return@fastFor
drops.addAll(block.getDrops(minion.getTool()))
ageable.age = 1
block.blockData = ageable
}
else -> return@fastFor
}
minion.addToContainerOrDrop(drops)
}
}
}

View File

@ -3,10 +3,11 @@ package com.artillexstudios.axminions.minions.miniontype
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.api.minions.miniontype.MinionType
import org.bukkit.loot.LootTables
class FisherMinionType : MinionType("fisher", AxMinionsPlugin.INSTANCE.getResource("minions/fisher.yml")!!) {
override fun run(minion: Minion) {
TODO("Not yet implemented")
}
}

View File

@ -7,6 +7,6 @@ import com.artillexstudios.axminions.api.minions.miniontype.MinionType
class LumberMinionType : MinionType("lumber", AxMinionsPlugin.INSTANCE.getResource("minions/lumber.yml")!!) {
override fun run(minion: Minion) {
TODO("Not yet implemented")
}
}

View File

@ -7,6 +7,6 @@ import com.artillexstudios.axminions.api.minions.miniontype.MinionType
class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource("minions/miner.yml")!!) {
override fun run(minion: Minion) {
TODO("Not yet implemented")
}
}

View File

@ -7,6 +7,6 @@ import com.artillexstudios.axminions.api.minions.miniontype.MinionType
class SellerMinionType : MinionType("seller", AxMinionsPlugin.INSTANCE.getResource("minions/seller.yml")!!) {
override fun run(minion: Minion) {
TODO("Not yet implemented")
}
}

View File

@ -7,6 +7,6 @@ import com.artillexstudios.axminions.api.minions.miniontype.MinionType
class SlayerMinionType : MinionType("slayer", AxMinionsPlugin.INSTANCE.getResource("minions/slayer.yml")!!) {
override fun run(minion: Minion) {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,36 @@
package com.artillexstudios.axminions.utils
import org.bukkit.Location
object LocationUtils {
@JvmStatic
fun getAllBlocksInRadius(location: Location, radius: Double, filterEmpty: Boolean): ArrayList<Location> {
// Approximate the volume of the sphere
val blocks = ArrayList<Location>((2 * radius * radius * radius).toInt())
val blockX = location.blockX
val blockY = location.blockY
val blockZ = location.blockZ
val rangeX = (blockX - radius).rangeTo((blockX + radius)).step(1.0)
val rangeY = (blockY - radius).rangeTo((blockY + radius)).step(1.0)
val rangeZ = (blockZ - radius).rangeTo((blockZ + radius)).step(1.0)
val radiusSquared = radius * radius
val smallRadiusSquared = (radius - 1) * (radius -1)
for (x in rangeX) {
for (y in rangeY) {
for (z in rangeZ) {
val distance = ((blockX - x) * (blockX - x) + ((blockZ - z) * (blockZ - z)) + ((blockY - y) * (blockY - y)))
if (distance < radiusSquared && !(filterEmpty && distance < smallRadiusSquared)) {
blocks.add(Location(location.world, x, y, z))
}
}
}
}
return blocks
}
}

View File

@ -0,0 +1,16 @@
package com.artillexstudios.axminions.utils
// Thanks a lot to this hero! https://stackoverflow.com/a/44332139
infix fun ClosedRange<Double>.step(step: Double): Iterable<Double> {
require(start.isFinite())
require(endInclusive.isFinite())
require(step > 0.0) { "Step must be positive, was: $step." }
val sequence = generateSequence(start) { previous ->
if (previous == Double.POSITIVE_INFINITY) return@generateSequence null
val next = previous + step
if (next > endInclusive) null else next
}
return sequence.asIterable()
}

View File

@ -10,7 +10,7 @@ tool:
- "NETHERITE_SHOVEL"
item:
material: "player_head"
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2UzZDM2MzVjZTQxMWFiZjFlNGYzNzNkMTYxZDA3YjhjNDdlMzU5YjZjNTZmNzRiNDEzY2I0OTRhYzc0NmUyZCJ9fX0="
name: "<#FFEE00>Collector <white>Minion"
lore:
@ -25,7 +25,7 @@ item:
gui:
upgrade:
material: "gold_ingot"
type: "gold_ingot"
name: "<#00CCFF><b>Upgrade minion"
lore:
- ""
@ -39,7 +39,7 @@ gui:
- ""
- "<#00CCFF><b>(!)</b> Click here to upgrade your minion!"
statistics:
material: "paper"
type: "paper"
name: "<#FFEE00><b>Statistics"
lore:
- ""
@ -52,18 +52,18 @@ upgrades:
speed: 160
items:
helmet:
material: "player_head"
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2UzZDM2MzVjZTQxMWFiZjFlNGYzNzNkMTYxZDA3YjhjNDdlMzU5YjZjNTZmNzRiNDEzY2I0OTRhYzc0NmUyZCJ9fX0="
chestplate:
material: "leather_chestplate"
type: "leather_chestplate"
color: "255, 230, 0"
glow: false
leggings:
material: "leather_leggings"
type: "leather_leggings"
color: "255, 230, 0"
glow: false
boots:
material: "leather_boots"
type: "leather_boots"
color: "255, 230, 0"
glow: false
2:
@ -118,14 +118,14 @@ upgrades:
actions: 50000
items:
chestplate:
material: LEATHER_CHESTPLATE
type: LEATHER_CHESTPLATE
color: "255, 200, 0"
glow: true
leggings:
material: LEATHER_LEGGINGS
type: LEATHER_LEGGINGS
color: "255, 200, 0"
glow: true
boots:
material: LEATHER_BOOTS
type: LEATHER_BOOTS
color: "255, 200, 0"
glow: true

View File

@ -0,0 +1,135 @@
name: "<level_color>[<level>] <#33FF33>Farmer <white>Minion <gray>[<owner>]"
tool:
material:
- "WOODEN_HOE"
- "STONE_HOE"
- "GOLDEN_HOE"
- "IRON_HOE"
- "DIAMOND_HOE"
- "NETHERITE_HOE"
item:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDAxZTAzNWEzZDhkNjEyNjA3MmJjYmU1MmE5NzkxM2FjZTkzNTUyYTk5OTk1YjVkNDA3MGQ2NzgzYTMxZTkwOSJ9fX0="
name: "<#33FF33>Collector <white>Minion"
lore:
- ""
- " <gray>- <white>Harvests and replants nearby crops."
- ""
- "<#33FF33>Statistics"
- " <#33FF33>❙ <white>Level: <#AAFFAA><level>"
- " <#33FF33>❙ <white>Harvested crops: <#AAFFAA><items>"
- ""
- "<#33FF33><b>(!)</b> Place the minion and give it a hoe!"
gui:
upgrade:
type: "gold_ingot"
name: "<#00CCFF><b>Upgrade minion"
lore:
- ""
- " <gray>- <white>Level: <green><current_level> » <dark_green><next_level>"
- " <gray>- <white>Range: <green><current_range> » <dark_green><next_range>"
- " <gray>- <white>Speed: <green><current_speed> » <dark_green><next_speed>"
- ""
- "<#00CCFF>Requirements:"
- " <gray>- <white>Money: <#33FF33><price>$"
- " <gray>- <white>Crops harvested: <#33FF33><required_actions>"
- ""
- "<#00CCFF><b>(!)</b> Click here to upgrade your minion!"
statistics:
type: "paper"
name: "<#33FF33><b>Statistics"
lore:
- ""
- " <gray>- <white>Crops harvested: <#33FF33><statistic_collected>"
- ""
upgrades:
1:
range: 2
speed: 200
items:
helmet:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDAxZTAzNWEzZDhkNjEyNjA3MmJjYmU1MmE5NzkxM2FjZTkzNTUyYTk5OTk1YjVkNDA3MGQ2NzgzYTMxZTkwOSJ9fX0="
chestplate:
type: "leather_chestplate"
color: "50, 255, 50"
glow: false
leggings:
type: "leather_leggings"
color: "50, 255, 50"
glow: false
boots:
type: "leather_boots"
color: "50, 255, 50"
glow: false
2:
range: 2.5
speed: 190
requirements:
money: 1000
actions: 10
3:
range: 3
speed: 180
requirements:
money: 3000
actions: 30
4:
range: 3.5
speed: 170
requirements:
money: 10000
actions: 100
5:
range: 3.5
speed: 160
requirements:
money: 20000
actions: 300
6:
range: 4
speed: 150
requirements:
money: 50000
actions: 600
7:
range: 4.5
speed: 140
requirements:
money: 150000
actions: 1000
8:
range: 5
speed: 120
requirements:
money: 500000
actions: 1750
9:
range: 5.5
speed: 110
requirements:
money: 1000000
actions: 25000
10:
range: 6
speed: 100
requirements:
money: 5000000
actions: 5000
items:
chestplate:
type: LEATHER_CHESTPLATE
color: "50, 225, 50"
glow: true
leggings:
type: LEATHER_LEGGINGS
color: "50, 225, 50"
glow: true
boots:
type: LEATHER_BOOTS
color: "50, 225, 50"
glow: true

View File

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

Binary file not shown.