mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-20 14:16:26 -04:00
Cleanup
This commit is contained in:
@@ -197,6 +197,7 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPa
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokeradar.PokeRadarScanPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokeradar.PokeRadarTeleportPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdatePassengerPositionPacket
|
||||
@@ -256,6 +257,7 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenH
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokeradar.PokeRadarScanHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokeradar.PokeRadarTeleportHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdatePassengerPositionHandler
|
||||
@@ -656,8 +658,9 @@ object CobblemonNetwork {
|
||||
|
||||
// Poke Radar
|
||||
list.add(PacketRegisterInfo(PokeRadarScanPacket.ID, PokeRadarScanPacket::decode, PokeRadarScanHandler))
|
||||
|
||||
// Debug / cheats
|
||||
list.add(PacketRegisterInfo(PokeRadarTeleportPacket.ID, PokeRadarTeleportPacket::decode, PokeRadarTeleportHandler))
|
||||
|
||||
// Debug / cheats
|
||||
list.add(PacketRegisterInfo(RequestOpenRidingStatsDebugGUIPacket.ID, RequestOpenRidingStatsDebugGUIPacket::decode, RequestOpenRidingStatsDebugGUIHandler))
|
||||
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@ package com.cobblemon.mod.common.client.gui.pokeradar
|
||||
|
||||
import com.cobblemon.mod.common.client.pokeradar.PokeRadarScanResults
|
||||
import com.cobblemon.mod.common.client.pokeradar.PokeRadarType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.server.pokeradar.PokeRadarScanPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokeradar.PokeRadarTeleportPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.util.Mth
|
||||
|
||||
@@ -17,6 +20,7 @@ class RadarGUI(
|
||||
private val rowsPerPage = 10
|
||||
private val rowHeight = 18
|
||||
private val listWidth = 300
|
||||
private val tpButtonWidth = 28
|
||||
private var page = initialPage
|
||||
|
||||
override fun init() {
|
||||
@@ -43,11 +47,42 @@ class RadarGUI(
|
||||
.bounds(width / 2 + 20, height - 28, 40, 20)
|
||||
.build()
|
||||
)
|
||||
|
||||
val entries = PokeRadarScanResults.entries
|
||||
if (entries.isEmpty()) return
|
||||
|
||||
val totalPages = maxOf(1, (entries.size + rowsPerPage - 1) / rowsPerPage)
|
||||
page = Mth.clamp(page, 0, totalPages - 1)
|
||||
|
||||
val listLeft = width / 2 - listWidth / 2
|
||||
val listTop = 30
|
||||
val start = page * rowsPerPage
|
||||
val end = Mth.clamp(start + rowsPerPage, 0, entries.size)
|
||||
|
||||
for (i in start until end) {
|
||||
val entry = entries[i]
|
||||
val level = Minecraft.getInstance().level ?: return
|
||||
val entity = entry.entityId?.let { level.getEntity(it) } as? PokemonEntity
|
||||
|
||||
val currentPos: BlockPos? = entity?.blockPosition()
|
||||
val rowY = listTop + (i - start) * rowHeight
|
||||
addRenderableWidget(
|
||||
Button.builder(Component.literal("TP")) {
|
||||
PokeRadarTeleportPacket(
|
||||
currentPos ?: Minecraft.getInstance().player?.blockPosition()
|
||||
).sendToServer()
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
}
|
||||
.bounds(listLeft + listWidth - tpButtonWidth - 2, rowY, tpButtonWidth, rowHeight - 2)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun changePage(delta: Int) {
|
||||
val totalPages = maxOf(1, (PokeRadarScanResults.entries.size + rowsPerPage - 1) / rowsPerPage)
|
||||
page = Mth.clamp(page + delta, 0, totalPages - 1)
|
||||
rebuild()
|
||||
}
|
||||
|
||||
override fun render(g: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||
@@ -57,7 +92,7 @@ class RadarGUI(
|
||||
val listLeft = width / 2 - listWidth / 2
|
||||
val listTop = 30
|
||||
|
||||
g.drawCenteredString(font, "PokeRadar Scan (${entries.size} results)", width / 2, 12, 0xFFFFFF)
|
||||
g.drawCenteredString(font, "PokeRadar Scan (${entries.size})", width / 2, 12, 0xFFFFFF)
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
g.drawCenteredString(font, "No results", width / 2, height / 2, 0xAAAAAA)
|
||||
@@ -65,25 +100,27 @@ class RadarGUI(
|
||||
}
|
||||
|
||||
val totalPages = maxOf(1, (entries.size + rowsPerPage - 1) / rowsPerPage)
|
||||
page = Mth.clamp(page, 0, totalPages - 1)
|
||||
|
||||
val start = page * rowsPerPage
|
||||
val end = Mth.clamp(start + rowsPerPage, 0, entries.size)
|
||||
val textRight = listLeft + listWidth - tpButtonWidth - 6
|
||||
|
||||
for (i in start until end) {
|
||||
val entry = entries[i]
|
||||
val level = Minecraft.getInstance().level ?: return
|
||||
val entity = entry.entityId?.let { level.getEntity(it) } as? PokemonEntity
|
||||
|
||||
val pos: BlockPos? = entity?.blockPosition()
|
||||
val rowY = listTop + (i - start) * rowHeight
|
||||
val hovered = mouseX in listLeft..(listLeft + listWidth) && mouseY in rowY..(rowY + rowHeight - 2)
|
||||
val hovered = mouseX in listLeft..textRight && mouseY in rowY..(rowY + rowHeight - 2)
|
||||
|
||||
g.fill(
|
||||
listLeft, rowY, listLeft + listWidth, rowY + rowHeight - 2,
|
||||
if (hovered) 0x80FFFFFF.toInt() else 0x40000000
|
||||
)
|
||||
|
||||
val name = entry.pokemon?.species ?: entry.detail.displayName ?: entry.detail.id
|
||||
val levelText = entry.levelRange?.let { "L${it.first}-${it.last}" } ?: "L?"
|
||||
val text = "$name $levelText ${"%.2f".format(entry.globalShare)}% " +
|
||||
"${"%.1f".format(entry.distanceFromOrigin)}m [${entry.detail.bucket}]"
|
||||
val name = entry.pokemon?.species ?: "?"
|
||||
val levelText = entry.pokemon?.level?.let { "$it" } ?: "?"
|
||||
val text = "$name $levelText (${pos?.x}, ${pos?.y}, ${pos?.z})"
|
||||
|
||||
g.drawString(font, text, listLeft + 4, rowY + 4, 0xFFFFFF)
|
||||
}
|
||||
@@ -96,28 +133,4 @@ class RadarGUI(
|
||||
0xFFFFFF
|
||||
)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (super.mouseClicked(mouseX, mouseY, button)) return true
|
||||
if (button != 0) return false
|
||||
|
||||
val entries = PokeRadarScanResults.entries
|
||||
if (entries.isEmpty()) return false
|
||||
|
||||
val listLeft = width / 2 - listWidth / 2
|
||||
val listTop = 30
|
||||
val start = page * rowsPerPage
|
||||
val end = Mth.clamp(start + rowsPerPage, 0, entries.size)
|
||||
|
||||
for (i in start until end) {
|
||||
val rowY = listTop + (i - start) * rowHeight
|
||||
if (mouseX in listLeft.toDouble()..(listLeft + listWidth).toDouble() &&
|
||||
mouseY in rowY.toDouble()..(rowY + rowHeight - 2).toDouble()
|
||||
) {
|
||||
Minecraft.getInstance().setScreen(RadarPokemonDetailGUI(type, entries[i], page))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
package com.cobblemon.mod.common.client.gui.pokeradar
|
||||
|
||||
import com.cobblemon.mod.common.client.pokeradar.PokeRadarType
|
||||
import com.cobblemon.mod.common.pokeradar.SpawnCheckEntryData
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
class RadarPokemonDetailGUI(
|
||||
override val type: PokeRadarType,
|
||||
private val entry: SpawnCheckEntryData,
|
||||
private val returnPage: Int
|
||||
) : PokeRadarGUI(type) {
|
||||
|
||||
override fun init() {
|
||||
addRenderableWidget(
|
||||
Button.builder(Component.literal("< Back")) {
|
||||
Minecraft.getInstance().setScreen(RadarGUI(type, returnPage))
|
||||
}.bounds(10, 10, 60, 20).build()
|
||||
)
|
||||
super.init()
|
||||
}
|
||||
|
||||
override fun render(g: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
|
||||
super.render(g, mouseX, mouseY, partialTick)
|
||||
|
||||
val name = entry.pokemon?.species ?: entry.detail.displayName ?: entry.detail.id
|
||||
g.drawCenteredString(font, name, width / 2, 15, 0xFFFFFF)
|
||||
|
||||
val lines = buildList {
|
||||
add("ID: ${entry.detail.id}")
|
||||
add("Type: ${entry.detail.type}")
|
||||
add("Bucket: ${entry.detail.bucket}")
|
||||
add("Level Range: ${entry.levelRange?.let { "${it.first}-${it.last}" } ?: "?"}")
|
||||
add("")
|
||||
add("Block Pos: ${entry.spawnable.position}")
|
||||
add(
|
||||
"World Pos: ${"%.1f".format(entry.worldPosition.x)}, ${"%.1f".format(entry.worldPosition.y)}, ${
|
||||
"%.1f".format(
|
||||
entry.worldPosition.z
|
||||
)
|
||||
}"
|
||||
)
|
||||
add("Distance: ${"%.2f".format(entry.distanceFromOrigin)}m")
|
||||
add("")
|
||||
add("Block Light: ${entry.spawnable.light}")
|
||||
add("Sky Light: ${entry.spawnable.skyLight}")
|
||||
add("Can See Sky: ${entry.spawnable.canSeeSky}")
|
||||
add("")
|
||||
add("Weight: ${"%.3f".format(entry.weight)}")
|
||||
add("Weight Share @ Pos: ${"%.2f".format(entry.weightShareAtPosition)}%")
|
||||
add("Global Share: ${"%.2f".format(entry.globalShare)}%")
|
||||
if (entry.detail.validBiomes.isNotEmpty()) {
|
||||
add("")
|
||||
add("Valid Biomes (${entry.detail.validBiomes.size}):")
|
||||
entry.detail.validBiomes.take(6).forEach { add(" - $it") }
|
||||
if (entry.detail.validBiomes.size > 6) {
|
||||
add(" ... +${entry.detail.validBiomes.size - 6} more")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var y = 40
|
||||
for (line in lines) {
|
||||
g.drawString(font, line, 20, y, 0xFFFFFF)
|
||||
y += 11
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.cobblemon.mod.common.net.messages.server.pokeradar
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class PokeRadarTeleportPacket(val pos: BlockPos? = BlockPos.ZERO) : NetworkPacket<PokeRadarTeleportPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeBlockPos(pos ?: BlockPos.ZERO)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("poke_radar_teleport")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = PokeRadarTeleportPacket(buffer.readBlockPos())
|
||||
}
|
||||
}
|
||||
+1
-7
@@ -1,6 +1,5 @@
|
||||
package com.cobblemon.mod.common.net.serverhandling.pokeradar
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.pokeradar.PokeRadarScanResultPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokeradar.PokeRadarScanPacket
|
||||
@@ -13,12 +12,7 @@ object PokeRadarScanHandler : ServerNetworkPacketHandler<PokeRadarScanPacket> {
|
||||
override fun handle(packet: PokeRadarScanPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
val radius = 16
|
||||
|
||||
val entries: List<SpawnCheckEntry> = SpawnExtensions.scanSpawnsInRadius(
|
||||
player = player,
|
||||
bucket = Cobblemon.bestSpawner.config.worldBuckets,
|
||||
radius = radius,
|
||||
cube = false
|
||||
)
|
||||
val entries = SpawnExtensions.scanPokemonInRadius(player = player, radius = radius, cube = false)
|
||||
|
||||
PokeRadarScanResultPacket(SpawnCheckEntry.toData(entries)).sendToPlayer(player)
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.cobblemon.mod.common.net.serverhandling.pokeradar
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.server.pokeradar.PokeRadarTeleportPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
// TODO: Add Operator Check
|
||||
object PokeRadarTeleportHandler : ServerNetworkPacketHandler<PokeRadarTeleportPacket> {
|
||||
override fun handle(packet: PokeRadarTeleportPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
player.teleportTo(
|
||||
packet.pos?.x?.plus(0.5) ?: 0.0,
|
||||
packet.pos?.y?.toDouble() ?: 0.0,
|
||||
packet.pos?.z?.plus(0.5) ?: 0.0
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -2,158 +2,31 @@ package com.cobblemon.mod.common.pokeradar
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
// TODO: Temporary until the Data that the client needs is finalized
|
||||
|
||||
data class SpawnablePositionData(
|
||||
val position: BlockPos,
|
||||
val light: Int,
|
||||
val skyLight: Int,
|
||||
val canSeeSky: Boolean
|
||||
) {
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeBlockPos(position)
|
||||
buffer.writeInt(light)
|
||||
buffer.writeInt(skyLight)
|
||||
buffer.writeBoolean(canSeeSky)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = SpawnablePositionData(
|
||||
position = buffer.readBlockPos(),
|
||||
light = buffer.readInt(),
|
||||
skyLight = buffer.readInt(),
|
||||
canSeeSky = buffer.readBoolean()
|
||||
)
|
||||
|
||||
fun of(spawnable: SpawnablePosition) = SpawnablePositionData(
|
||||
position = spawnable.position,
|
||||
light = spawnable.light,
|
||||
skyLight = spawnable.skyLight,
|
||||
canSeeSky = spawnable.canSeeSky
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class SpawnDetailData(
|
||||
val type: String,
|
||||
val id: String,
|
||||
val displayName: String?,
|
||||
val bucket: String,
|
||||
val validBiomes: Set<ResourceLocation>
|
||||
) {
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUtf(type)
|
||||
buffer.writeUtf(id)
|
||||
buffer.writeNullable(displayName) { buf, s -> buf.writeUtf(s) }
|
||||
buffer.writeUtf(bucket)
|
||||
buffer.writeVarInt(validBiomes.size)
|
||||
validBiomes.forEach { buffer.writeResourceLocation(it) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): SpawnDetailData {
|
||||
val type = buffer.readUtf()
|
||||
val id = buffer.readUtf()
|
||||
val displayName = buffer.readNullable { it.readUtf() }
|
||||
val bucket = buffer.readUtf()
|
||||
val size = buffer.readVarInt()
|
||||
val validBiomes = mutableSetOf<ResourceLocation>()
|
||||
repeat(size) { validBiomes.add(buffer.readResourceLocation()) }
|
||||
return SpawnDetailData(type, id, displayName, bucket, validBiomes)
|
||||
}
|
||||
|
||||
fun of(detail: SpawnDetail) = SpawnDetailData(
|
||||
type = detail.type,
|
||||
id = detail.id,
|
||||
displayName = detail.displayName,
|
||||
bucket = detail.bucket,
|
||||
validBiomes = detail.validBiomes
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class SpawnCheckEntryData(
|
||||
val spawnable: SpawnablePositionData,
|
||||
val detail: SpawnDetailData,
|
||||
val pokemon: PokemonProperties?,
|
||||
val levelRange: IntRange?,
|
||||
val worldPosition: Vec3,
|
||||
val bucket: Map<String, Float>,
|
||||
val weight: Float,
|
||||
val weightShareAtPosition: Float,
|
||||
val globalShare: Float,
|
||||
val distanceFromOrigin: Double
|
||||
val entityId: Int? = null
|
||||
) : Encodable {
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
spawnable.encode(buffer)
|
||||
detail.encode(buffer)
|
||||
buffer.writeNullable(pokemon) { buf, p -> buf.writeUtf(p.asString()) }
|
||||
buffer.writeNullable(levelRange) { buf, r ->
|
||||
buf.writeInt(r.first)
|
||||
buf.writeInt(r.last)
|
||||
}
|
||||
buffer.writeDouble(worldPosition.x)
|
||||
buffer.writeDouble(worldPosition.y)
|
||||
buffer.writeDouble(worldPosition.z)
|
||||
buffer.writeVarInt(bucket.size)
|
||||
bucket.forEach { (k, v) ->
|
||||
buffer.writeUtf(k)
|
||||
buffer.writeFloat(v)
|
||||
}
|
||||
buffer.writeFloat(weight)
|
||||
buffer.writeFloat(weightShareAtPosition)
|
||||
buffer.writeFloat(globalShare)
|
||||
buffer.writeDouble(distanceFromOrigin)
|
||||
buffer.writeNullable(entityId) { buf, id -> buf.writeVarInt(id) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): SpawnCheckEntryData {
|
||||
val spawnable = SpawnablePositionData.decode(buffer)
|
||||
val detail = SpawnDetailData.decode(buffer)
|
||||
val pokemon = buffer.readNullable { PokemonProperties.parse(it.readUtf()) }
|
||||
val levelRange = buffer.readNullable { IntRange(it.readInt(), it.readInt()) }
|
||||
val worldPosition = Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble())
|
||||
val bucketSize = buffer.readVarInt()
|
||||
val bucket = LinkedHashMap<String, Float>(bucketSize)
|
||||
repeat(bucketSize) { bucket[buffer.readUtf()] = buffer.readFloat() }
|
||||
val weight = buffer.readFloat()
|
||||
val weightShareAtPosition = buffer.readFloat()
|
||||
val globalShare = buffer.readFloat()
|
||||
val distanceFromOrigin = buffer.readDouble()
|
||||
return SpawnCheckEntryData(
|
||||
spawnable = spawnable,
|
||||
detail = detail,
|
||||
pokemon = pokemon,
|
||||
levelRange = levelRange,
|
||||
worldPosition = worldPosition,
|
||||
bucket = bucket,
|
||||
weight = weight,
|
||||
weightShareAtPosition = weightShareAtPosition,
|
||||
globalShare = globalShare,
|
||||
distanceFromOrigin = distanceFromOrigin
|
||||
)
|
||||
val entityId = buffer.readNullable { it.readVarInt() }
|
||||
return SpawnCheckEntryData(pokemon, entityId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class SpawnCheckEntry(
|
||||
val position: SpawnablePosition,
|
||||
val detail: SpawnDetail,
|
||||
val pokemon: PokemonProperties?,
|
||||
val levelRange: IntRange?,
|
||||
val worldPosition: Vec3,
|
||||
val bucket: MutableMap<String, Float>,
|
||||
val weight: Float,
|
||||
val weightShareAtPosition: Float,
|
||||
val globalShare: Float,
|
||||
val distanceFromOrigin: Double,
|
||||
val entityId: Int? = null
|
||||
) {
|
||||
companion object {
|
||||
fun toData(entries: List<SpawnCheckEntry>): List<SpawnCheckEntryData> =
|
||||
@@ -161,15 +34,7 @@ data class SpawnCheckEntry(
|
||||
}
|
||||
|
||||
fun toData() = SpawnCheckEntryData(
|
||||
spawnable = SpawnablePositionData.of(position),
|
||||
detail = SpawnDetailData.of(detail),
|
||||
pokemon = pokemon,
|
||||
levelRange = levelRange,
|
||||
worldPosition = worldPosition,
|
||||
bucket = bucket,
|
||||
weight = weight,
|
||||
weightShareAtPosition = weightShareAtPosition,
|
||||
globalShare = globalShare,
|
||||
distanceFromOrigin = distanceFromOrigin
|
||||
entityId = entityId
|
||||
)
|
||||
}
|
||||
@@ -1,137 +1,36 @@
|
||||
package com.cobblemon.mod.common.pokeradar
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.config
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.position.calculators.SpawnablePositionCalculator.Companion.prioritizedAreaCalculators
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.SpawningZoneInput
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck
|
||||
import com.cobblemon.mod.common.util.spawner
|
||||
import net.minecraft.network.chat.Component
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.max
|
||||
|
||||
object SpawnExtensions {
|
||||
fun scanSpawnsInRadius(
|
||||
|
||||
private const val BLOCKS_PER_CHUNK = 16
|
||||
|
||||
fun scanPokemonInRadius(
|
||||
player: ServerPlayer,
|
||||
bucket: MutableMap<String, Float>,
|
||||
radius: Int,
|
||||
cube: Boolean = false,
|
||||
maxDistance: Double = radius.toDouble()
|
||||
maxDistance: Double = (radius * BLOCKS_PER_CHUNK).toDouble()
|
||||
): List<SpawnCheckEntry> {
|
||||
if (!config.enableSpawning) return emptyList()
|
||||
val levelKey = (player.serverLevel() as ServerLevelDuck).`cobblemon$getLevelResourceLocation`()
|
||||
if (levelKey in config.worldSpawningBlocklist) return emptyList()
|
||||
|
||||
val spawner: Spawner = player.spawner
|
||||
val world: ServerLevel = player.serverLevel()
|
||||
val cause = SpawnCause(spawner, player)
|
||||
|
||||
val diameter = radius * 2 + 1
|
||||
val height = if (cube) diameter else config.spawningZoneHeight
|
||||
|
||||
val slice = Cobblemon.spawningZoneGenerator.generate(
|
||||
spawner = spawner,
|
||||
input = SpawningZoneInput(
|
||||
cause = cause,
|
||||
world = world,
|
||||
baseX = Mth.ceil(player.x - diameter / 2.0),
|
||||
baseY = Mth.ceil(player.y - height / 2.0),
|
||||
baseZ = Mth.ceil(player.z - diameter / 2.0),
|
||||
length = diameter,
|
||||
height = height,
|
||||
width = diameter
|
||||
)
|
||||
)
|
||||
|
||||
val positions: List<AreaSpawnablePosition> = Cobblemon.areaSpawnablePositionResolver
|
||||
.resolve(spawner, prioritizedAreaCalculators, slice)
|
||||
|
||||
val radiusInBlocks = (radius * BLOCKS_PER_CHUNK).toDouble()
|
||||
val verticalRadius = if (cube) radiusInBlocks else config.spawningZoneHeight / 2.0
|
||||
val box = player.boundingBox.inflate(radiusInBlocks, verticalRadius, radiusInBlocks)
|
||||
val origin = player.position()
|
||||
val entries = ArrayList<SpawnCheckEntry>(positions.size)
|
||||
val globalWeightByDetail = HashMap<SpawnDetail, Float>()
|
||||
|
||||
for (pos in positions) {
|
||||
val wp = Vec3(pos.position.x + 0.5, pos.position.y.toDouble(), pos.position.z + 0.5)
|
||||
if (maxDistance > 0 && wp.distanceTo(origin) > maxDistance) continue
|
||||
|
||||
val matching = LinkedHashMap<SpawnDetail, Float>()
|
||||
for (bucketName in bucket.keys) {
|
||||
for (detail in spawner.getMatchingSpawns(bucketName, pos)) {
|
||||
if (!pos.preFilter(detail) || !pos.postFilter(detail)) continue
|
||||
val w = max(0F, pos.getWeight(detail))
|
||||
if (w <= 0F) continue
|
||||
matching.merge(detail, w, Float::plus)
|
||||
}
|
||||
}
|
||||
|
||||
if (matching.isEmpty()) continue
|
||||
|
||||
val positionTotal = matching.values.sum().takeIf { it > 0F } ?: 1F
|
||||
|
||||
for ((detail, weight) in matching) {
|
||||
globalWeightByDetail.merge(detail, weight, Float::plus)
|
||||
|
||||
entries.add(
|
||||
SpawnCheckEntry(
|
||||
position = pos,
|
||||
detail = detail,
|
||||
pokemon = (detail as? PokemonSpawnDetail)?.pokemon,
|
||||
levelRange = (detail as? PokemonSpawnDetail)?.levelRange,
|
||||
worldPosition = wp,
|
||||
bucket = bucket,
|
||||
weight = weight,
|
||||
weightShareAtPosition = weight / positionTotal * 100F,
|
||||
globalShare = 0F,
|
||||
distanceFromOrigin = origin.distanceTo(wp),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val globalTotal = globalWeightByDetail.values.sum().takeIf { it > 0F } ?: 1F
|
||||
return entries.map { entry ->
|
||||
val g = (globalWeightByDetail[entry.detail] ?: 0F) / globalTotal * 100F
|
||||
entry.copy(globalShare = g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Debug
|
||||
fun ServerPlayer.sendSpawnScan(entries: List<SpawnCheckEntry>, bucket: MutableMap<String, Float>) {
|
||||
if (entries.isEmpty()) {
|
||||
sendSystemMessage(Component.literal("No spawns for $bucket."))
|
||||
return
|
||||
}
|
||||
|
||||
val grouped = entries
|
||||
.groupBy { it.pokemon?.species ?: it.detail.displayName ?: "?" }
|
||||
|
||||
sendSystemMessage(
|
||||
Component.literal(
|
||||
"${entries.size} entries across ${grouped.size} species in bucket $bucket:"
|
||||
)
|
||||
)
|
||||
|
||||
grouped.entries
|
||||
.sortedByDescending { (_, list) -> list.maxOf { it.globalShare } }
|
||||
.forEach { (name, list) ->
|
||||
val nearest = list.minBy { it.distanceFromOrigin }
|
||||
sendSystemMessage(
|
||||
Component.literal(
|
||||
" $name — ${"%.2f".format(nearest.globalShare)}% " +
|
||||
"(${list.size} pos, nearest @ ${nearest.position.position} " +
|
||||
"${"%.1f".format(nearest.distanceFromOrigin)}m, " +
|
||||
"light=${nearest.position.light}/sky=${nearest.position.skyLight}, " +
|
||||
"biome=${nearest.position.biomeName})"
|
||||
)
|
||||
return world.getEntitiesOfClass(PokemonEntity::class.java, box) { entity ->
|
||||
entity.isAlive &&
|
||||
entity.pokemon.isWild() &&
|
||||
(maxDistance <= 0 || entity.position().distanceTo(origin) <= maxDistance)
|
||||
}.map { entity ->
|
||||
SpawnCheckEntry(
|
||||
pokemon = PokemonProperties.parse(entity.pokemon.species.resourceIdentifier.toString()),
|
||||
entityId = entity.id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user