So much work, nms & stuff

This commit is contained in:
TomTom 2023-10-15 17:29:21 +02:00
parent 14a7db9c38
commit 2bb47ffae7
43 changed files with 1280 additions and 61 deletions

View File

@ -10,6 +10,8 @@
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/api" />
<option value="$PROJECT_DIR$/common" />
<option value="$PROJECT_DIR$/nms" />
<option value="$PROJECT_DIR$/nms/v1_20_R1" />
</set>
</option>
</GradleProjectSettings>

View File

@ -12,6 +12,7 @@ import java.io.InputStream
class Config(file: File, stream: InputStream) {
companion object {
private var debug: Boolean? = null
@JvmStatic
fun AUTO_SAVE_MINUTES() = AxMinionsAPI.INSTANCE.getConfig().get("autosave-minutes", 3L)
@JvmStatic
@ -39,7 +40,13 @@ class Config(file: File, stream: InputStream) {
@JvmStatic
fun GUI_SIZE() = AxMinionsAPI.INSTANCE.getConfig().get<Int>("gui.size")
@JvmStatic
fun DEBUG() = AxMinionsAPI.INSTANCE.getConfig().get<Boolean>("debug")
fun DEBUG(): Boolean {
if (debug === null) {
debug = AxMinionsAPI.INSTANCE.getConfig().get("debug", false)
}
return debug ?: false
}
}
private val config = Config(

View File

@ -47,6 +47,14 @@ class Messages(file: File, stream: InputStream) {
fun WRONG_TOOL() = AxMinionsAPI.INSTANCE.getMessages().get<String>("tools.wrong-tool")
@JvmStatic
fun ERROR_INVENTORY_FULL() = AxMinionsAPI.INSTANCE.getMessages().get<String>("errors.inventory-full")
@JvmStatic
fun LINK_SUCCESS() = AxMinionsAPI.INSTANCE.getMessages().get<String>("link.success")
@JvmStatic
fun LINK_UNLINK() = AxMinionsAPI.INSTANCE.getMessages().get<String>("link.unlink")
@JvmStatic
fun LINK_FAIL() = AxMinionsAPI.INSTANCE.getMessages().get<String>("link.fail")
@JvmStatic
fun LINK_START() = AxMinionsAPI.INSTANCE.getMessages().get<String>("link.start")
}
private val config = Config(

View File

@ -0,0 +1,30 @@
package com.artillexstudios.axminions.api.events
import com.artillexstudios.axminions.api.minions.Minion
import org.bukkit.entity.LivingEntity
import org.bukkit.event.Cancellable
import org.bukkit.event.HandlerList
class MinionDamageEntityEvent(minion: Minion, val target: LivingEntity, val damage: Double) : MinionEvent(minion), Cancellable {
companion object {
private val handlerList = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList = handlerList
}
private var isCancelled = false
override fun getHandlers(): HandlerList {
return handlerList
}
override fun isCancelled(): Boolean {
return isCancelled
}
override fun setCancelled(cancelled: Boolean) {
isCancelled = cancelled
}
}

View File

@ -0,0 +1,6 @@
package com.artillexstudios.axminions.api.events
import com.artillexstudios.axminions.api.minions.Minion
import org.bukkit.event.Event
abstract class MinionEvent(val minion: Minion) : Event()

View File

@ -9,9 +9,9 @@ interface Integrations {
fun getStackerIntegration(): StackerIntegration
fun getPricesIntegration(): PricesIntegration
fun getPricesIntegration(): PricesIntegration?
fun getEconomyIntegration(): EconomyIntegration
fun getEconomyIntegration(): EconomyIntegration?
fun getProtectionIntegration(): ProtectionIntegrations

View File

@ -24,8 +24,6 @@ interface Minion : InventoryHolder {
fun updateInventories()
fun updateInventory(inventory: Inventory)
fun openInventory(player: Player)
fun getAsItem(): ItemStack

View File

@ -8,6 +8,7 @@ inline fun <T> Array<T>.fastFor(action: (T) -> Unit) {
}
inline fun <T> List<T>.fastFor(action: (T) -> Unit) {
if (isEmpty()) return
val indices = indices
for (i in indices) {
action(get(i))

View File

@ -29,9 +29,11 @@ object Warnings {
}
@JvmStatic
fun remove(minion: Minion) {
minion.getWarningHologram()?.remove()
minion.setWarningHologram(null)
minion.setWarning(null)
fun remove(minion: Minion, warning: Warning) {
if (minion.getWarning() == warning) {
minion.getWarningHologram()?.remove()
minion.setWarningHologram(null)
minion.setWarning(null)
}
}
}

View File

@ -20,6 +20,7 @@ repositories {
dependencies {
implementation project(path: ":api")
implementation project(path: ":common")
implementation project(path: ":nms:v1_20_R1", configuration: "reobf")
}
allprojects {
@ -110,6 +111,9 @@ allprojects {
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')
// compileOnly files('../libs/CMI-API9.5.0.8.jar')
// compileOnly files('../libs/IridiumSkyblock-3.2.12.jar')
// compileOnly files('../libs/KingdomsX-1.16.12.jar')
}
shadowJar {

View File

@ -17,13 +17,17 @@ import com.artillexstudios.axminions.data.H2DataHandler
import com.artillexstudios.axminions.integrations.Integrations
import com.artillexstudios.axminions.listeners.ChunkListener
import com.artillexstudios.axminions.listeners.LinkingListener
import com.artillexstudios.axminions.listeners.MinionDamageListener
import com.artillexstudios.axminions.listeners.MinionInventoryListener
import com.artillexstudios.axminions.listeners.MinionPlaceListener
import com.artillexstudios.axminions.minions.MinionTicker
import com.artillexstudios.axminions.minions.miniontype.CollectorMinionType
import com.artillexstudios.axminions.minions.miniontype.FarmerMinionType
import com.artillexstudios.axminions.minions.miniontype.FisherMinionType
import com.artillexstudios.axminions.minions.miniontype.LumberMinionType
import com.artillexstudios.axminions.minions.miniontype.MinerMinionType
import com.artillexstudios.axminions.minions.miniontype.SellerMinionType
import com.artillexstudios.axminions.minions.miniontype.SlayerMinionType
import org.bukkit.Bukkit
import java.io.File
@ -65,6 +69,9 @@ class AxMinionsPlugin : AxPlugin() {
it.register(FarmerMinionType())
it.register(MinerMinionType())
it.register(LumberMinionType())
it.register(SellerMinionType())
it.register(FisherMinionType())
it.register(SlayerMinionType())
}
val handler = BukkitCommandHandler.create(this)
@ -84,12 +91,15 @@ class AxMinionsPlugin : AxPlugin() {
handler.register(AxMinionsCommand())
handler.registerBrigadier()
if (handler.isBrigadierSupported) {
handler.registerBrigadier()
}
Bukkit.getPluginManager().registerEvents(MinionPlaceListener(), this)
Bukkit.getPluginManager().registerEvents(LinkingListener(), this)
Bukkit.getPluginManager().registerEvents(MinionInventoryListener(), this)
Bukkit.getPluginManager().registerEvents(ChunkListener(), this)
Bukkit.getPluginManager().registerEvents(MinionDamageListener(), this)
MinionTicker.startTicking()
}
@ -102,8 +112,6 @@ class AxMinionsPlugin : AxPlugin() {
if (Config.DATABASE_TYPE().equals("H2", true)) {
dataHandler = H2DataHandler()
dataHandler.setup()
} else {
}
}
}

View File

@ -0,0 +1,6 @@
package com.artillexstudios.axminions.converter
interface Converter {
fun convert();
}

View File

@ -0,0 +1,8 @@
package com.artillexstudios.axminions.converter
class JetsMinionsConverter : Converter {
override fun convert() {
TODO("Not yet implemented")
}
}

View File

@ -0,0 +1,79 @@
package com.artillexstudios.axminions.converter
import com.artillexstudios.axapi.serializers.Serializers
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.api.minions.Direction
import java.sql.Connection
import java.sql.DriverManager
import java.util.Locale
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
class LitMinionsConverter : Converter {
private lateinit var connection: Connection
override fun convert() {
Bukkit.getConsoleSender()
.sendMessage(StringUtils.formatToString("<#33FF33>[AxMinions-Converter] <white>Converting from <green>LitMinions..."))
val url = "jdbc:sqlite:" + "plugins/LitMinions/minions.db"
try {
connection = DriverManager.getConnection(url) ?: return
} catch (exception: Exception) {
Bukkit.getConsoleSender()
.sendMessage(StringUtils.formatToString("<#33FF33>[AxMinions-Converter] <#FF0000>FAILED! Database not found, or corrupted!"))
return
}
connection.use {
connection.prepareStatement("SELECT * FROM `minions_data`").use { preparedStatement ->
preparedStatement.executeQuery().use { resultSet ->
while (resultSet.next()) {
// Bukkit.getConsoleSender().sendMessage(
// StringUtils.formatToString(
//// "&#DDDDDD[AxMinions-Converter] Converting: " + resultSet.getString("minionworld") + ";" + rs.getDouble(
// "minionx"
// ) + ";" + resultSet.getDouble("miniony") + ";" + resultSet.getDouble("minionz")
// )
// )
/* val location =
resultSet.getString("minionworld") + ";" + resultSet.getDouble("minionx") + ";" + resultSet.getDouble(
"miniony"*//**//*
// ) + ";" + rs.getDouble(
"minionz"
)*/
val direction: Direction =
Direction.valueOf(resultSet.getString("minionface").uppercase(Locale.ENGLISH))
val level = resultSet.getInt("level")
val type = resultSet.getString("miniontype").uppercase(Locale.getDefault())
val owner = resultSet.getString("owner")
val storage = resultSet.getDouble("exp")
val statistic = resultSet.getLong("stat")
val linkedChest = "${resultSet.getString("chestworld")};${resultSet.getDouble("chestx")};${
resultSet.getDouble("chesty")
};${resultSet.getDouble("chestz")};0;0"
var linkedChestLoc: Location? = null
if (resultSet.getString("chestworld") != null) {
linkedChestLoc = Serializers.LOCATION.deserialize(linkedChest)
}
val it = ItemStack(Material.AIR)
// val locationId = AxMinionsPlugin.dataHandler.getLocationID(location)
// val minion = Minion(location, owner, Bukkit.getOfflinePlayer(owner), minionType, 1, ItemStack(Material.AIR), null, Direction.NORTH, 0, 0.0, locationId, 0)
// minion.setLevel(level)
// minion.setActions(stats)
// minion.setTicking(true)
}
}
}
}
}
}

View File

@ -18,6 +18,8 @@ import com.artillexstudios.axminions.integrations.prices.EssentialsIntegration
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.IridiumSkyBlockIntegration
import com.artillexstudios.axminions.integrations.protection.KingdomsXIntegration
import com.artillexstudios.axminions.integrations.protection.LandsIntegration
import com.artillexstudios.axminions.integrations.protection.SuperiorSkyBlock2Integration
import com.artillexstudios.axminions.integrations.protection.WorldGuardIntegration
@ -29,19 +31,19 @@ import org.bukkit.Bukkit
class Integrations : Integrations {
private lateinit var stackerIntegration: StackerIntegration
private lateinit var pricesIntegration: PricesIntegration
private lateinit var economyIntegration: EconomyIntegration
private var pricesIntegration: PricesIntegration? = null
private var economyIntegration: EconomyIntegration? = null
private val protectionIntegrations = com.artillexstudios.axminions.integrations.protection.ProtectionIntegrations()
override fun getStackerIntegration(): StackerIntegration {
return stackerIntegration
}
override fun getPricesIntegration(): PricesIntegration {
override fun getPricesIntegration(): PricesIntegration? {
return pricesIntegration
}
override fun getEconomyIntegration(): EconomyIntegration {
override fun getEconomyIntegration(): EconomyIntegration? {
return economyIntegration
}
@ -133,6 +135,14 @@ class Integrations : Integrations {
if (Bukkit.getPluginManager().getPlugin("Lands") != null) {
register(LandsIntegration())
}
if (Bukkit.getPluginManager().getPlugin("IridiumSkyBlock") != null) {
register(IridiumSkyBlockIntegration())
}
if (Bukkit.getPluginManager().getPlugin("KingdomsX") != null) {
register(KingdomsXIntegration())
}
}
override fun register(integration: Integration) {

View File

@ -1,15 +1,21 @@
package com.artillexstudios.axminions.integrations.prices
import com.Zrips.CMI.CMI
import com.artillexstudios.axminions.api.integrations.types.PricesIntegration
import org.bukkit.inventory.ItemStack
class CMIIntegration : PricesIntegration {
private lateinit var manager: CMI
override fun getPrice(itemStack: ItemStack): Double {
TODO("Not yet implemented")
val worth = manager.worthManager.getWorth(itemStack) ?: return -1.0
return if (worth.sellPrice == 0.0) -1.0 else worth.sellPrice
}
override fun register() {
TODO("Not yet implemented")
manager = CMI.getInstance();
}
}

View File

@ -0,0 +1,19 @@
package com.artillexstudios.axminions.integrations.protection
import com.artillexstudios.axminions.api.integrations.types.ProtectionIntegration
import com.iridium.iridiumskyblock.api.IridiumSkyblockAPI
import org.bukkit.Location
import org.bukkit.entity.Player
class IridiumSkyBlockIntegration : ProtectionIntegration {
override fun canBuildAt(player: Player, location: Location): Boolean {
val island = IridiumSkyblockAPI.getInstance().getIslandViaLocation(location)
return island.map { IridiumSkyblockAPI.getInstance().getUser(player) in it.members }.orElse(true)
}
override fun register() {
}
}

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 org.kingdoms.constants.land.Land
import org.kingdoms.constants.player.KingdomPlayer
class KingdomsXIntegration : ProtectionIntegration {
override fun canBuildAt(player: Player, location: Location): Boolean {
val localPlayer = KingdomPlayer.getKingdomPlayer(player.uniqueId);
val land = Land.getLand(location) ?: return true
return land.kingdom.isMember(localPlayer);
}
override fun register() {
}
}

View File

@ -1,6 +1,9 @@
package com.artillexstudios.axminions.listeners
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.config.Config
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.minions.Minion
import java.util.UUID
import org.bukkit.Material
@ -19,17 +22,18 @@ class LinkingListener : Listener {
if (event.player.uniqueId !in linking) return
if (event.clickedBlock == null) return
if (event.clickedBlock!!.type !in CONTAINERS) return
// TODO Check if player can build at location
if (!AxMinionsPlugin.integrations.getProtectionIntegration().canBuildAt(event.player, event.clickedBlock!!.location)) return
val minion = linking.remove(event.player.uniqueId) ?: return
event.isCancelled = true
if (minion.getLocation()
.distanceSquared(event.clickedBlock!!.location) > Config.MAX_LINKING_DISTANCE() * Config.MAX_LINKING_DISTANCE()
) {
// TODO Send too far message
event.player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_FAIL()))
return
}
event.player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_SUCCESS()))
minion.setLinkedChest(event.clickedBlock!!.location)
}
}

View File

@ -0,0 +1,19 @@
package com.artillexstudios.axminions.listeners
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.events.MinionDamageEntityEvent
import java.util.concurrent.ThreadLocalRandom
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
class MinionDamageListener : Listener {
@EventHandler
fun onMinionDamageEntityEvent(event: MinionDamageEntityEvent) {
if (event.damage < event.target.health) return
val entitySize = AxMinionsPlugin.integrations.getStackerIntegration().getStackSize(event.target)
event.minion.setStorage(event.minion.getStorage() + ThreadLocalRandom.current().nextInt(1, 4) * entitySize)
}
}

View File

@ -66,7 +66,7 @@ class MinionInventoryListener : Listener {
event.currentItem!!.amount = 0
}
minion.updateInventory(event.inventory)
minion.updateInventories()
return
}
@ -85,7 +85,7 @@ class MinionInventoryListener : Listener {
tool.setItemMeta(toolMeta)
player.inventory.addItem(tool)
minion.updateInventory(event.inventory)
minion.updateInventories()
return
}
@ -110,15 +110,16 @@ class MinionInventoryListener : Listener {
"link" -> {
if (minion.getLinkedChest() != null) {
minion.setLinkedChest(null)
// TODO Unlink message
player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_UNLINK()))
return
}
player.sendMessage(StringUtils.formatToString(Messages.PREFIX() + Messages.LINK_START()))
LinkingListener.linking[player.uniqueId] = minion
}
}
minion.updateInventory(event.inventory)
minion.updateInventories()
}
@EventHandler

View File

@ -5,6 +5,7 @@ import com.artillexstudios.axapi.scheduler.Scheduler
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.AxMinionsPlugin
import com.artillexstudios.axminions.api.AxMinionsAPI
import com.artillexstudios.axminions.api.config.Config
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.minions.Direction
import com.artillexstudios.axminions.api.minions.miniontype.MinionTypes
@ -53,15 +54,16 @@ class MinionPlaceListener : Listener {
}
val locationId = AxMinionsPlugin.dataHandler.getLocationID(location)
Scheduler.get().run {
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)
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)
if (Config.DEBUG()) {
event.player.sendMessage("Placed minion $minion. Ticking? ${minion.isTicking()} Is chunk ticking? ${Minions.isTicking(location.chunk)}")
AxMinionsPlugin.dataHandler.saveMinion(minion)
}
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())))
}
}

View File

@ -3,6 +3,7 @@ package com.artillexstudios.axminions.minions
import com.artillexstudios.axapi.entity.PacketEntityFactory
import com.artillexstudios.axapi.entity.impl.PacketArmorStand
import com.artillexstudios.axapi.entity.impl.PacketEntity
import com.artillexstudios.axapi.events.PacketEntityInteractEvent
import com.artillexstudios.axapi.hologram.Hologram
import com.artillexstudios.axapi.hologram.HologramFactory
import com.artillexstudios.axapi.libs.kyori.adventure.text.minimessage.tag.resolver.Placeholder
@ -99,8 +100,16 @@ class Minion(
updateArmour()
entity.onClick { event ->
if (event.isAttack) {
println("LEFT CLICKED!")
// if (ownerUUID == event.player.uniqueId && Config.ONLY_OWNER_BREAK()) {
// breakMinion(event)
// } else if (AxMinionsPlugin.integrations.getProtectionIntegration().canBuildAt(event.player, event.packetEntity.location)) {
breakMinion(event)
// }
} else {
/* if (ownerUUID == event.player.uniqueId || AxMinionsPlugin.integrations.getProtectionIntegration().canBuildAt(event.player, event.packetEntity.location)) {
}*/
Scheduler.get().run {
openInventory(event.player)
}
@ -108,6 +117,18 @@ class Minion(
}
}
private fun breakMinion(event: PacketEntityInteractEvent) {
setTicking(false)
val tool = getTool()
val asItem = getAsItem()
val remaining = event.player.inventory.addItem(tool, asItem)
remove()
remaining.forEach { (_, i) ->
AxMinionsPlugin.integrations.getStackerIntegration().dropItemAt(i, i.amount, location)
}
}
override fun tick() {
if (dirty) {
dirty = false
@ -132,7 +153,7 @@ class Minion(
}
}
override fun updateInventory(inventory: Inventory) {
private fun updateInventory(inventory: Inventory) {
AxMinionsAPI.INSTANCE.getConfig().getConfig().getSection("gui.items").getRoutesAsStrings(false).forEach {
if (it.equals("filler")) return@forEach
val item: ItemStack
@ -284,6 +305,8 @@ class Minion(
override fun setLevel(level: Int) {
this.level = level
updateArmour()
updateInventories()
entity.name = StringUtils.format(
type.getConfig().get("entity.name"),
@ -361,9 +384,13 @@ class Minion(
}
override fun remove() {
Warnings.remove(this)
Warnings.remove(this, warning ?: Warnings.NO_CONTAINER)
Minions.remove(this)
entity.remove()
AxMinionsPlugin.dataQueue.submit {
AxMinionsPlugin.dataHandler.deleteMinion(this)
}
}
override fun getLinkedInventory(): Inventory? {
@ -457,6 +484,7 @@ class Minion(
} else {
meta.damage += amount
tool?.itemMeta = meta
updateInventories()
}
}

View File

@ -42,14 +42,14 @@ class CollectorMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.get
return
}
Warnings.remove(minion)
Warnings.remove(minion, Warnings.NO_CONTAINER)
if (!minion.canUseTool()) {
Warnings.NO_TOOL.display(minion)
return
}
Warnings.remove(minion)
Warnings.remove(minion, Warnings.NO_TOOL)
val entities = minion.getLocation().world?.getNearbyEntities(
minion.getLocation(),

View File

@ -44,7 +44,7 @@ class FarmerMinionType : MinionType("farmer", AxMinionsPlugin.INSTANCE.getResour
return
}
Warnings.remove(minion)
Warnings.remove(minion, Warnings.NO_TOOL)
LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location ->
val block = location.block

View File

@ -3,11 +3,68 @@ 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
import com.artillexstudios.axminions.api.utils.LocationUtils
import com.artillexstudios.axminions.api.utils.fastFor
import com.artillexstudios.axminions.api.warnings.Warnings
import com.artillexstudios.axminions.minions.MinionTicker
import com.artillexstudios.axminions.nms.NMSHandler
import java.util.concurrent.ThreadLocalRandom
import kotlin.math.roundToInt
import org.bukkit.Material
import org.bukkit.enchantments.Enchantment
class FisherMinionType : MinionType("fisher", AxMinionsPlugin.INSTANCE.getResource("minions/fisher.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.LURE)?.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)
}
var hasWater = false
run breaking@{
LocationUtils.getAllBlocksInRadius(minion.getLocation(), 2.0, false).fastFor {
if (it.block.type != Material.WATER) return@fastFor
hasWater = true
return@breaking
}
}
if (!hasWater) {
Warnings.NO_WATER_NEARBY.display(minion)
return
}
Warnings.remove(minion, Warnings.NO_WATER_NEARBY)
if (!minion.canUseTool()) {
Warnings.NO_TOOL.display(minion)
return
}
Warnings.remove(minion, Warnings.NO_TOOL)
val loot = NMSHandler.get().generateRandomFishingLoot(minion)
val xp = ThreadLocalRandom.current().nextInt(6) + 1
minion.addToContainerOrDrop(loot)
minion.setStorage(minion.getStorage() + xp)
}
}

View File

@ -44,7 +44,7 @@ class LumberMinionType : MinionType("lumber", AxMinionsPlugin.INSTANCE.getResour
return
}
Warnings.remove(minion)
Warnings.remove(minion, Warnings.NO_TOOL)
val loot = ArrayList<ItemStack>()
LocationUtils.getAllBlocksInRadius(minion.getLocation(), minion.getRange(), false).fastFor { location ->

View File

@ -49,7 +49,7 @@ class MinerMinionType : MinionType("miner", AxMinionsPlugin.INSTANCE.getResource
return
}
Warnings.remove(minion)
Warnings.remove(minion, Warnings.NO_TOOL)
when (getConfig().getString("mode").lowercase(Locale.ENGLISH)) {
"sphere" -> {

View File

@ -3,10 +3,81 @@ 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.api.warnings.Warnings
import com.artillexstudios.axminions.minions.MinionTicker
import kotlin.math.roundToInt
import org.bukkit.Material
import org.bukkit.enchantments.Enchantment
class SellerMinionType : MinionType("seller", AxMinionsPlugin.INSTANCE.getResource("minions/seller.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) {
Warnings.NO_CONTAINER.display(minion)
return
}
val type = minion.getLinkedChest()!!.block.type
if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) {
Warnings.NO_CONTAINER.display(minion)
minion.setLinkedChest(null)
return
}
if (minion.getLinkedInventory() == null) {
Warnings.NO_CONTAINER.display(minion)
minion.setLinkedChest(null)
return
}
Warnings.remove(minion, Warnings.NO_CONTAINER)
if (!minion.canUseTool()) {
Warnings.NO_TOOL.display(minion)
return
}
Warnings.remove(minion, Warnings.NO_TOOL)
if (AxMinionsPlugin.integrations.getPricesIntegration() === null) {
return
}
for (it in minion.getLinkedInventory()!!.contents) {
if (it == null || it.type == Material.AIR) {
continue
}
var price = AxMinionsPlugin.integrations.getPricesIntegration()!!.getPrice(it)
if (price == -1.0) {
if (getConfig().get("delete-unsellable")) {
it.amount = 0
}
continue
}
price *= getDouble("multiplier", minion.getLevel())
if (minion.getStorage() + price > getDouble("storage", minion.getLevel())) {
continue
}
minion.setActions(minion.getActionAmount() + it.amount)
minion.damageTool()
minion.setStorage(minion.getStorage() + price)
it.amount = 0
}
}
}

View File

@ -3,10 +3,79 @@ 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.api.utils.fastFor
import com.artillexstudios.axminions.api.warnings.Warnings
import com.artillexstudios.axminions.minions.MinionTicker
import com.artillexstudios.axminions.nms.NMSHandler
import kotlin.math.roundToInt
import org.bukkit.Material
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.Item
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player
import org.bukkit.entity.Tameable
class SlayerMinionType : MinionType("slayer", AxMinionsPlugin.INSTANCE.getResource("minions/slayer.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, Warnings.NO_TOOL)
minion.getLocation().world!!.getNearbyEntities(minion.getLocation(), minion.getRange(), minion.getRange(), minion.getRange()).filterIsInstance<LivingEntity>().fastFor {
if (it is Player) return@fastFor
if (!getConfig().getBoolean("damage-animals") && NMSHandler.get().isAnimal(it)) {
return@fastFor
}
if (!getConfig().getBoolean("damage-renamed") && it.customName != null) {
return@fastFor
}
if (!getConfig().getBoolean("damage-tamed") && it is Tameable && it.isTamed) {
return@fastFor
}
NMSHandler.get().attack(minion, it)
it.location.world!!.getNearbyEntities(it.location, 2.0, 2.0, 2.0).filterIsInstance<Item>().fastFor { item ->
if (minion.getLinkedInventory()?.firstEmpty() == -1) {
Warnings.CONTAINER_FULL.display(minion)
return
}
val amount = AxMinionsPlugin.integrations.getStackerIntegration().getStackSize(item)
val stack = item.itemStack
stack.amount = amount.toInt()
minion.addToContainerOrDrop(stack)
item.remove()
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.artillexstudios.axminions.nms
import com.artillexstudios.axapi.utils.Version
import com.artillexstudios.axminions.api.minions.Minion
import org.bukkit.entity.Entity
import org.bukkit.inventory.ItemStack
interface NMSHandler {
companion object {
private val handler: NMSHandler =
Class.forName("com.artillexstudios.axminions.nms.${Version.getServerVersion().nmsVersion}.NMSHandler").getConstructor().newInstance() as NMSHandler
fun get(): NMSHandler {
return handler
}
}
fun attack(source: Minion, target: Entity)
fun generateRandomFishingLoot(minion: Minion): List<ItemStack>
fun isAnimal(entity: Entity): Boolean
}

View File

@ -32,6 +32,12 @@ upgrades:
upgraded: "<green>Successfully upgraded the minion to level: <white><level></white>!"
limit-reached: "<red>You have maxed this minion!"
link:
success: "<green>Successfully linked the minion to a container!"
unlink: "<green>You have unliked the minion."
fail: "<red>You can't link to that block! It's either too far away, or not a container!"
start: "<green>Started linking! Click on a container!"
levels:
1: "<#33FF33>"
2: "<#66FF00>"

View File

@ -0,0 +1,133 @@
name: "<#00EEFF>Fisher <white>Minion"
entity:
name: "<level_color>[<level>] <#00EEFF>Fisher <white>Minion <gray>[<owner>]"
tool:
material:
- "FISHING_ROD"
item:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWMxNWU1ZmI1NmZhMTZiMDc0N2IxYmNiMDUzMzVmNTVkMWZhMzE1NjFjMDgyYjVlMzY0M2RiNTU2NTQxMDg1MiJ9fX0="
name: "<#00EEFF>Fisher <white>Minion"
lore:
- ""
- " <gray>- <white>It catches fish."
- ""
- "<#00EEFF>Statistics"
- " <#00EEFF>❙ <white>Level: <#FFEEAA><level>"
- " <#00EEFF>❙ <white>Fish caught: <#FFEEAA><actions>"
- ""
- "<#00EEFF><b>(!)</b> Place the minion and give it a fishing rod!"
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>Fish caught: <#33FF33><required_actions>"
- ""
- "<#00CCFF><b>(!)</b> Click here to upgrade your minion!"
statistics:
type: "paper"
name: "<#00EEFF><b>Statistics"
lore:
- ""
- " <gray>- <white>Killed mobs: <#00EEFF><actions>"
- ""
upgrades:
1:
range: 3
speed: 200
items:
helmet:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWMxNWU1ZmI1NmZhMTZiMDc0N2IxYmNiMDUzMzVmNTVkMWZhMzE1NjFjMDgyYjVlMzY0M2RiNTU2NTQxMDg1MiJ9fX0="
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: 4
speed: 175
requirements:
money: 3000
actions: 300
4:
range: 5
speed: 160
requirements:
money: 10000
actions: 1000
5:
range: 5
speed: 150
requirements:
money: 20000
actions: 3000
6:
range: 6
speed: 130
requirements:
money: 50000
actions: 6000
7:
range: 6
speed: 115
requirements:
money: 150000
actions: 10000
8:
range: 7
speed: 100
requirements:
money: 500000
actions: 17500
9:
range: 8
speed: 85
requirements:
money: 1000000
actions: 25000
10:
range: 8
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

@ -76,49 +76,49 @@ upgrades:
money: 1000
actions: 100
3:
range: 5
range: 4
speed: 175
requirements:
money: 3000
actions: 300
4:
range: 6
range: 5
speed: 160
requirements:
money: 10000
actions: 1000
5:
range: 7
range: 5
speed: 150
requirements:
money: 20000
actions: 3000
6:
range: 8
range: 6
speed: 130
requirements:
money: 50000
actions: 6000
7:
range: 9
range: 6
speed: 115
requirements:
money: 150000
actions: 10000
8:
range: 10
range: 7
speed: 100
requirements:
money: 500000
actions: 17500
9:
range: 11
range: 8
speed: 85
requirements:
money: 1000000
actions: 25000
10:
range: 12
range: 8
speed: 60
requirements:
money: 5000000

View File

@ -14,7 +14,7 @@ tool:
# 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 line: checks blocks in all 4 directions from the minion in the range of the minion (Best performance to blocks broken ratio)
# 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,
@ -79,55 +79,55 @@ upgrades:
color: "0, 150, 255"
glow: false
2:
range: 4
speed: 190
range: 3
speed: 185
requirements:
money: 1000
actions: 100
3:
range: 5
range: 3
speed: 175
requirements:
money: 3000
actions: 300
4:
range: 6
range: 4
speed: 160
requirements:
money: 10000
actions: 1000
5:
range: 7
range: 4
speed: 150
requirements:
money: 20000
actions: 3000
6:
range: 8
range: 5
speed: 130
requirements:
money: 50000
actions: 6000
7:
range: 9
range: 5
speed: 115
requirements:
money: 150000
actions: 10000
8:
range: 10
range: 6
speed: 100
requirements:
money: 500000
actions: 17500
9:
range: 11
range: 6
speed: 85
requirements:
money: 1000000
actions: 25000
10:
range: 12
range: 7
speed: 60
requirements:
money: 5000000

View File

@ -0,0 +1,148 @@
name: "<#CC00FF>Seller <white>Minion"
entity:
name: "<level_color>[<level>] <#CC00FF>Seller <white>Minion <gray>[<owner>]"
tool:
material:
- "BOW"
- "CROSSBOW"
delete-unsellable: true
item:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI0YmE3NjBhNjFkZDI1NmM1MmIzMjUxMjlmNDYwMTZhZTg5MjIzMmEwZGVhMTcxNWY5OTdmN2M0ZDYyMmJlZiJ9fX0="
name: "<#CC00FF>Seller <white>Minion"
lore:
- ""
- " <gray>- <white>Sells all items from it's container."
- ""
- "<#CC00FF>Statistics"
- " <#CC00FF>❙ <white>Level: <#FFEEAA><level>"
- " <#CC00FF>❙ <white>Sold items: <#FFEEAA><actions>"
- ""
- "<#CC00FF><b>(!)</b> Place the minion and give it a bow!"
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: "<#CC00FF><b>Statistics"
lore:
- ""
- " <gray>- <white>Collected items: <#CC00FF><actions>"
- " <gray>- <white>Stored coins: <#CC00FF><storage>"
- ""
- "<#CC00FF><b>(!)</b> Click here to collect the stored coins!"
upgrades:
1:
multiplier: 1
speed: 600
storage: 100000
items:
helmet:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI0YmE3NjBhNjFkZDI1NmM1MmIzMjUxMjlmNDYwMTZhZTg5MjIzMmEwZGVhMTcxNWY5OTdmN2M0ZDYyMmJlZiJ9fX0="
chestplate:
type: "leather_chestplate"
color: "200, 0, 255"
glow: false
leggings:
type: "leather_leggings"
color: "255, 230, 0"
glow: false
boots:
type: "leather_boots"
color: "255, 230, 0"
glow: false
2:
multiplier: 1.05
speed: 500
storage: 500000
requirements:
money: 1000
actions: 100
3:
multiplier: 1.1
speed: 450
storage: 1000000
requirements:
money: 3000
actions: 300
4:
multiplier: 1.15
speed: 400
storage: 4000000
requirements:
money: 10000
actions: 1000
5:
multiplier: 1.2
speed: 350
storage: 7000000
requirements:
money: 20000
actions: 3000
6:
multiplier: 1.25
speed: 300
storage: 10000000
requirements:
money: 50000
actions: 6000
7:
multiplier: 1.3
speed: 250
storage: 30000000
requirements:
money: 150000
actions: 10000
8:
multiplier: 1.35
speed: 200
storage: 50000000
requirements:
money: 500000
actions: 17500
9:
multiplier: 1.4
speed: 150
storage: 80000000
requirements:
money: 1000000
actions: 25000
10:
multiplier: 1.5
speed: 100
storage: 100000000
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,142 @@
name: "<#FF3333>Slayer <white>Minion"
entity:
name: "<level_color>[<level>] <#FF3333>Slayer <white>Minion <gray>[<owner>]"
tool:
material:
- "WOODEN_SWORD"
- "STONE_SWORD"
- "GOLDEN_SWORD"
- "IRON_SWORD"
- "DIAMOND_SWORD"
- "NETHERITE_SWORD"
damage-animals: false
damage-tamed: false
damage-renamed: false
item:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTc1MzJlOTBjNTczYTM5NGM3ODAyYWE0MTU4MzA1ODAyYjU5ZTY3ZjJhMmI3ZTNmZDAzNjNhYTZlYTQyYjg0MSJ9fX0="
name: "<#FF3333>Slayer <white>Minion"
lore:
- ""
- " <gray>- <white>Kills mobs around itself."
- ""
- "<#FF3333>Statistics"
- " <#FF3333>❙ <white>Level: <#FFEEAA><level>"
- " <#FF3333>❙ <white>Mobs killed: <#FFEEAA><actions>"
- ""
- "<#FF3333><b>(!)</b> Place the minion and give it a sword!"
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>Killed mobs: <#33FF33><required_actions>"
- ""
- "<#00CCFF><b>(!)</b> Click here to upgrade your minion!"
statistics:
type: "paper"
name: "<#FF3333><b>Statistics"
lore:
- ""
- " <gray>- <white>Killed mobs: <#FF3333><actions>"
- ""
upgrades:
1:
range: 3
speed: 200
items:
helmet:
type: "player_head"
texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTc1MzJlOTBjNTczYTM5NGM3ODAyYWE0MTU4MzA1ODAyYjU5ZTY3ZjJhMmI3ZTNmZDAzNjNhYTZlYTQyYjg0MSJ9fX0="
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: 4
speed: 175
requirements:
money: 3000
actions: 300
4:
range: 5
speed: 160
requirements:
money: 10000
actions: 1000
5:
range: 5
speed: 150
requirements:
money: 20000
actions: 3000
6:
range: 6
speed: 130
requirements:
money: 50000
actions: 6000
7:
range: 6
speed: 115
requirements:
money: 150000
actions: 10000
8:
range: 7
speed: 100
requirements:
money: 500000
actions: 17500
9:
range: 8
speed: 85
requirements:
money: 1000000
actions: 25000
10:
range: 8
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

13
nms/build.gradle Normal file
View File

@ -0,0 +1,13 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.5.4" apply false
}
group = "com.artillexstudios.axminions"
version = rootProject.version
subprojects {
dependencies {
compileOnly project(":common")
compileOnly project(":api")
}
}

20
nms/v1_20_R1/build.gradle Normal file
View File

@ -0,0 +1,20 @@
plugins {
id("io.papermc.paperweight.userdev")
}
group = 'com.artillexstudios.axminions.nms'
version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT")
}
tasks {
build {
dependsOn(reobfJar)
}
reobfJar {
mustRunAfter(shadowJar)
}
}

View File

@ -0,0 +1,205 @@
package com.artillexstudios.axminions.nms.v1_20_R1
import com.artillexstudios.axminions.api.events.MinionDamageEntityEvent
import com.artillexstudios.axminions.api.minions.Minion
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.Mth
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.MobType
import net.minecraft.world.entity.decoration.ArmorStand
import net.minecraft.world.item.AxeItem
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.SwordItem
import net.minecraft.world.item.TridentItem
import net.minecraft.world.item.enchantment.EnchantmentHelper
import net.minecraft.world.item.enchantment.SweepingEdgeEnchantment
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.Entity
import org.bukkit.event.entity.EntityPotionEffectEvent
object DamageHandler {
fun damage(source: Minion, entity: Entity) {
val nmsEntity = (entity as CraftEntity).handle
var f = 1
val nmsItem: ItemStack
if (source.getTool() == null) {
nmsItem = ItemStack.EMPTY
} else {
nmsItem = CraftItemStack.asNMSCopy(source.getTool())
if (nmsItem.item is SwordItem) {
f = (f + (nmsItem.item as SwordItem).damage).toInt()
}
if (nmsItem.item is AxeItem) {
f = (f + (nmsItem.item as AxeItem).attackDamage).toInt()
}
if (nmsItem.item is TridentItem) {
f = (f + TridentItem.BASE_DAMAGE).toInt()
}
}
if (!nmsEntity.isAttackable) return
val f2 = 1.0f
var f1 = if (nmsEntity is LivingEntity) {
EnchantmentHelper.getDamageBonus(nmsItem, (nmsEntity).mobType)
} else {
EnchantmentHelper.getDamageBonus(nmsItem, MobType.UNDEFINED)
}
f = (f * (0.2f + f2 * f2 * 0.8f)).toInt()
f1 *= f2
if (f > 0.0f || f1 > 0.0f) {
var flag3 = false
val b0: Byte = 0
val i = b0 + (source.getTool()?.getEnchantmentLevel(Enchantment.KNOCKBACK) ?: 0)
f = (f * 1.5f).toInt()
f = (f + f1).toInt()
if (nmsItem.item is SwordItem) {
flag3 = true
}
var f3 = 0.0f
var flag4 = false
val j = (source.getTool()?.getEnchantmentLevel(Enchantment.FIRE_ASPECT) ?: 0)
if (nmsEntity is LivingEntity) {
f3 = nmsEntity.health
if (j > 0 && !nmsEntity.isOnFire()) {
flag4 = true
nmsEntity.setSecondsOnFire(1, false)
}
}
val event = MinionDamageEntityEvent(source, entity as org.bukkit.entity.LivingEntity, f.toDouble())
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) {
return
}
val flag5 = nmsEntity.hurt(nmsEntity.damageSources().magic(), f.toFloat())
if (flag5) {
if (i > 0) {
if (nmsEntity is LivingEntity) {
(nmsEntity).knockback(
(i.toFloat() * 0.5f).toDouble(),
Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble(),
(-Mth.cos(source.getLocation().yaw * 0.017453292f)).toDouble()
)
} else {
nmsEntity.push(
(-Mth.sin(source.getLocation().yaw * 0.017453292f) * i.toFloat() * 0.5f).toDouble(),
0.1,
(Mth.cos(source.getLocation().yaw * 0.017453292f) * i.toFloat() * 0.5f).toDouble()
)
}
}
if (flag3) {
val sweep = source.getTool()?.getEnchantmentLevel(Enchantment.SWEEPING_EDGE) ?: 0
val f4 = 1.0f + if (sweep > 0) SweepingEdgeEnchantment.getSweepingDamageRatio(sweep) else 0.0f * f
val list: List<LivingEntity> = (source.getLocation().world as CraftWorld).handle
.getEntitiesOfClass(LivingEntity::class.java, nmsEntity.boundingBox.inflate(1.0, 0.25, 1.0))
val iterator: Iterator<*> = list.iterator()
while (iterator.hasNext()) {
val entityliving: LivingEntity = iterator.next() as LivingEntity
if ((entityliving !is ArmorStand || !(entityliving).isMarker) && source.getLocation().distanceSquared(
(entity as Entity).location
) < 9.0
) {
val damageEvent = MinionDamageEntityEvent(source, entityliving.bukkitEntity as org.bukkit.entity.LivingEntity, f4.toDouble())
Bukkit.getPluginManager().callEvent(damageEvent)
if (event.isCancelled) {
return
}
// CraftBukkit start - Only apply knockback if the damage hits
if (entityliving.hurt(nmsEntity.damageSources().magic(), f4)) {
entityliving.knockback(
0.4000000059604645,
Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble(),
(-Mth.cos(source.getLocation().yaw * 0.017453292f)).toDouble()
)
}
// CraftBukkit end
}
}
val d0 = -Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble()
val d1 = Mth.cos(source.getLocation().yaw * 0.017453292f).toDouble()
if ((source.getLocation().world as CraftWorld).handle is ServerLevel) {
((source.getLocation().world as CraftWorld).handle as ServerLevel).sendParticles(
ParticleTypes.SWEEP_ATTACK,
source.getLocation().x + d0,
source.getLocation().y + 0.5,
source.getLocation().z + d1,
0,
d0,
0.0,
d1,
0.0
)
}
}
val baneOfArthropods = source.getTool()?.getEnchantmentLevel(Enchantment.DAMAGE_ARTHROPODS) ?: 0
if (nmsEntity is LivingEntity) {
if (baneOfArthropods > 0 && (nmsEntity.mobType === MobType.ARTHROPOD)) {
val p: Int = 20 + nmsEntity.random.nextInt(10 * baneOfArthropods)
nmsEntity.addEffect(
MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, p, 3),
EntityPotionEffectEvent.Cause.ATTACK
)
}
}
if (nmsEntity is LivingEntity) {
val f5: Float = f3 - nmsEntity.health
if (j > 0) {
nmsEntity.setSecondsOnFire(j * 4, false)
}
if ((source.getLocation().world as CraftWorld).handle is ServerLevel && f5 > 2.0f) {
val k = (f5.toDouble() * 0.5).toInt()
((source.getLocation().world as CraftWorld).handle).sendParticles(
ParticleTypes.DAMAGE_INDICATOR,
nmsEntity.getX(),
nmsEntity.getY(0.5),
nmsEntity.getZ(),
k,
0.1,
0.0,
0.1,
0.2
)
}
}
} else {
if (flag4) {
nmsEntity.clearFire()
}
}
}
}
}

View File

@ -0,0 +1,38 @@
package com.artillexstudios.axminions.nms.v1_20_R1
import com.artillexstudios.axminions.api.minions.Minion
import net.minecraft.server.MinecraftServer
import net.minecraft.world.level.storage.loot.BuiltInLootTables
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.Vec3
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
object LootHandler {
fun generateFishingLoot(minion: Minion): List<ItemStack> {
val nmsItem: net.minecraft.world.item.ItemStack = if (minion.getTool() == null) {
net.minecraft.world.item.ItemStack.EMPTY
} else {
CraftItemStack.asNMSCopy(minion.getTool())
}
val level = (minion.getLocation().world as CraftWorld).handle
val lootparams = LootParams.Builder(level).withParameter(
LootContextParams.ORIGIN, Vec3(minion.getLocation().x, minion.getLocation().y, minion.getLocation().z)
).withParameter(LootContextParams.TOOL, nmsItem).withOptionalParameter(LootContextParams.THIS_ENTITY, null)
.create(LootContextParamSets.FISHING)
val lootTable = MinecraftServer.getServer().lootData.getLootTable(BuiltInLootTables.FISHING)
return lootTable.getRandomItems(lootparams).stream().map { original: net.minecraft.world.item.ItemStack? ->
CraftItemStack.asBukkitCopy(
original
)
}.toList()
}
}

View File

@ -0,0 +1,23 @@
package com.artillexstudios.axminions.nms.v1_20_R1
import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.nms.NMSHandler
import net.minecraft.world.entity.MobCategory
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity
import org.bukkit.entity.Entity
import org.bukkit.inventory.ItemStack
class NMSHandler : NMSHandler {
override fun attack(source: Minion, target: Entity) {
DamageHandler.damage(source, target)
}
override fun generateRandomFishingLoot(minion: Minion): List<ItemStack> {
return LootHandler.generateFishingLoot(minion)
}
override fun isAnimal(entity: Entity): Boolean {
return (entity as CraftEntity).handle.type.category == MobCategory.CREATURE
}
}

View File

@ -12,4 +12,6 @@ plugins {
rootProject.name = 'AxMinions'
include 'api'
include 'common'
include 'nms'
include 'nms:v1_20_R1'