Archived
1
0
Fork 0

Finish chunk data packet codec (for now)

This commit is contained in:
Moritz Ruth 2020-12-15 23:23:54 +01:00
parent b96afbfcea
commit e0a0003b07
No known key found for this signature in database
GPG key ID: AFD57E23E753841B
15 changed files with 138 additions and 16 deletions

View file

@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build TestPlugin.jar" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$/test-plugin" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="shadowJar" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
<method v="2" />
</configuration>
</component>

View file

@ -10,6 +10,7 @@
<option name="WORKING_DIRECTORY" value="" />
<method v="2">
<option name="Make" enabled="true" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Build TestPlugin.jar" run_configuration_type="GradleRunConfiguration" />
</method>
</configuration>
</component>

View file

@ -32,6 +32,8 @@ class BlockCodec<T : Block> internal constructor(
}
})
val lastStateID get() = firstStateID + states.size
class IllegalAttributeTargetType : Exception("The type of the target property is not allowed for attributes")
fun getStateID(block: T): Int {

View file

@ -14,6 +14,9 @@ interface Material<T : Block> {
val collisionShape: CollisionShape
companion object {
/**
* All materials, sorted by their numeric ID in ascending order.
*/
val all = GENERATED_BLOCKS
val byID = GENERATED_BLOCKS.map { it.id to it }.toMap()

View file

@ -32,8 +32,9 @@ class NBT internal constructor(private val map: MutableMap<String, Any>) {
map[name] = value
}
fun write(destination: DataOutputStream, name: String) {
NBTCompound.writeNamedTag(destination, name, this)
fun write(destination: DataOutputStream, name: String? = null) {
if (name == null) NBTCompound.writeValue(destination, this)
else NBTCompound.writeNamedTag(destination, name, this)
}
fun toSNBT(pretty: Boolean) = NBTCompound.toSNBT(this, pretty)

View file

@ -1,6 +1,8 @@
package space.blokk.net.packet.play
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufOutputStream
import io.netty.buffer.Unpooled
import space.blokk.nbt.NBT
import space.blokk.net.MinecraftProtocolDataTypes.writeVarInt
import space.blokk.net.packet.OutgoingPacketCodec
@ -9,19 +11,23 @@ import space.blokk.util.toCompactLongArray
import space.blokk.world.block.Air
import space.blokk.world.block.CaveAir
import space.blokk.world.block.Material
import space.blokk.world.block.material
import java.io.DataOutputStream
import kotlin.math.ceil
import kotlin.math.log
object ChunkDataPacketCodec : OutgoingPacketCodec<ChunkDataPacket>(0x22, ChunkDataPacket::class) {
private val nonAirHeightmapIgnoredBlocks = setOf(Air::class, CaveAir::class)
private val solidHeightmapIgnoredBlocks = Material.all.filter {
// TODO
true
}
private val airBlocks: Set<Material<*>> = setOf(Air, CaveAir)
private val nonSolidBlocks = Material.all.filter { it.collisionShape.isEmpty() }
private val numberOfBitsPerBlock = ceil(log(Material.all.last().codec.lastStateID.toDouble(), 2.0)).toInt()
override fun ChunkDataPacket.encode(dst: ByteBuf) {
dst.writeInt(key.x)
dst.writeInt(key.z)
dst.writeBoolean(true) // Full Chunk
// Bitmask
var includedSections = 0
data.sections.forEachIndexed { index, value ->
if (value != null) includedSections = includedSections and (1 shl index)
@ -29,10 +35,46 @@ object ChunkDataPacketCodec : OutgoingPacketCodec<ChunkDataPacket>(0x22, ChunkDa
dst.writeVarInt(includedSections)
val heightmap = data.solidBlocksHeightmap ?: generateHeightmap(data.sections, listOf())
// Heightmaps
val heightmaps = NBT()
heightmaps.set("MOTION_BLOCKING", heightmap.toCompactLongArray(9))
heightmaps.set("MOTION_BLOCKING", heightmap.toCompactLongArray(9))
heightmaps.set(
"MOTION_BLOCKING",
(data.solidBlocksHeightmap ?: generateHeightmap(
data.sections,
nonSolidBlocks
)).toCompactLongArray(9)
)
heightmaps.set(
"WORLD_SURFACE",
(data.nonAirBlocksHeightmap ?: generateHeightmap(
data.sections,
airBlocks
)).toCompactLongArray(9)
)
DataOutputStream(ByteBufOutputStream(dst)).use { heightmaps.write(it) }
// Biomes
data.biomes.forEach { dst.writeInt(it.numericID) }
// Blocks
val dataBuf = Unpooled.buffer() // TODO: Set an initial capacity
for (section in data.sections.filterNotNull()) {
val ids = section.map { it.material().codec.getStateID(it) }.toIntArray()
dataBuf.writeShort(ids.count { !(it == Air.codec.id || it == CaveAir.codec.id) })
dataBuf.writeByte(numberOfBitsPerBlock)
val array = ids.toCompactLongArray(numberOfBitsPerBlock)
dataBuf.writeVarInt(array.size)
array.forEach { dataBuf.writeLong(it) }
}
dst.writeVarInt(dataBuf.readableBytes())
dst.writeBytes(dataBuf)
dataBuf.release()
// Block entities
dst.writeVarInt(0)
}
}

View file

@ -5,6 +5,7 @@ import space.blokk.net.packet.Protocol
object PlayProtocol : Protocol(
"PLAY",
ClientSettingsPacketCodec,
ChunkDataPacketCodec,
DeclareRecipesPacketCodec,
DisconnectPacketCodec,
IncomingPluginMessagePacketCodec,

View file

@ -61,8 +61,10 @@ tasks {
@Suppress("UnstableApiUsage")
manifest {
this.attributes("Main-Class" to "space.blokk.BlokkServer")
this.attributes("Implementation-Version" to project.version)
this.attributes(
"Main-Class" to "space.blokk.BlokkServer",
"Implementation-Version" to project.version
)
}
}
}

View file

@ -12,3 +12,4 @@ include(":blokk-nbt")
include(":blokk-packet-codecs")
include(":blokk-packets")
include(":blokk-server")
include("test-plugin")

View file

@ -0,0 +1,22 @@
plugins {
kotlin("jvm")
id("com.github.johnrengelman.shadow") version "6.1.0"
}
group = "space.blokk.testplugin"
version = "0.0.1-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation(project(":blokk-api"))
}
tasks {
shadowJar {
archiveFileName.set("TestPlugin.jar")
destinationDirectory.set(file("../serverData/plugins"))
}
}

View file

@ -0,0 +1,25 @@
package space.blokk.testplugin
import space.blokk.Blokk
import space.blokk.event.EventHandler
import space.blokk.event.Listener
import space.blokk.net.event.SessionAfterLoginEvent
import space.blokk.plugin.Plugin
import space.blokk.world.*
import space.blokk.testplugin.anvil.AnvilWorld
import space.blokk.world.block.GrassBlock
class TestPlugin: Plugin("Test", "1.0.0") {
override fun onEnable() {
val world = AnvilWorld(WorldDimension.OVERWORLD, WorldType.FLAT)
world.getVoxel(VoxelLocation(0, 2, 0)).block = GrassBlock(Unit)
Blokk.sessions.registerListener(object : Listener {
@EventHandler
fun onSessionAfterLogin(event: SessionAfterLoginEvent) {
event.initialWorldAndLocation =
WorldAndLocationWithRotation(world, LocationWithRotation(0.0, 4.0, 0.0, 0f, 0f))
}
})
}
}

View file

@ -1,4 +1,4 @@
package space.blokk.world.anvil
package space.blokk.testplugin.anvil
import com.google.common.cache.LoadingCache
import space.blokk.player.Player

View file

@ -1,4 +1,4 @@
package space.blokk.world.anvil
package space.blokk.testplugin.anvil
import space.blokk.world.Chunk
import space.blokk.world.Voxel

View file

@ -1,4 +1,4 @@
package space.blokk.world.anvil
package space.blokk.testplugin.anvil
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader

View file

@ -0,0 +1 @@
space.blokk.testplugin.TestPlugin