mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-20 14:16:26 -04:00
Merge remote-tracking branch 'origin/spawn-rules' into npcs
# Conflicts: # common/src/main/kotlin/com/cobblemon/mod/common/api/pokemon/PokemonProperties.kt
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.MoParams
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.biome.Biome
|
||||
import net.minecraft.world.dimension.DimensionType
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 2nd, 2023
|
||||
*/
|
||||
object MoLangFunctions {
|
||||
val generalFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val dimensionTypeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val blockFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
|
||||
fun RegistryEntry<Biome>.asBiomeMoLangValue() = asMoLangValue(RegistryKeys.BIOME).addFunctions(biomeFunctions)
|
||||
fun RegistryEntry<World>.asWorldMoLangValue() = asMoLangValue(RegistryKeys.WORLD).addFunctions(worldFunctions)
|
||||
fun RegistryEntry<Block>.asBlockMoLangValue() = asMoLangValue(RegistryKeys.BLOCK).addFunctions(blockFunctions)
|
||||
fun RegistryEntry<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(RegistryKeys.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions)
|
||||
|
||||
fun <T> RegistryEntry<T>.asMoLangValue(key: RegistryKey<Registry<T>>): ObjectValue<RegistryEntry<T>> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.key.get().value.toString() }
|
||||
)
|
||||
value.functions.put("is_in") {
|
||||
val tag = TagKey.of(key, Identifier(it.getString(0).replace("#", "")))
|
||||
return@put DoubleValue(if (value.obj.isIn(tag)) 1.0 else 0.0)
|
||||
}
|
||||
value.functions.put("is_of") {
|
||||
val identifier = Identifier(it.getString(0))
|
||||
return@put DoubleValue(if (value.obj.matchesId(identifier)) 1.0 else 0.0)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
fun QueryStruct.addStandardFunctions(): QueryStruct {
|
||||
functions.putAll(generalFunctions)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : QueryStruct> T.addFunctions(functions: Map<String, java.util.function.Function<MoParams, Any>>): T {
|
||||
this.functions.putAll(functions)
|
||||
return this
|
||||
}
|
||||
|
||||
fun MoLangEnvironment.getQueryStruct(name: String = "query") = structs.getOrPut(name) { QueryStruct(hashMapOf()).addStandardFunctions() } as QueryStruct
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
|
||||
/**
|
||||
* A [MoValue] that just wraps around some other object value. It's for good and valid reasons.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 2nd, 2023
|
||||
*/
|
||||
class ObjectValue<T>(
|
||||
var obj: T,
|
||||
val stringify: (T) -> String = { it.toString() },
|
||||
val doublify: (T) -> Double = { throw NotImplementedError("Doublify not implemented for this object value, are you doing weird molang") }
|
||||
) : QueryStruct(hashMapOf()) {
|
||||
override fun value() = this
|
||||
override fun asDouble() = doublify(obj)
|
||||
override fun asString() = stringify(obj)
|
||||
}
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
@@ -631,6 +633,13 @@ open class PokemonProperties {
|
||||
return pieces.joinToString(separator)
|
||||
}
|
||||
|
||||
fun asStruct(): VariableStruct {
|
||||
val struct = VariableStruct()
|
||||
species?.let { struct.setDirectly("species", StringValue(it)) }
|
||||
// todo a bunch more
|
||||
return struct
|
||||
}
|
||||
|
||||
fun updateAspects() {
|
||||
val aspects = mutableSetOf<String>()
|
||||
AspectProvider.providers.forEach { aspects.addAll(it.provide(this)) }
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
|
||||
import com.cobblemon.mod.common.api.spawning.rules.component.FilterRuleComponent
|
||||
import com.cobblemon.mod.common.api.spawning.rules.component.LocationRuleCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.rules.component.SpawnRuleComponent
|
||||
import com.cobblemon.mod.common.api.spawning.rules.component.WeightTweakRuleComponent
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.ConditionalSpawningContextSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.ExpressionSpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.ExpressionSpawningContextSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawningContextSelector
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnDetailSelectorAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnRuleComponentAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawningConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawningContextSelectorAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TextAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* All of the [SpawnRule]s that will be applied as global [SpawningInfluence]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since September 30th, 2023
|
||||
*/
|
||||
object CobblemonSpawnRules : JsonDataRegistry<SpawnRule> {
|
||||
override val gson = GsonBuilder()
|
||||
.registerTypeAdapter(SpawnRuleComponent::class.java, SpawnRuleComponentAdapter)
|
||||
.registerTypeAdapter(SpawnDetailSelector::class.java, SpawnDetailSelectorAdapter)
|
||||
.registerTypeAdapter(SpawningContextSelector::class.java, SpawningContextSelectorAdapter)
|
||||
.registerTypeAdapter(SpawningCondition::class.java, SpawningConditionAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(Text::class.java, TextAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.get(SpawnRule::class.java)
|
||||
override val resourcePath = "spawn_rules"
|
||||
|
||||
init {
|
||||
SpawnRuleComponent.register<WeightTweakRuleComponent>("weight")
|
||||
SpawnRuleComponent.register<FilterRuleComponent>("filter")
|
||||
SpawnRuleComponent.register<LocationRuleCalculator>("location")
|
||||
|
||||
SpawnDetailSelector.register<ExpressionSpawnDetailSelector>("expression")
|
||||
|
||||
SpawningContextSelector.register<ExpressionSpawningContextSelector>("expression")
|
||||
SpawningContextSelector.register<ConditionalSpawningContextSelector>("conditional")
|
||||
}
|
||||
|
||||
val rules = mutableMapOf<Identifier, SpawnRule>()
|
||||
|
||||
override fun reload(data: Map<Identifier, SpawnRule>) {
|
||||
rules.clear()
|
||||
rules.putAll(data)
|
||||
data.forEach { (id, value) -> value.id = id }
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override val id: Identifier = cobblemonResource("spawn_rules")
|
||||
override val type: ResourceType = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonSpawnRules>()
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
}
|
||||
+1
-1
@@ -55,5 +55,5 @@ interface AppendageCondition {
|
||||
|
||||
fun getAppendages(spawningCondition: SpawningCondition<*>) = appendages.filter { it.spawningConditionFits(spawningCondition) }.map { it.clazz }
|
||||
}
|
||||
fun fits(ctx: SpawningContext, detail: SpawnDetail): Boolean
|
||||
fun fits(ctx: SpawningContext): Boolean
|
||||
}
|
||||
+2
-2
@@ -26,8 +26,8 @@ abstract class AreaTypeSpawningCondition<T : AreaSpawningContext> : SpawningCond
|
||||
var maxHeight: Int? = null
|
||||
var neededNearbyBlocks: MutableList<RegistryLikeCondition<Block>>? = null
|
||||
|
||||
override fun fits(ctx: T, detail: SpawnDetail): Boolean {
|
||||
if (!super.fits(ctx, detail)) {
|
||||
override fun fits(ctx: T): Boolean {
|
||||
if (!super.fits(ctx)) {
|
||||
return false
|
||||
} else if (minHeight != null && ctx.height < minHeight!!) {
|
||||
return false
|
||||
|
||||
+3
-3
@@ -30,11 +30,11 @@ class CompositeSpawningCondition {
|
||||
var conditions = mutableListOf<SpawningCondition<*>>()
|
||||
var anticonditions = mutableListOf<SpawningCondition<*>>()
|
||||
|
||||
fun satisfiedBy(ctx: SpawningContext, detail: SpawnDetail): Boolean {
|
||||
return if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(ctx, detail) }) {
|
||||
fun satisfiedBy(ctx: SpawningContext): Boolean {
|
||||
return if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(ctx) }) {
|
||||
false
|
||||
} else {
|
||||
!(anticonditions.isNotEmpty() && anticonditions.any { it.isSatisfiedBy(ctx, detail) })
|
||||
!(anticonditions.isNotEmpty() && anticonditions.any { it.isSatisfiedBy(ctx) })
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -24,8 +24,8 @@ import net.minecraft.block.Block
|
||||
abstract class GroundedTypeSpawningCondition<T : GroundedSpawningContext> : AreaTypeSpawningCondition<T>() {
|
||||
var neededBaseBlocks: MutableList<RegistryLikeCondition<Block>>? = null
|
||||
|
||||
override fun fits(ctx: T, detail: SpawnDetail): Boolean {
|
||||
return if (!super.fits(ctx, detail)) {
|
||||
override fun fits(ctx: T): Boolean {
|
||||
return if (!super.fits(ctx)) {
|
||||
false
|
||||
} else if (minHeight != null && ctx.height < minHeight!!) {
|
||||
return false
|
||||
|
||||
+4
-16
@@ -11,8 +11,6 @@ package com.cobblemon.mod.common.api.spawning.condition
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.spawning.MoonPhaseRange
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.condition.ListCheckMode.ALL
|
||||
import com.cobblemon.mod.common.api.spawning.condition.ListCheckMode.ANY
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.Merger
|
||||
@@ -55,8 +53,6 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
var isRaining: Boolean? = null
|
||||
var isThundering: Boolean? = null
|
||||
var timeRange: TimeRange? = null
|
||||
var labels: MutableList<String>? = null
|
||||
var labelMode = ANY
|
||||
var structures: MutableList<Either<Identifier, TagKey<Structure>>>? = null
|
||||
|
||||
@Transient
|
||||
@@ -65,15 +61,15 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
abstract fun contextClass(): Class<out T>
|
||||
fun contextMatches(ctx: SpawningContext) = contextClass().isAssignableFrom(ctx::class.java)
|
||||
|
||||
fun isSatisfiedBy(ctx: SpawningContext, detail: SpawnDetail): Boolean {
|
||||
fun isSatisfiedBy(ctx: SpawningContext): Boolean {
|
||||
return if (contextMatches(ctx)) {
|
||||
fits(ctx as T, detail)
|
||||
fits(ctx as T)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun fits(ctx: T, detail: SpawnDetail): Boolean {
|
||||
protected open fun fits(ctx: T): Boolean {
|
||||
if (ctx.position.x < minX.orMin() || ctx.position.x > maxX.orMax()) {
|
||||
return false
|
||||
} else if (ctx.position.y < minY.orMin() || ctx.position.y > maxY.orMax()) {
|
||||
@@ -96,14 +92,7 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
return false
|
||||
} else if (isThundering != null && ctx.world.isThundering != isThundering!!) {
|
||||
return false
|
||||
} else if (labels != null && labels!!.isNotEmpty() &&
|
||||
(
|
||||
(labelMode == ANY && labels!!.none { it in detail.labels }) ||
|
||||
(labelMode == ALL && labels!!.any { it !in detail.labels })
|
||||
)
|
||||
) {
|
||||
return false
|
||||
} else if (appendages.any { !it.fits(ctx, detail) }) {
|
||||
} else if (appendages.any { !it.fits(ctx) }) {
|
||||
return false
|
||||
} else if (structures != null && structures!!.isNotEmpty() &&
|
||||
structures!!.let { structures ->
|
||||
@@ -123,7 +112,6 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
open fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
|
||||
dimensions = merger.merge(dimensions, other.dimensions)?.toMutableList()
|
||||
biomes = merger.merge(biomes, other.biomes)?.toMutableSet()
|
||||
labels = merger.merge(labels, other.labels)?.toMutableList()
|
||||
moonPhase = merger.mergeSingle(moonPhase, other.moonPhase)
|
||||
canSeeSky = merger.mergeSingle(canSeeSky, other.canSeeSky)
|
||||
minX = merger.mergeSingle(minX, other.minX)
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawningContext> : Ar
|
||||
var fluidIsSource: Boolean? = null
|
||||
var fluid: RegistryLikeCondition<Fluid>? = null
|
||||
|
||||
override fun fits(ctx: T, detail: SpawnDetail): Boolean {
|
||||
return if (!super.fits(ctx, detail)) {
|
||||
override fun fits(ctx: T): Boolean {
|
||||
return if (!super.fits(ctx)) {
|
||||
false
|
||||
} else if (minHeight != null && ctx.height < minHeight!!) {
|
||||
return false
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ abstract class SurfaceTypeSpawningCondition<T : SurfaceSpawningContext> : AreaTy
|
||||
var maxDepth: Int? = null
|
||||
var fluid: RegistryLikeCondition<Fluid>? = null
|
||||
|
||||
override fun fits(ctx: T, detail: SpawnDetail): Boolean {
|
||||
return if (!super.fits(ctx, detail)) {
|
||||
override fun fits(ctx: T): Boolean {
|
||||
return if (!super.fits(ctx)) {
|
||||
false
|
||||
} else if (minDepth != null && ctx.depth < minDepth!!) {
|
||||
false
|
||||
|
||||
+2
-1
@@ -49,7 +49,8 @@ interface AreaContextResolver {
|
||||
pos.set(x, y, z)
|
||||
val vec = pos.toVec3d()
|
||||
if (slice.nearbyEntityPositions.none { it.isInRange(vec, config.minimumDistanceBetweenEntities) && it != slice.cause.entity }) {
|
||||
val fittedContextCalculator = contextCalculators.firstOrNull { it.fits(input) }
|
||||
val fittedContextCalculator = contextCalculators
|
||||
.firstOrNull { calc -> calc.fits(input) && input.spawner.influences.none { !it.isAllowedPosition(input.world, input.position, calc) } }
|
||||
if (fittedContextCalculator != null) {
|
||||
val context = fittedContextCalculator.calculate(input)
|
||||
if (context != null) {
|
||||
|
||||
+23
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.context
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
@@ -80,6 +83,9 @@ abstract class SpawningContext {
|
||||
val biomeName: Identifier
|
||||
get() = this.biomeRegistry.getId(biome)!!
|
||||
|
||||
private val struct = VariableStruct()
|
||||
private var structCompiled = false
|
||||
|
||||
class StructureChunkCache {
|
||||
val missingTags = mutableSetOf<TagKey<Structure>>()
|
||||
val foundTags = mutableSetOf<TagKey<Structure>>()
|
||||
@@ -159,4 +165,21 @@ abstract class SpawningContext {
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
fun getOrSetupStruct(): VariableStruct {
|
||||
if (structCompiled) {
|
||||
return struct
|
||||
}
|
||||
|
||||
struct.setDirectly("light", DoubleValue(light.toDouble()))
|
||||
struct.setDirectly("x", DoubleValue(position.x.toDouble()))
|
||||
struct.setDirectly("y", DoubleValue(position.y.toDouble()))
|
||||
struct.setDirectly("z", DoubleValue(position.z.toDouble()))
|
||||
struct.setDirectly("moon_phase", DoubleValue(moonPhase.toDouble()))
|
||||
struct.setDirectly("world", ObjectValue(world.registryManager.get(RegistryKeys.WORLD).getEntry(world)))
|
||||
struct.setDirectly("biome", ObjectValue(biomeRegistry.getEntry(biome)))
|
||||
|
||||
structCompiled = true
|
||||
return struct
|
||||
}
|
||||
}
|
||||
+4
@@ -50,6 +50,7 @@ interface FlooredSpawningContextCalculator<T : FlooredSpawningContext> : AreaSpa
|
||||
*/
|
||||
object GroundedSpawningContextCalculator : FlooredSpawningContextCalculator<GroundedSpawningContext> {
|
||||
// TODO expand base condition
|
||||
override val name = "grounded"
|
||||
override val baseCondition: (BlockState) -> Boolean = isSolidCondition
|
||||
override val surroundingCondition: (BlockState) -> Boolean = isAirCondition
|
||||
|
||||
@@ -76,6 +77,7 @@ object GroundedSpawningContextCalculator : FlooredSpawningContextCalculator<Grou
|
||||
* @since February 7th, 2022
|
||||
*/
|
||||
object SeafloorSpawningContextCalculator : FlooredSpawningContextCalculator<SeafloorSpawningContext> {
|
||||
override val name = "seafloor"
|
||||
override val baseCondition: (BlockState) -> Boolean = isSolidCondition
|
||||
override val surroundingCondition: (BlockState) -> Boolean = isWaterCondition
|
||||
|
||||
@@ -102,6 +104,7 @@ object SeafloorSpawningContextCalculator : FlooredSpawningContextCalculator<Seaf
|
||||
* @since February 7th, 2022
|
||||
*/
|
||||
object LavafloorSpawningContextCalculator : FlooredSpawningContextCalculator<LavafloorSpawningContext> {
|
||||
override val name = "lavafloor"
|
||||
override val baseCondition: (BlockState) -> Boolean = isSolidCondition
|
||||
override val surroundingCondition: (BlockState) -> Boolean = isLavaCondition
|
||||
|
||||
@@ -129,6 +132,7 @@ object LavafloorSpawningContextCalculator : FlooredSpawningContextCalculator<Lav
|
||||
* @since December 15th, 2022
|
||||
*/
|
||||
object SurfaceSpawningContextCalculator : FlooredSpawningContextCalculator<SurfaceSpawningContext> {
|
||||
override val name = "surface"
|
||||
override val baseCondition: (BlockState) -> Boolean = { !it.fluidState.isEmpty }
|
||||
override val surroundingCondition: (BlockState) -> Boolean = isAirCondition
|
||||
|
||||
|
||||
+2
@@ -48,6 +48,8 @@ interface SpawningContextCalculator<I : SpawningContextInput, O : SpawningContex
|
||||
}
|
||||
}
|
||||
|
||||
val name: String
|
||||
|
||||
/** Tries creating a [SpawningContext] from the given input. Returning null should be a last resort. */
|
||||
fun calculate(input: I): O?
|
||||
}
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ import net.minecraft.util.math.MathHelper.ceil
|
||||
* @since February 7th, 2022
|
||||
*/
|
||||
object SubmergedSpawningContextCalculator : AreaSpawningContextCalculator<SubmergedSpawningContext> {
|
||||
override val name = "submerged"
|
||||
val fluidConditions = mutableListOf(
|
||||
isWaterCondition,
|
||||
isLavaCondition
|
||||
|
||||
+4
-1
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.detail
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -50,6 +50,9 @@ class PokemonSpawnAction(
|
||||
entity.pokemon.swapHeldItem(heldItem)
|
||||
}
|
||||
entity.drops = detail.drops
|
||||
// Useful debug code in situations where you want to find spawns
|
||||
// val fireworkRocketEntity = FireworkRocketEntity(ctx.world, ctx.position.x.toDouble(), ctx.position.y.toDouble() + 2, ctx.position.z.toDouble(), ItemStack(Items.FIREWORK_ROCKET))
|
||||
// ctx.world.spawnEntity(fireworkRocketEntity)
|
||||
return entity
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -69,7 +69,7 @@ class PokemonSpawnDetail : SpawnDetail() {
|
||||
}
|
||||
|
||||
override fun autoLabel() {
|
||||
super.autoLabel()
|
||||
val pokemonStruct = pokemon.asStruct()
|
||||
if (pokemon.species != null) {
|
||||
val species = PokemonSpecies.getByIdentifier(pokemon.species!!.asIdentifierDefaultingNamespace())
|
||||
if (species != null) {
|
||||
@@ -87,6 +87,9 @@ class PokemonSpawnDetail : SpawnDetail() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct.setDirectly("pokemon", pokemonStruct)
|
||||
super.autoLabel()
|
||||
}
|
||||
|
||||
fun getDerivedLevelRange() = levelRange.let { levelRange ->
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.detail
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.ArrayStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.ModDependant
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.condition.CompositeSpawningCondition
|
||||
@@ -50,20 +54,32 @@ abstract class SpawnDetail : ModDependant {
|
||||
|
||||
var labels = mutableListOf<String>()
|
||||
|
||||
val struct: VariableStruct = VariableStruct()
|
||||
|
||||
override var neededInstalledMods = listOf<String>()
|
||||
override var neededUninstalledMods = listOf<String>()
|
||||
|
||||
open fun autoLabel() {}
|
||||
open fun autoLabel() {
|
||||
struct.setDirectly("weight", DoubleValue(weight.toDouble()))
|
||||
struct.setDirectly("percentage", DoubleValue(percentage.toDouble()))
|
||||
struct.setDirectly("id", StringValue(id))
|
||||
struct.setDirectly("bucket", StringValue(bucket.name))
|
||||
struct.setDirectly("width", DoubleValue(width.toDouble()))
|
||||
struct.setDirectly("height", DoubleValue(height.toDouble()))
|
||||
struct.setDirectly("context", StringValue(context.name))
|
||||
struct.setDirectly("labels", ArrayStruct(labels.mapIndexed { index, s -> "$index" to StringValue(s) }.toMap()))
|
||||
}
|
||||
|
||||
open fun getName() = displayName?.asTranslated() ?: id.text()
|
||||
|
||||
open fun isSatisfiedBy(ctx: SpawningContext): Boolean {
|
||||
if (!ctx.preFilter(this)) {
|
||||
return false
|
||||
} else if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(ctx, this) }) {
|
||||
} else if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(ctx) }) {
|
||||
return false
|
||||
} else if (anticonditions.isNotEmpty() && anticonditions.any { it.isSatisfiedBy(ctx, this) }) {
|
||||
} else if (anticonditions.isNotEmpty() && anticonditions.any { it.isSatisfiedBy(ctx) }) {
|
||||
return false
|
||||
} else if (compositeCondition?.satisfiedBy(ctx, this) == false) {
|
||||
} else if (compositeCondition?.satisfiedBy(ctx) == false) {
|
||||
return false
|
||||
} else if (!ctx.postFilter(this)) {
|
||||
return false
|
||||
|
||||
+5
@@ -11,9 +11,12 @@ package com.cobblemon.mod.common.api.spawning.influence
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* An influence over spawning that can affect various parts of the spawning process. These can be attached to
|
||||
@@ -35,4 +38,6 @@ interface SpawningInfluence {
|
||||
fun affectSpawn(entity: Entity) {}
|
||||
/** Applies some influence over the weight of spawn buckets. */
|
||||
fun affectBucketWeight(bucket: SpawnBucket, weight: Float): Float = weight
|
||||
/** Filters positions that could be usable for a spawning context calculator */
|
||||
fun isAllowedPosition(world: ServerWorld, pos: BlockPos, contextCalculator: SpawningContextCalculator<*, *>): Boolean = true
|
||||
}
|
||||
+2
-2
@@ -31,8 +31,8 @@ class WeightMultiplier : SpawningInfluence {
|
||||
var multiplier = 1F
|
||||
|
||||
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
|
||||
val meetsConditions = (conditions.isEmpty() || conditions.any { it.isSatisfiedBy(ctx, detail) })
|
||||
&& (anticonditions.isEmpty() || anticonditions.none { it.isSatisfiedBy(ctx, detail) })
|
||||
val meetsConditions = (conditions.isEmpty() || conditions.any { it.isSatisfiedBy(ctx) })
|
||||
&& (anticonditions.isEmpty() || anticonditions.none { it.isSatisfiedBy(ctx) })
|
||||
return if (meetsConditions) multiplier * weight else weight
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.rules.component.SpawnRuleComponent
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* A bundling of [SpawnRuleComponent]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since September 30th, 2023
|
||||
*/
|
||||
class SpawnRule {
|
||||
|
||||
lateinit var id: Identifier
|
||||
val displayName: Text = "Spawn Rule".text()
|
||||
// val pool: String? = null Kinda difficult to see how this would get used in practice.
|
||||
// var enabled = true One would expect there to be some kind of persistence if this could be enabled and disabled willy nilly.
|
||||
val components: MutableList<SpawnRuleComponent> = mutableListOf()
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.component
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.ast.BooleanExpression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.AllSpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.AllSpawningContextSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawningContextSelector
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
|
||||
/**
|
||||
* A rule component that targets specific spawns and contexts and judges whether it
|
||||
* is allowed to spawn. This runs prior to the regular SpawnDetail conditions.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 1st, 2023
|
||||
*/
|
||||
class FilterRuleComponent : SpawnRuleComponent {
|
||||
@Transient
|
||||
val runtime = MoLangRuntime()
|
||||
|
||||
val spawnSelector: SpawnDetailSelector = AllSpawnDetailSelector
|
||||
val contextSelector: SpawningContextSelector = AllSpawningContextSelector
|
||||
val allow: Expression = BooleanExpression(true)
|
||||
|
||||
override fun affectSpawnable(detail: SpawnDetail, ctx: SpawningContext): Boolean {
|
||||
return if (spawnSelector.selects(detail) && contextSelector.selects(ctx)) {
|
||||
runtime.environment.setSimpleVariable("spawn", detail.struct)
|
||||
runtime.environment.setSimpleVariable("context", ctx.getOrSetupStruct())
|
||||
runtime.resolveBoolean(allow)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.component
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asDimensionTypeMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asWorldMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.context.calculators.SpawningContextCalculator
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.dimension.DimensionType
|
||||
|
||||
/**
|
||||
* An early rule that filters possible locations that would go into a [SpawningContext].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 2nd, 2023
|
||||
*/
|
||||
class LocationRuleCalculator : SpawnRuleComponent {
|
||||
@Transient
|
||||
val runtime = MoLangRuntime().also { it.environment.getQueryStruct() }
|
||||
@Transient
|
||||
private val reusableX = DoubleValue(0.0)
|
||||
@Transient
|
||||
private val reusableY = DoubleValue(0.0)
|
||||
@Transient
|
||||
private val reusableZ = DoubleValue(0.0)
|
||||
@Transient
|
||||
private val reusableContext = StringValue("")
|
||||
@Transient
|
||||
private lateinit var reusableWorldValue: ObjectValue<RegistryEntry<World>>
|
||||
@Transient
|
||||
private lateinit var reusableDimensionTypeValue: ObjectValue<RegistryEntry<DimensionType>>
|
||||
|
||||
val allow = "true".asExpression()
|
||||
|
||||
override fun isAllowedPosition(
|
||||
world: ServerWorld,
|
||||
pos: BlockPos,
|
||||
contextCalculator: SpawningContextCalculator<*, *>
|
||||
): Boolean {
|
||||
reusableX.value = pos.x.toDouble()
|
||||
reusableY.value = pos.y.toDouble()
|
||||
reusableZ.value = pos.z.toDouble()
|
||||
reusableContext.value = contextCalculator.name
|
||||
|
||||
if (!this::reusableWorldValue.isInitialized) {
|
||||
reusableWorldValue = world.registryManager.get(RegistryKeys.WORLD).getEntry(world).asWorldMoLangValue()
|
||||
} else {
|
||||
reusableWorldValue.obj = world.registryManager.get(RegistryKeys.WORLD).getEntry(world)
|
||||
}
|
||||
|
||||
if (!this::reusableDimensionTypeValue.isInitialized) {
|
||||
reusableDimensionTypeValue = world.dimensionEntry.asDimensionTypeMoLangValue()
|
||||
} else {
|
||||
reusableDimensionTypeValue.obj = world.dimensionEntry
|
||||
}
|
||||
|
||||
runtime.environment.setSimpleVariable("x", reusableX)
|
||||
runtime.environment.setSimpleVariable("y", reusableY)
|
||||
runtime.environment.setSimpleVariable("z", reusableZ)
|
||||
runtime.environment.setSimpleVariable("context", reusableContext)
|
||||
runtime.environment.setSimpleVariable("world", reusableWorldValue)
|
||||
runtime.environment.setSimpleVariable("dimension_type", reusableDimensionTypeValue)
|
||||
return runtime.resolveBoolean(allow)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.component
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
|
||||
/**
|
||||
* Responsible for changing a thing about spawns. A spawn rule may have many components like this.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since September 30th, 2023
|
||||
*/
|
||||
interface SpawnRuleComponent : SpawningInfluence {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out SpawnRuleComponent>>()
|
||||
|
||||
inline fun <reified T : SpawnRuleComponent> register(type: String) {
|
||||
types[type] = T::class.java
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.component
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.AllSpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.AllSpawningContextSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawningContextSelector
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
|
||||
/**
|
||||
* A rule component that alters the weight of spawns at specific contexts.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 1st, 2023
|
||||
*/
|
||||
class WeightTweakRuleComponent : SpawnRuleComponent {
|
||||
val spawnSelector: SpawnDetailSelector = AllSpawnDetailSelector
|
||||
val contextSelector: SpawningContextSelector = AllSpawningContextSelector
|
||||
val weight: Expression = "v.weight".asExpression()
|
||||
|
||||
@Transient
|
||||
val runtime = MoLangRuntime()
|
||||
|
||||
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
|
||||
return if (spawnSelector.selects(detail) && contextSelector.selects(ctx)) {
|
||||
runtime.environment.setSimpleVariable("spawn", detail.struct)
|
||||
runtime.environment.setSimpleVariable("weight", DoubleValue(weight.toDouble()))
|
||||
runtime.resolveFloat(this.weight)
|
||||
} else {
|
||||
weight
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.selector
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
|
||||
object AllSpawnDetailSelector : SpawnDetailSelector {
|
||||
override fun selects(spawnDetail: SpawnDetail) = true
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.selector
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
|
||||
object AllSpawningContextSelector : SpawningContextSelector {
|
||||
override fun selects(ctx: SpawningContext) = true
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.selector
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
|
||||
class ConditionalSpawningContextSelector : SpawningContextSelector {
|
||||
var conditions = mutableListOf<SpawningCondition<*>>()
|
||||
var anticonditions = mutableListOf<SpawningCondition<*>>()
|
||||
|
||||
override fun selects(ctx: SpawningContext): Boolean {
|
||||
return if (conditions.isNotEmpty() && conditions.none { it.isSatisfiedBy(ctx) }) {
|
||||
false
|
||||
} else {
|
||||
!(anticonditions.isNotEmpty() && anticonditions.any { it.isSatisfiedBy(ctx) })
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.selector
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
|
||||
class ExpressionSpawnDetailSelector : SpawnDetailSelector {
|
||||
@Transient
|
||||
val runtime = MoLangRuntime()
|
||||
var expression = "true".asExpression()
|
||||
|
||||
override fun selects(spawnDetail: SpawnDetail): Boolean {
|
||||
runtime.environment.setSimpleVariable("spawn", spawnDetail.struct)
|
||||
return runtime.resolveBoolean(expression)
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.selector
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
|
||||
class ExpressionSpawningContextSelector : SpawningContextSelector {
|
||||
@Transient
|
||||
val runtime = MoLangRuntime()
|
||||
var expression = "true".asExpression()
|
||||
|
||||
override fun selects(ctx: SpawningContext): Boolean {
|
||||
runtime.environment.setSimpleVariable("context", ctx.getOrSetupStruct())
|
||||
return runtime.resolveBoolean(expression)
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.selector
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
|
||||
interface SpawnDetailSelector {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out SpawnDetailSelector>>()
|
||||
|
||||
inline fun <reified T : SpawnDetailSelector> register(type: String) {
|
||||
types[type] = T::class.java
|
||||
}
|
||||
}
|
||||
fun selects(spawnDetail: SpawnDetail): Boolean
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.rules.selector
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
|
||||
interface SpawningContextSelector {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out SpawningContextSelector>>()
|
||||
|
||||
inline fun <reified T : SpawningContextSelector> register(type: String) {
|
||||
types[type] = T::class.java
|
||||
}
|
||||
}
|
||||
|
||||
fun selects(ctx: SpawningContext): Boolean
|
||||
}
|
||||
+29
-14
@@ -26,8 +26,13 @@ import kotlin.random.Random
|
||||
* [FlatContextWeightedSelector] because here a spawning context type only appearing once
|
||||
* will not make it any less likely to be selected.
|
||||
*
|
||||
* A spawn detail's weight when selecting between all possible spawn details will be the
|
||||
* highest of its contextual weights. In other words, if a spawn is possible at both A and
|
||||
* B contexts but is weighed more highly at A due to a weight multiplier, it will use the
|
||||
* weight of the spawn at A when choosing which spawn will run.
|
||||
*
|
||||
* When choosing which context a specific spawn detail will spawn at once that spawn detail
|
||||
* has been chosen, it does a flat random across the possible contexts.
|
||||
* has been chosen, it does a context-weighted random selection across those contexts.
|
||||
*
|
||||
* At a glance:
|
||||
* - Spawn detail selection is flat across context quantity
|
||||
@@ -37,10 +42,22 @@ import kotlin.random.Random
|
||||
* @since July 10th, 2022
|
||||
*/
|
||||
open class FlatSelector : SpawningSelector {
|
||||
open fun getWeight(contextType: RegisteredSpawningContext<*>) = contextType.getWeight()
|
||||
protected class SelectingSpawnInformation {
|
||||
val spawningContexts = mutableMapOf<SpawningContext, Float>()
|
||||
var highestWeight = 0F
|
||||
|
||||
fun add(spawningContext: SpawningContext, contextWeight: Float) {
|
||||
spawningContexts[spawningContext] = contextWeight
|
||||
if (contextWeight > highestWeight) {
|
||||
highestWeight = contextWeight
|
||||
}
|
||||
}
|
||||
|
||||
fun chooseContext() = spawningContexts.entries.weightedSelection { it.value }!!.key
|
||||
}
|
||||
|
||||
protected class ContextSelectionData(
|
||||
val spawnsToContexts: MutableMap<SpawnDetail, MutableList<SpawningContext>>,
|
||||
val spawnsToContexts: MutableMap<SpawnDetail, SelectingSpawnInformation>,
|
||||
var percentSum: Float
|
||||
) {
|
||||
val size: Int
|
||||
@@ -51,7 +68,7 @@ open class FlatSelector : SpawningSelector {
|
||||
spawner: Spawner,
|
||||
contexts: List<SpawningContext>
|
||||
): ContextSelectionData {
|
||||
val spawnsToContexts: MutableMap<SpawnDetail, MutableList<SpawningContext>> = mutableMapOf()
|
||||
val spawnsToContexts: MutableMap<SpawnDetail, SelectingSpawnInformation> = mutableMapOf()
|
||||
var percentSum = 0F
|
||||
|
||||
contexts.forEach { ctx ->
|
||||
@@ -65,9 +82,9 @@ open class FlatSelector : SpawningSelector {
|
||||
|
||||
val selectingSpawnInformation = spawnsToContexts.getOrPut(
|
||||
it,
|
||||
::mutableListOf
|
||||
::SelectingSpawnInformation
|
||||
)
|
||||
selectingSpawnInformation.add(ctx)
|
||||
selectingSpawnInformation.add(ctx, ctx.getWeight(it))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +104,6 @@ open class FlatSelector : SpawningSelector {
|
||||
val spawnsToContexts = selectionData.spawnsToContexts
|
||||
var percentSum = selectionData.percentSum
|
||||
|
||||
|
||||
// First pass is doing percentage checks.
|
||||
if (percentSum > 0) {
|
||||
|
||||
@@ -111,15 +127,14 @@ open class FlatSelector : SpawningSelector {
|
||||
if (spawnDetail.percentage > 0) {
|
||||
percentSum += spawnDetail.percentage
|
||||
if (percentSum >= selectedPercentage) {
|
||||
return info.random() to spawnDetail
|
||||
return info.chooseContext() to spawnDetail
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val selectedSpawn = spawnsToContexts.entries.toList().weightedSelection { it.key.weight }!!
|
||||
|
||||
return selectedSpawn.value.random() to selectedSpawn.key
|
||||
val selectedSpawn = spawnsToContexts.entries.toList().weightedSelection { it.value.highestWeight }!!
|
||||
return selectedSpawn.value.chooseContext() to selectedSpawn.key
|
||||
}
|
||||
|
||||
override fun getTotalWeights(
|
||||
@@ -129,13 +144,13 @@ open class FlatSelector : SpawningSelector {
|
||||
val selectionData = getSelectionData(spawner, contexts)
|
||||
|
||||
if (selectionData.size == 0) {
|
||||
return mapOf()
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
val totalWeights = mutableMapOf<SpawnDetail, Float>()
|
||||
|
||||
for (spawnDetail in selectionData.spawnsToContexts.keys) {
|
||||
totalWeights[spawnDetail] = spawnDetail.weight
|
||||
for ((spawnDetail, info) in selectionData.spawnsToContexts.entries) {
|
||||
totalWeights[spawnDetail] = info.highestWeight
|
||||
}
|
||||
|
||||
return totalWeights
|
||||
|
||||
-1
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.api.spawning.SpawnerManager
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
|
||||
/**
|
||||
* A spawner that works within a fixed area, and ticks on its own. The location
|
||||
|
||||
+3
@@ -9,10 +9,12 @@
|
||||
package com.cobblemon.mod.common.api.spawning.spawner
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnerManager
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
@@ -31,6 +33,7 @@ object PlayerSpawnerFactory {
|
||||
val influences = influenceBuilders.mapNotNull { it(player) }
|
||||
return PlayerSpawner(player, spawns, spawnerManager).also {
|
||||
it.influences.addAll(influences)
|
||||
it.influences.addAll(CobblemonSpawnRules.rules.values.flatMap(SpawnRule::components))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ data class BedrockAnimation(
|
||||
val boneTimelines: Map<String, BedrockBoneTimeline>
|
||||
) {
|
||||
companion object {
|
||||
val functionMappings = mutableMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val functionMappings = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val sharedRuntime = MoLangRuntime().also {
|
||||
it.environment.structs["query"] = it.environment.structs["variable"]
|
||||
it.environment.structs["script"] = QueryStruct(functionMappings)
|
||||
|
||||
@@ -24,12 +24,12 @@ import com.cobblemon.mod.common.api.pokemon.feature.GlobalSpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureAssignments
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnDetailPresets
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
|
||||
import com.cobblemon.mod.common.pokemon.properties.PropertiesCompletionProvider
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
@@ -62,6 +62,7 @@ object CobblemonDataProvider : DataProvider {
|
||||
this.register(PokeBalls)
|
||||
this.register(PropertiesCompletionProvider)
|
||||
this.register(SpawnDetailPresets)
|
||||
this.register(CobblemonSpawnRules)
|
||||
this.register(CobblemonMechanics)
|
||||
this.register(BagItems)
|
||||
this.register(NPCClasses)
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.util.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.ExpressionSpawnDetailSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawnDetailSelector
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object SpawnDetailSelectorAdapter : JsonDeserializer<SpawnDetailSelector> {
|
||||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): SpawnDetailSelector {
|
||||
return if (json.isJsonPrimitive) {
|
||||
val expression = json.asString.asExpression()
|
||||
ExpressionSpawnDetailSelector().also { it.expression = expression }
|
||||
} else {
|
||||
json as JsonObject
|
||||
val type = json.get("type").asString
|
||||
val clazz = SpawnDetailSelector.types[type] ?: throw IllegalArgumentException("Unknown spawn detail selector type: $type")
|
||||
ctx.deserialize(json, clazz)
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.util.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.rules.component.SpawnRuleComponent
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object SpawnRuleComponentAdapter : JsonDeserializer<SpawnRuleComponent> {
|
||||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): SpawnRuleComponent {
|
||||
json as JsonObject
|
||||
val type = json.get("type").asString
|
||||
val clazz = SpawnRuleComponent.types[type] ?: throw IllegalArgumentException("Unknown spawn rule component type: $type")
|
||||
return ctx.deserialize(json, clazz)
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.util.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.ConditionalSpawningContextSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.ExpressionSpawningContextSelector
|
||||
import com.cobblemon.mod.common.api.spawning.rules.selector.SpawningContextSelector
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object SpawningContextSelectorAdapter : JsonDeserializer<SpawningContextSelector> {
|
||||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): SpawningContextSelector {
|
||||
return if (json.isJsonPrimitive) {
|
||||
val expression = json.asString.asExpression()
|
||||
ExpressionSpawningContextSelector().also { it.expression = expression }
|
||||
} else {
|
||||
json as JsonObject
|
||||
val type = json.get("type")?.asString ?: return ctx.deserialize(json, ConditionalSpawningContextSelector::class.java)
|
||||
val clazz = SpawningContextSelector.types[type] ?: throw IllegalArgumentException("Unknown spawn detail selector type: $type")
|
||||
ctx.deserialize(json, clazz)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.util.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import java.lang.reflect.Type
|
||||
import net.minecraft.text.Text
|
||||
|
||||
object TextAdapter : JsonDeserializer<Text> {
|
||||
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext) = json.asString.text()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"displayName": "Pikachu Daylight Multiplier",
|
||||
"components": [
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>local.com.bedrockk</groupId>
|
||||
<artifactId>molang</artifactId>
|
||||
<version>1.1.8</version>
|
||||
</project>
|
||||
+3
-3
@@ -3,10 +3,10 @@
|
||||
<groupId>local.com.bedrockk</groupId>
|
||||
<artifactId>molang</artifactId>
|
||||
<versioning>
|
||||
<release>1.1.5</release>
|
||||
<release>1.1.8</release>
|
||||
<versions>
|
||||
<version>1.1.5</version>
|
||||
<version>1.1.8</version>
|
||||
</versions>
|
||||
<lastUpdated>20221939127999</lastUpdated>
|
||||
<lastUpdated>20221949138999</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
|
||||
@@ -25,7 +25,7 @@ versions:
|
||||
|
||||
# common
|
||||
graal: 22.3.0
|
||||
molang: 1.1.5
|
||||
molang: 1.1.8
|
||||
|
||||
# test
|
||||
junit: 5.9.0
|
||||
|
||||
Reference in New Issue
Block a user