The End gets Pokémon: a dimension zone with Cobblemon's End lines
Adrian, 2026-11-02: the End looked barren. The End is now a zone of its own (Lv 50-70, world/zones.json -> dimensions; Zones.at returns it anywhere in the End). tools/zone_spawns.py copies every line Cobblemon spawns in End biomes into spawn_pool_world/the_end.json, on top of its island home: Beheeyem, Reuniclus, Metagross; Gothitelle and Sigilyph in End cities; Malamar and Unown with a Poke Snack. Cobblemon rolls the bucket before the Pokemon and has these all uncommon or rare, so they move to the common bucket with even line weights (Metagross a fifth). Self-test end_has_spawns: the main island is in the_end and offers only End spawns, some in the common bucket. Self-tests and the island check pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e7b16abae
commit
4f0bc03919
11 files changed
+810
-9
No files matched your search
@@ -19,6 +19,8 @@ import net.minecraft.core.BlockPos
|
||||
import net.minecraft.gametest.framework.GameTestAssertException
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.level.ChunkPos
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.levelgen.Heightmap
|
||||
import kotlin.math.roundToInt
|
||||
@@ -36,6 +38,7 @@ object ZoneTests {
|
||||
SelfTestCase("spawn_pools_are_zoned", 20, ::spawnPoolsAreZoned),
|
||||
SelfTestCase("spawn_survey", 2400, ::spawnSurvey, islandOnly = true),
|
||||
SelfTestCase("level_pressure_cuts_xp", 100, ::levelPressure),
|
||||
SelfTestCase("end_has_spawns", 200, ::endSpawns),
|
||||
)
|
||||
|
||||
private fun zoneOf(detail: SpawnDetail): Zone? = Zones.byId[detail.id.substringBefore('-')]
|
||||
@@ -108,6 +111,44 @@ object ZoneTests {
|
||||
}.thenSucceed()
|
||||
}
|
||||
|
||||
/**
|
||||
* The End is a zone of its own (Adrian, 2026-11-02: it was barren). On the main island Cobblemon offers End
|
||||
* spawns only, and some in the common bucket, which it rolls most of the time.
|
||||
*/
|
||||
private fun endSpawns(s: Scenario) {
|
||||
val end = s.level.server.getLevel(Level.END) ?: throw GameTestAssertException("no End")
|
||||
val chunks = (0..2).flatMap { x -> (0..2).map { z -> ChunkPos(x, z) } }
|
||||
chunks.forEach { end.setChunkForced(it.x, it.z, true) }
|
||||
s.afterTest { chunks.forEach { end.setChunkForced(it.x, it.z, false) } }
|
||||
s.helper.startSequence()
|
||||
.thenWaitUntil { s.check(chunks.all { end.areEntitiesLoaded(it.toLong()) }) { "the End's main island isn't loaded yet" } }
|
||||
.thenExecute {
|
||||
val stand = ground(end, 20, 20)
|
||||
s.check(Zones.at(end, stand)?.id == "the_end") { "the End's main island is in zone ${Zones.at(end, stand)?.id}, not the_end" }
|
||||
val (offered, common) = offeredAt(s.player(), end, stand)
|
||||
val strangers = offered.filter { zoneOf(it)?.id != "the_end" }
|
||||
s.check(strangers.isEmpty()) { "the End offers other zones' spawns: ${strangers.take(5).map { it.id }}" }
|
||||
s.check(common.isNotEmpty()) { "nothing in the common bucket can spawn on the End's main island (${offered.map { it.id }})" }
|
||||
}
|
||||
.thenSucceed()
|
||||
}
|
||||
|
||||
/** What Cobblemon could spawn around [pos] in [level] right now (the way `/checkspawn` does): all, and the common bucket's. */
|
||||
private fun offeredAt(player: ServerPlayer, level: net.minecraft.server.level.ServerLevel, pos: BlockPos): Pair<Set<SpawnDetail>, Set<SpawnDetail>> {
|
||||
val spawner = player.spawner
|
||||
val diameter = Cobblemon.config.spawningZoneDiameter
|
||||
val height = Cobblemon.config.spawningZoneHeight
|
||||
val input = SpawningZoneInput(
|
||||
SpawnCause(spawner, player), level,
|
||||
pos.x - diameter / 2, pos.y - height / 2, pos.z - diameter / 2, diameter, height, diameter,
|
||||
)
|
||||
val positions = Cobblemon.areaSpawnablePositionResolver.resolve(
|
||||
spawner, SpawnablePositionCalculator.prioritizedAreaCalculators, Cobblemon.spawningZoneGenerator.generate(spawner, input),
|
||||
)
|
||||
fun inBucket(bucket: String) = spawner.selector.getProbabilities(spawner, bucket, positions).filterValues { it > 0f }.keys
|
||||
return CobblemonSpawnPools.WORLD_SPAWN_POOL.buckets.flatMap(::inBucket).toSet() to inBucket("common")
|
||||
}
|
||||
|
||||
/**
|
||||
* The ground at [x] [z], below any tree: standing on a mangrove's roots or logs, the survey once found no natural
|
||||
* ground around it, so nothing could spawn (2026-11-02).
|
||||
|
||||
Reference in new issue
Block a user