9
0
mirror of https://github.com/Auxilor/EcoMobs.git synced 2025-12-20 07:29:21 +00:00

Compare commits

...

53 Commits

Author SHA1 Message Date
Auxilor
ab6d297222 Updated eco/kotlin/libreforge 2022-04-20 11:46:01 +01:00
Auxilor
9626588c66 Updated libreforge 2022-04-16 15:45:37 +01:00
Auxilor
c4eda19d78 Updated to 8.20.4 2022-04-12 11:35:01 +01:00
Auxilor
691326577a Updated to 8.20.4 2022-04-11 14:51:47 +01:00
Auxilor
e2086387e7 Fixed custom AI not working 2022-04-11 14:51:36 +01:00
Auxilor
13a72f849d Updated to 8.20.2 2022-04-09 14:42:29 +01:00
Auxilor
6346975e77 Updated to 8.20.2 2022-04-08 18:03:48 +01:00
Auxilor
0d846d9dff Added autospawn.one-boss-per-world option 2022-04-08 18:03:39 +01:00
Auxilor
31610383c4 Updated libreforge 2022-04-06 14:18:41 +01:00
Auxilor
d7c16ad3cc Updated libreforge 2022-04-04 10:23:34 +01:00
Auxilor
afe9095276 Updated libreforge 2022-04-02 14:04:56 +01:00
Auxilor
31a782581f Updated libreforge 2022-03-31 20:20:00 +01:00
Auxilor
8aad221450 Updated libreforge 2022-03-30 20:38:08 +01:00
Auxilor
b0bff24263 Updated libreforge 2022-03-28 19:05:19 +01:00
Auxilor
04b00fa01b Merge remote-tracking branch 'origin/master'
# Conflicts:
#	build.gradle
#	gradle.properties
2022-03-28 19:05:11 +01:00
Auxilor
276ba4616a Updated libreforge 2022-03-25 09:31:29 +00:00
Auxilor
d8e5fb9cd0 Updated to 8.14.0 2022-03-21 12:40:12 +00:00
Auxilor
9f05a6504a Added support for custom entity AI 2022-03-21 12:39:09 +00:00
Auxilor
322a6bb41b Updated libreforge 2022-03-21 12:24:06 +00:00
Auxilor
4dbc8afdf4 Updated libreforge 2022-03-19 16:42:59 +00:00
Auxilor
7ffa6ff4f4 Updated libreforge 2022-03-17 08:57:55 +00:00
Auxilor
3769684bb0 Updated libreforge 2022-03-16 09:05:56 +00:00
Auxilor
7bb931e027 Updated libreforge 2022-03-13 11:59:46 +00:00
Auxilor
879d6dd72d Updated libreforge 2022-03-12 12:22:54 +00:00
Auxilor
0a4aff45ad Updated libreforge 2022-03-10 15:13:28 +00:00
Auxilor
5929da1f48 Updated libreforge 2022-03-09 12:50:07 +00:00
Will FP
6db5de581b Update README.md 2022-03-09 12:47:33 +00:00
Auxilor
9ce1bb7ddf Updated libreforge 2022-03-08 20:20:01 +00:00
Auxilor
351d34de9f Updated libreforge 2022-03-07 14:01:18 +00:00
Auxilor
4d2b726aa0 Updated to 8.7.1 2022-03-04 16:59:39 +00:00
Auxilor
ff20b70784 Improved PDC storage 2022-03-04 16:59:31 +00:00
Auxilor
f31cd20200 Updated to 8.7.0 2022-03-03 17:02:43 +00:00
Auxilor
0ad2d3cfc7 Adapted pull request 2022-03-03 17:01:19 +00:00
Will FP
ccc7c5797a Merge pull request #28
Add commands ran for lifecycle
2022-03-03 16:54:00 +00:00
Auxilor
a218fa96c0 Updated libreforge 2022-03-01 16:26:17 +00:00
Auxilor
13c0a4d83a Updated to 8.5.2 2022-02-28 10:16:04 +00:00
Auxilor
62e7177b1b Fixed autospawn 2022-02-28 10:15:52 +00:00
Auxilor
752b30b4a2 Fixed spawn event not being called with totems 2022-02-28 10:14:11 +00:00
Auxilor
be4d6156e3 Fixed spawn totems some more 2022-02-28 10:12:12 +00:00
Auxilor
fed6dcafd7 Fixed spawn totems 2022-02-28 10:09:31 +00:00
Auxilor
36f944c58c Updated libreforge 2022-02-28 10:04:53 +00:00
Auxilor
1bc35656fe Fixed bosses attacking creative and spectator mode players 2022-02-28 10:04:38 +00:00
casper
1216e83a39 Add commands ran for lifecycle 2022-02-26 15:31:52 -05:00
Auxilor
4723c7982c Updated libreforge 2022-02-25 11:24:50 +00:00
Auxilor
8ba3c7834c Updated libreforge 2022-02-20 17:25:32 +00:00
Auxilor
76530a1617 Updated libreforge 2022-02-19 15:58:02 +00:00
Auxilor
bf41554846 build.gradle messages 2022-02-18 15:10:11 +00:00
Auxilor
a741c78b6b Fixed compatibility with other plugins 2022-02-18 14:37:01 +00:00
Auxilor
0f8dce74da Updated libreforge 2022-02-18 14:36:11 +00:00
Auxilor
0d31556b84 Updated libreforge 2022-02-15 16:49:03 +00:00
Auxilor
f8544c284e Updated libreforge 2022-02-14 17:18:16 +00:00
Auxilor
512a477fc6 Updated libreforge 2022-02-13 15:41:22 +00:00
Auxilor
8a1b473837 Updated libreforge 2022-02-12 10:51:41 +00:00
14 changed files with 184 additions and 31 deletions

View File

@@ -1,6 +1,6 @@
<h1 align="center"> <h1 align="center">
<br> <br>
<img src="https://i.imgur.com/A2qieC3.png" alt="EcoBosses logo" width="256"> <img src="https://i.imgur.com/3n3ssb4.png" alt="EcoBosses logo" width="256">
<br> <br>
</h1> </h1>

View File

@@ -4,7 +4,7 @@ buildscript {
} }
dependencies { dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
} }
} }
@@ -61,12 +61,12 @@ allprojects {
} }
dependencies { dependencies {
compileOnly 'com.willfp:eco:6.24.0' compileOnly 'com.willfp:eco:6.34.0'
implementation 'com.willfp:libreforge:3.17.0' implementation 'com.willfp:libreforge:3.34.1'
compileOnly 'org.jetbrains:annotations:23.0.0' compileOnly 'org.jetbrains:annotations:23.0.0'
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.6.0' compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.6.21'
} }
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
@@ -118,4 +118,16 @@ version = findProperty("version")
compileJava.options.encoding = 'UTF-8' compileJava.options.encoding = 'UTF-8'
build.dependsOn shadowJar build.dependsOn shadowJar
build.dependsOn publishToMavenLocal build.dependsOn publishToMavenLocal
task buyThePlugins {
dependsOn subprojects.build
doLast {
println 'If you like the plugin, please consider buying it on Spigot or Polymart!'
println 'Spigot: https://www.spigotmc.org/resources/authors/auxilor.507394/'
println 'Polymart: https://polymart.org/user/auxilor.1107/'
println 'Buying gives you access to support and the plugin auto-updater, and it allows me to keep developing plugins.'
}
}
build.finalizedBy buyThePlugins

View File

@@ -0,0 +1,8 @@
package com.willfp.ecobosses.bosses
import com.willfp.eco.core.entities.ai.Goal
data class ConfiguredGoal<T : Goal<*>>(
val priority: Int,
val goal: T
)

View File

@@ -5,12 +5,14 @@ import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.entities.CustomEntity import com.willfp.eco.core.entities.CustomEntity
import com.willfp.eco.core.entities.Entities import com.willfp.eco.core.entities.Entities
import com.willfp.eco.core.entities.TestableEntity import com.willfp.eco.core.entities.TestableEntity
import com.willfp.eco.core.entities.ai.*
import com.willfp.eco.core.items.CustomItem import com.willfp.eco.core.items.CustomItem
import com.willfp.eco.core.items.Items import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.recipe.Recipes import com.willfp.eco.core.recipe.Recipes
import com.willfp.eco.core.recipe.parts.EmptyTestableItem import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import com.willfp.eco.core.recipe.recipes.CraftingRecipe import com.willfp.eco.core.recipe.recipes.CraftingRecipe
import com.willfp.eco.util.NamespacedKeyUtils
import com.willfp.eco.util.toComponent import com.willfp.eco.util.toComponent
import com.willfp.ecobosses.events.BossKillEvent import com.willfp.ecobosses.events.BossKillEvent
import com.willfp.ecobosses.lifecycle.BossLifecycle import com.willfp.ecobosses.lifecycle.BossLifecycle
@@ -24,8 +26,10 @@ import org.bukkit.Bukkit
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Mob
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType
import java.util.* import java.util.*
class EcoBoss( class EcoBoss(
@@ -157,6 +161,22 @@ class EcoBoss(
locations locations
} }
val hasCustomAI = config.getBool("customai.enabled")
val targetGoals = config.getSubsections("customai.target-goals").mapNotNull {
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
val deserializer = TargetGoals.getByKey(key) ?: return@mapNotNull null
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
ConfiguredGoal(it.getInt("priority"), goal)
}
val entityGoals = config.getSubsections("customai.ai-goals").mapNotNull {
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
val deserializer = EntityGoals.getByKey(key) ?: return@mapNotNull null
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
ConfiguredGoal(it.getInt("priority"), goal)
}
val spawnConditions = config.getSubsections("spawn.conditions").mapNotNull { val spawnConditions = config.getSubsections("spawn.conditions").mapNotNull {
Conditions.compile(it, "$id Spawn Conditions") Conditions.compile(it, "$id Spawn Conditions")
} }
@@ -189,6 +209,16 @@ class EcoBoss(
map map
} }
private val commands: Map<BossLifecycle, LocalCommands> = run {
val map = mutableMapOf<BossLifecycle, LocalCommands>()
for (value in BossLifecycle.values()) {
map[value] = LocalCommands(config.getStrings("commands.${value.name.lowercase()}"))
}
map
}
private val commandRewards: Map<Int, Iterable<CommandReward>> = run { private val commandRewards: Map<Int, Iterable<CommandReward>> = run {
val map = mutableMapOf<Int, Iterable<CommandReward>>() val map = mutableMapOf<Int, Iterable<CommandReward>>()
@@ -280,10 +310,25 @@ class EcoBoss(
} }
fun spawn(location: Location): LivingEcoBoss { fun spawn(location: Location): LivingEcoBoss {
val mob = mob.spawn(location) as LivingEntity val mob = mob.spawn(location) as Mob
mob.isPersistent = true mob.isPersistent = true
mob.isCustomNameVisible = true mob.isCustomNameVisible = true
mob.removeWhenFarAway = false mob.removeWhenFarAway = false
mob.persistentDataContainer.set(
plugin.namespacedKeyFactory.create("boss"),
PersistentDataType.STRING,
this.id
)
if (hasCustomAI) {
val controller = EntityController.getFor(mob)
.clearAllGoals()
@Suppress("UNCHECKED_CAST") // What could go wrong?
targetGoals.forEach { controller.addTargetGoal(it.priority, it.goal as TargetGoal<in Mob>) }
@Suppress("UNCHECKED_CAST")
entityGoals.forEach { controller.addEntityGoal(it.priority, it.goal as EntityGoal<in Mob>) }
}
val boss = LivingEcoBoss( val boss = LivingEcoBoss(
plugin, plugin,
@@ -322,6 +367,7 @@ class EcoBoss(
fun handleLifecycle(lifecycle: BossLifecycle, location: Location, entity: LivingEntity?) { fun handleLifecycle(lifecycle: BossLifecycle, location: Location, entity: LivingEntity?) {
sounds[lifecycle]?.play(location) sounds[lifecycle]?.play(location)
messages[lifecycle]?.forEach { it.broadcast(location, entity?.topDamagers ?: emptyList()) } messages[lifecycle]?.forEach { it.broadcast(location, entity?.topDamagers ?: emptyList()) }
commands[lifecycle]?.dispatch(location, entity?.topDamagers ?: emptyList())
} }
fun processRewards(event: BossKillEvent) { fun processRewards(event: BossKillEvent) {

View File

@@ -3,6 +3,7 @@ package com.willfp.ecobosses.bosses
import com.google.common.collect.BiMap import com.google.common.collect.BiMap
import com.google.common.collect.HashBiMap import com.google.common.collect.HashBiMap
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import org.bukkit.GameMode
import org.bukkit.entity.Entity import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player import org.bukkit.entity.Player
@@ -23,7 +24,9 @@ class TargetMode(
boss.boss.targetRange, boss.boss.targetRange,
boss.boss.targetRange, boss.boss.targetRange,
boss.boss.targetRange boss.boss.targetRange
).filterIsInstance<Player>(), ).filterIsInstance<Player>()
.filter { listOf(GameMode.SURVIVAL, GameMode.ADVENTURE).contains(it.gameMode) }
.ifEmpty { return null },
entity entity
) )
} }

View File

@@ -31,6 +31,7 @@ class BossSpawnEvent(
TOTEM, TOTEM,
EGG, EGG,
COMMAND, COMMAND,
AUTOSPAWN,
UNKNOWN UNKNOWN
} }

View File

@@ -2,6 +2,8 @@ package com.willfp.ecobosses.spawn
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.ecobosses.bosses.Bosses import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossSpawnEvent
import org.bukkit.Bukkit
object AutospawnHandler { object AutospawnHandler {
private var tick = 1 private var tick = 1
@@ -20,11 +22,19 @@ object AutospawnHandler {
val location = boss.autoSpawnLocations.randomOrNull() ?: continue val location = boss.autoSpawnLocations.randomOrNull() ?: continue
val world = location.world ?: continue val world = location.world ?: continue
if (Bosses.getAllAlive().mapNotNull { it.entity }.any { it.world == world }) { if (plugin.configYml.getBool("autospawn.one-boss-per-world")) {
continue if (Bosses.getAllAlive().mapNotNull { it.entity }.any { it.world == world }) {
continue
}
} }
boss.spawn(location) val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.AUTOSPAWN, null)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (!spawnEvent.isCancelled) {
boss.spawn(location)
}
} }
tick++ tick++

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.util.containsIgnoreCase
import com.willfp.ecobosses.bosses.Bosses import com.willfp.ecobosses.bosses.Bosses
import com.willfp.ecobosses.events.BossSpawnEvent import com.willfp.ecobosses.events.BossSpawnEvent
import com.willfp.ecobosses.util.SpawnTotem import com.willfp.ecobosses.util.SpawnTotem
import org.bukkit.Bukkit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.block.Block import org.bukkit.block.Block
import org.bukkit.event.EventHandler import org.bukkit.event.EventHandler
@@ -16,36 +17,36 @@ class SpawnTotemHandler : Listener {
) )
fun handle(event: BlockPlaceEvent) { fun handle(event: BlockPlaceEvent) {
for (i in 0..2) { for (i in 0..2) {
lateinit var block1: Block lateinit var top: Block
lateinit var block2: Block lateinit var middle: Block
lateinit var block3: Block lateinit var bottom: Block
// I know this code sucks ass, but I can't be arsed to write it nicely // I know this code sucks ass, but I can't be arsed to write it nicely
when (i) { when (i) {
0 -> { 0 -> {
block3 = event.block top = event.block
block2 = event.block.getRelative(0, -1, 0) middle = event.block.getRelative(0, -1, 0)
block1 = event.block.getRelative(0, -2, 0) bottom = event.block.getRelative(0, -2, 0)
} }
1 -> { 1 -> {
block1 = event.block top = event.block.getRelative(0, 2, 0)
block2 = event.block.getRelative(0, 1, 0) middle = event.block.getRelative(0, 1, 0)
block3 = event.block.getRelative(0, 2, 0) bottom = event.block
} }
2 -> { 2 -> {
block2 = event.block top = event.block.getRelative(0, 1, 0)
block1 = event.block.getRelative(0, -1, 0) middle = event.block
block3 = event.block.getRelative(0, 1, 0) bottom = event.block.getRelative(0, -1, 0)
} }
} }
val placedTotem = SpawnTotem(block1.type, block2.type, block3.type) val placedTotem = SpawnTotem(top.type, middle.type, bottom.type)
for (boss in Bosses.values()) { for (boss in Bosses.values()) {
if (boss.totem == null || boss.disabledTotemWorlds.containsIgnoreCase(event.block.world.name)) { if (boss.totem == null || boss.disabledTotemWorlds.containsIgnoreCase(event.block.world.name)) {
continue continue
} }
if (boss.totem != placedTotem) { if (!boss.totem.matches(placedTotem)) {
continue continue
} }
@@ -57,10 +58,12 @@ class SpawnTotemHandler : Listener {
val spawnEvent = BossSpawnEvent(boss, event.block.location, BossSpawnEvent.SpawnReason.TOTEM, player) val spawnEvent = BossSpawnEvent(boss, event.block.location, BossSpawnEvent.SpawnReason.TOTEM, player)
Bukkit.getPluginManager().callEvent(spawnEvent)
if (!spawnEvent.isCancelled) { if (!spawnEvent.isCancelled) {
block1.type = Material.AIR top.type = Material.AIR
block2.type = Material.AIR middle.type = Material.AIR
block3.type = Material.AIR bottom.type = Material.AIR
boss.spawn(event.block.location.add(0.0, 1.5, 0.0)) boss.spawn(event.block.location.add(0.0, 1.5, 0.0))
} }

View File

@@ -0,0 +1,38 @@
package com.willfp.ecobosses.util
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecobosses.EcoBossesPlugin
import org.bukkit.Bukkit
import org.bukkit.Location
data class LocalCommands(
val commands: Iterable<String>,
) {
fun dispatch(location: Location, topDamagers: List<Damager>) {
val toDispatch = commands.toMutableList()
toDispatch.replaceAll {
var command = it
for (i in 1..20) {
val damager = topDamagers.getOrNull(i - 1)
val damage = if (damager?.damage != null) NumberUtils.format(damager.damage) else
EcoBossesPlugin.instance.langYml.getFormattedString("na")
val player = if (damager?.uuid != null) Bukkit.getOfflinePlayer(damager.uuid).savedDisplayName else
EcoBossesPlugin.instance.langYml.getFormattedString("na")
command = command.replace("%damage_${i}%", damage)
.replace("%damage_${i}_player%", player)
}
command.replace("%x%", location.blockX.toString())
.replace("%y%", location.blockY.toString())
.replace("%z%", location.blockZ.toString())
}
for (s in toDispatch) {
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), s);
}
}
}

View File

@@ -6,4 +6,10 @@ data class SpawnTotem(
val top: Material, val top: Material,
val middle: Material, val middle: Material,
val bottom: Material val bottom: Material
) ) {
fun matches(totem: SpawnTotem): Boolean {
return this.top == totem.top
&& this.middle == totem.middle
&& this.bottom == totem.bottom
}
}

View File

@@ -6,6 +6,9 @@
discover-recipes: true discover-recipes: true
log-spawn-kill: true log-spawn-kill: true
autospawn:
one-boss-per-world: true # If only one boss can auto-spawn per world at once.
cooldown: cooldown:
in-actionbar: true in-actionbar: true
sound: sound:
@@ -32,4 +35,15 @@ point-names: # If you have point names that look ugly (eg g_souls) then you can
use-faster-move-trigger: true # Disable if you want move trigger to detect sub-1-block movements use-faster-move-trigger: true # Disable if you want move trigger to detect sub-1-block movements
raytrace-distance: 80 # The distance that alt_click should check for a location raytrace-distance: 80 # The distance that alt_click should check for a location
block-item-drop-place-check: true # If the block_item_drop trigger should only fire on naturally placed blocks (prevents dupes) block-item-drop-place-check: true # If the block_item_drop trigger should only fire on naturally placed blocks (prevents dupes)
potions:
icon:
permanent: true
triggered: true
ambient:
permanent: false
triggered: true
particles:
permanent: false
triggered: true

View File

@@ -26,6 +26,10 @@ bosses:
# Supported placeholders: %health%, %time% (formats as minutes:seconds, eg 1:56) # Supported placeholders: %health%, %time% (formats as minutes:seconds, eg 1:56)
displayName: "&8Steel Golem &7| &c%health%♥ &7| &e%time%" displayName: "&8Steel Golem &7| &c%health%♥ &7| &e%time%"
influence: 40 # The distance at which effects will be applied to players influence: 40 # The distance at which effects will be applied to players
customai: # Custom mob AI using the entity goal system.
enabled: false # If custom AI should be enabled, this will override the vanilla mob behaviour.
target-goals: [ ] # How the boss decides who to attack, if the target mode isn't being used.
ai-goals: [ ] # How the boss should behave.
effects: # Effects are done from the player's perspective: to treat the player as the victim, use the self_as_victim option in args effects: # Effects are done from the player's perspective: to treat the player as the victim, use the self_as_victim option in args
- id: run_chain - id: run_chain
args: args:
@@ -123,6 +127,13 @@ bosses:
- iron_block - iron_block
- netherite_block - netherite_block
- iron_block - iron_block
commands:
# For each category, you can add as many commands as you want, which will be executed by
# console. Supported placeholders are the same as for messages (see below)
spawn: [ ]
kill: [ ]
despawn: [ ]
injure: [ ]
messages: messages:
# For each category, you can add as many messages as you want, each with their own radius. # For each category, you can add as many messages as you want, each with their own radius.
# Radius is the distance from the boss where the player will be sent the message # Radius is the distance from the boss where the player will be sent the message

View File

@@ -18,5 +18,6 @@ messages:
on-cooldown: "&cThis effect is on cooldown! &fTime left: &a%seconds% seconds" on-cooldown: "&cThis effect is on cooldown! &fTime left: &a%seconds% seconds"
cannot-afford: "&cYou can't afford to do this! &fCost: &a$$%cost%" cannot-afford: "&cYou can't afford to do this! &fCost: &a$$%cost%"
cannot-afford-type: "&cYou can't afford to do this! &fCost: &a%cost% %type%" cannot-afford-type: "&cYou can't afford to do this! &fCost: &a%cost% %type%"
cannot-transmit: "&cYou can't transmit here!"
na: "N/A" na: "N/A"

View File

@@ -1,2 +1,2 @@
version = 8.3.0 version = 8.21.1
plugin-name = EcoBosses plugin-name = EcoBosses