Skip to content

Commit

Permalink
feat: geary test spawn command
Browse files Browse the repository at this point in the history
  • Loading branch information
0ffz committed Dec 12, 2024
1 parent ebe3390 commit ee671a1
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.mineinabyss.geary.papermc

import com.charleskorn.kaml.*
import com.mineinabyss.geary.modules.Geary
import com.mineinabyss.geary.modules.geary
import com.mineinabyss.geary.serialization.serializers.PolymorphicListAsMapSerializer
import com.mineinabyss.geary.serialization.serializers.PolymorphicListAsMapSerializer.Companion.provideConfig
import kotlinx.serialization.KSerializer
Expand All @@ -11,12 +10,21 @@ import kotlinx.serialization.modules.overwriteWith
import java.nio.file.Path
import kotlin.io.path.*

data class EntryWithNode<T>(
val entry: T,
val node: YamlNode,
)

class MultiEntryYamlReader<T>(
val serializer: KSerializer<T>,
val yamlFormat: Yaml,
) {
fun decodeRecursiveEntries(rootDir: Path): List<T> {
return decodeRecursive(rootDir).values.map { it.entry }
}

@OptIn(ExperimentalPathApi::class)
fun decodeRecursive(rootDir: Path): List<T> {
fun decodeRecursive(rootDir: Path): Map<String, EntryWithNode<T>> {
val nodes = mutableMapOf<String, EntryWithNode<T>>()
val entries = mutableListOf<T>()
rootDir.walk()
Expand Down Expand Up @@ -47,14 +55,9 @@ class MultiEntryYamlReader<T>(
}

}
return entries
return nodes
}

data class EntryWithNode<T>(
val entry: T,
val node: YamlNode,
)

fun decodeEntry(
yaml: Yaml,
decodedEntries: Map<String, EntryWithNode<T>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ class Checks() {
inline fun check(name: String, run: () -> Boolean) {
val result = runCatching { run() }
.onFailure { exception ->
with(failed) {
appendLine("$name: ${exception.message}")
}

if (failed.isNotEmpty()) failed.appendLine()
failed.append("$name: ${exception.message}")
}
.getOrNull() ?: return
if (!result) failed.appendLine("$name: Condition failed")
if (!result) {
if (failed.isNotEmpty()) failed.appendLine()
failed.append("$name: Condition failed")
}
}

inline fun <T> checkOptional(name: String, argument: T?, run: (T) -> Boolean) {
if (argument == null) return
check(name) { run(argument) }
}

val result get() = if(failed.isEmpty()) CheckResult.Success else CheckResult.Failure(failed.toString())
val result get() = if (failed.isEmpty()) CheckResult.Success else CheckResult.Failure(failed.toString())
}

inline fun checks(check: Checks.() -> Unit): CheckResult {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mineinabyss.geary.papermc.plugin.commands

import com.mineinabyss.geary.papermc.plugin.GearyPluginImpl
import com.mineinabyss.geary.papermc.plugin.commands.TestCommands.test
import com.mineinabyss.geary.papermc.plugin.commands.mobs.mobs
import com.mineinabyss.geary.prefabs.PrefabKey
import com.mineinabyss.idofront.commands.brigadier.commands
Expand All @@ -12,7 +13,7 @@ internal fun GearyPluginImpl.registerGearyCommands() = commands {
prefabs()
reload(this@registerGearyCommands)
debug()
testCommands()
test()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.mineinabyss.geary.papermc.plugin.commands
import com.mineinabyss.geary.actions.ActionGroupContext
import com.mineinabyss.geary.actions.Condition
import com.mineinabyss.geary.papermc.gearyPaper
import com.mineinabyss.geary.papermc.spawning.SpawningFeature
import com.mineinabyss.geary.papermc.tracking.entities.toGeary
import com.mineinabyss.geary.serialization.SerializableComponents
import com.mineinabyss.geary.serialization.serializers.PolymorphicListAsMapSerializer
Expand All @@ -13,27 +14,47 @@ import com.mineinabyss.idofront.commands.brigadier.playerExecutes
import com.mineinabyss.idofront.messaging.error
import com.mineinabyss.idofront.messaging.success

fun IdoCommand.testCommands() = "test" {
requiresPermission("geary.admin.test")
"condition" {
playerExecutes(Args.greedyString()) { yaml ->
test(yaml)
object TestCommands {
fun IdoCommand.test() = "test" {
requiresPermission("geary.admin.test")
"condition" {
playerExecutes(Args.greedyString().named("Condition Yaml")) { yaml ->
testCondition(yaml)
}
}
"spawn" {
fun spawningFeature() = gearyPaper.features.get<SpawningFeature>()
fun getSpawns() = spawningFeature().spawnEntriesByName

val spawnArg = Args.string()
.suggests { suggestFiltering(getSpawns()?.map { it.key } ?: listOf()) }
.named("Spawn name")

playerExecutes(spawnArg) { spawnName ->
val spawn = getSpawns()?.get(spawnName) ?: fail("Could not find spawn named $spawnName")
val spawner = spawningFeature().spawnTask?.mobSpawner ?: fail("Mob spawn task not enabled")
runCatching { spawner.checkSpawnConditions(spawn, player.location) }
.onSuccess {
if (it) sender.success("Conditions for $spawnName passed") else sender.error("Conditions for $spawnName failed")
}
.onFailure { sender.error("Conditions for $spawnName failed:\n${it.message}") }
}
}
}
}

fun IdoPlayerCommandContext.test(yaml: String) {
val decoded = gearyPaper.worldManager.global.getAddon(SerializableComponents)
.formats["yml"]
?.decodeFromString(PolymorphicListAsMapSerializer.ofComponents(), yaml)
?: fail("Could not decode yaml")
decoded.forEach { condition ->
if (condition !is Condition) return@forEach
val conditionName = condition::class.simpleName ?: return@forEach
with(condition) {
runCatching { ActionGroupContext(player.toGeary()).execute() }
.onSuccess { sender.success("Condition $conditionName passed") }
.onFailure { exception -> sender.error("Condition $conditionName failed:\n${exception.message}") }
fun IdoPlayerCommandContext.testCondition(yaml: String) {
val decoded = gearyPaper.worldManager.global.getAddon(SerializableComponents)
.formats["yml"]
?.decodeFromString(PolymorphicListAsMapSerializer.ofComponents(), yaml)
?: fail("Could not decode yaml")
decoded.forEach { condition ->
if (condition !is Condition) return@forEach
val conditionName = condition::class.simpleName ?: return@forEach
with(condition) {
runCatching { ActionGroupContext(player.toGeary()).execute() }
.onSuccess { sender.success("Condition $conditionName passed") }
.onFailure { exception -> sender.error("Condition $conditionName failed:\n${exception.message}") }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.mineinabyss.geary.actions.ActionGroupContext
import com.mineinabyss.geary.papermc.location
import com.mineinabyss.geary.papermc.spawning.choosing.LocationSpread
import com.mineinabyss.geary.papermc.spawning.choosing.SpawnChooser
import com.mineinabyss.geary.papermc.spawning.config.SpawnEntry
import com.mineinabyss.geary.papermc.spawning.config.SpawnPosition
import com.mineinabyss.idofront.util.randomOrMin
import org.bukkit.Location
Expand All @@ -13,6 +14,18 @@ class MobSpawner(
val spawnChooser: SpawnChooser,
val spreadRepo: LocationSpread,
) {
fun checkSpawnConditions(spawn: SpawnEntry, location: Location): Boolean {
// Check dynamic conditions
return spawn.conditions.all {
it.conditionsMet(
ActionGroupContext().apply {
this.location = location.clone()
environment["spawnTypes"] = listOf(spawn.type.key)
}
)
}
}

/**
* Choose and attempt a spawn at a [location] using allowed spawns based on [position].
*
Expand All @@ -22,17 +35,7 @@ class MobSpawner(
val spawn = spawnChooser.chooseAllowedSpawnNear(location, position) ?: return false

if (spawn.chance != 1.0 && Random.nextDouble() > spawn.chance) return false

// Check dynamic conditions
if (!spawn.conditions.all {
it.conditionsMet(
ActionGroupContext().apply {
this.location = location.clone()
environment["spawnTypes"] = listOf(spawn.type.key)
}
)
}
) return false
if (runCatching { !checkSpawnConditions(spawn, location) }.getOrDefault(true)) return false

repeat(spawn.amount.randomOrMin()) {
val spread = spawn.spread.randomOrMin().toDouble()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.mineinabyss.geary.papermc.spawning.choosing.SpawnLocationChooser
import com.mineinabyss.geary.papermc.spawning.choosing.mobcaps.MobCaps
import com.mineinabyss.geary.papermc.spawning.choosing.worldguard.WorldGuardSpawning
import com.mineinabyss.geary.papermc.spawning.config.SpawnConfig
import com.mineinabyss.geary.papermc.spawning.config.SpawnEntry
import com.mineinabyss.geary.papermc.spawning.config.SpawnEntryReader
import com.mineinabyss.geary.papermc.spawning.readers.SpawnPositionReader
import com.mineinabyss.geary.papermc.spawning.spawn_types.geary.GearySpawnTypeListener
Expand All @@ -21,6 +22,8 @@ import com.mineinabyss.idofront.config.config

class SpawningFeature(context: FeatureContext) : Feature(context) {
val config by config("spawning", plugin.dataPath, SpawnConfig())
var spawnTask: SpawnTask? = null
var spawnEntriesByName: Map<String, SpawnEntry>? = null

init {
pluginDeps("WorldGuard", "MythicMobs")
Expand All @@ -43,21 +46,22 @@ class SpawningFeature(context: FeatureContext) : Feature(context) {
)
)
val spawns = reader.readSpawnEntries()
val wg = WorldGuardSpawning(spawns)
val wg = WorldGuardSpawning(spawns.values.map { it.entry })
val caps = MobCaps(config.playerCaps, config.defaultCap, config.range.playerCapRadius)
val spawnChooser = SpawnChooser(wg, caps)
val spawnPositionReader = SpawnPositionReader()
task(
SpawnTask(
runTimes = config.runTimes,
locationChooser = SpawnLocationChooser(config.range),
spawnPositionReader = spawnPositionReader,
spawnAttempts = config.maxSpawnAttemptsPerPlayer,
mobSpawner = MobSpawner(
spawnChooser,
LocationSpread(spawnPositionReader, triesForNearbyLoc = 10)
),
).job
val task = SpawnTask(
runTimes = config.runTimes,
locationChooser = SpawnLocationChooser(config.range),
spawnPositionReader = spawnPositionReader,
spawnAttempts = config.maxSpawnAttemptsPerPlayer,
mobSpawner = MobSpawner(
spawnChooser,
LocationSpread(spawnPositionReader, triesForNearbyLoc = 10)
),
)
spawnTask = task
spawnEntriesByName = spawns.mapValues { it.value.entry }
task(task.job)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mineinabyss.geary.papermc.spawning.config

import com.charleskorn.kaml.Yaml
import com.mineinabyss.geary.papermc.EntryWithNode
import com.mineinabyss.geary.papermc.MultiEntryYamlReader
import com.mineinabyss.geary.papermc.spawning.spawn_types.SpawnType
import org.bukkit.plugin.Plugin
Expand All @@ -13,8 +14,8 @@ class SpawnEntryReader(
) {
private val reader = MultiEntryYamlReader(SpawnEntry.serializer(), yamlFormat)

fun readSpawnEntries(): List<SpawnEntry> {
fun readSpawnEntries(): Map<String, EntryWithNode<SpawnEntry>> {
return reader.decodeRecursive((plugin.dataPath / "spawns").createParentDirectories())
.filter { it.type != SpawnType.None }
.filterValues { it.entry.type != SpawnType.None }
}
}

0 comments on commit ee671a1

Please sign in to comment.