diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index e2c3d3d9d..963a780a6 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -73,8 +73,9 @@
-
+
+
@@ -114,6 +115,11 @@
+
+
+
+
+
diff --git a/build.gradle.kts b/build.gradle.kts
index 56cd7eda1..62ba66cd0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -40,6 +40,7 @@ dependencies {
implementation("com.akuleshov7:ktoml-core:0.5.1")
implementation("com.akuleshov7:ktoml-file:0.5.1")
implementation("net.bytebuddy:byte-buddy-agent:1.14.12")
+ implementation("org.jctools:jctools-core:4.0.5")
api("io.github.dockyardmc:bytesocks-client-java:1.0-SNAPSHOT") {
exclude(module = "slf4j-api")
diff --git a/src/main/kotlin/io/github/dockyardmc/DockyardServer.kt b/src/main/kotlin/io/github/dockyardmc/DockyardServer.kt
index 78b2c23d8..5102d339d 100644
--- a/src/main/kotlin/io/github/dockyardmc/DockyardServer.kt
+++ b/src/main/kotlin/io/github/dockyardmc/DockyardServer.kt
@@ -97,7 +97,7 @@ class DockyardServer(configBuilder: Config.() -> Unit) {
if (ConfigManager.config.implementationConfig.applyBlockPlacementRules) DefaultBlockHandlers().register()
}
- NetworkCompression.compressionThreshold = ConfigManager.config.networkCompressionThreshold
+ NetworkCompression.COMPRESSION_THRESHOLD = ConfigManager.config.networkCompressionThreshold
WorldManager.loadDefaultWorld()
Events.dispatch(ServerFinishLoadEvent(this))
diff --git a/src/main/kotlin/io/github/dockyardmc/apis/Hologram.kt b/src/main/kotlin/io/github/dockyardmc/apis/Hologram.kt
index de53a7440..412a41985 100644
--- a/src/main/kotlin/io/github/dockyardmc/apis/Hologram.kt
+++ b/src/main/kotlin/io/github/dockyardmc/apis/Hologram.kt
@@ -63,8 +63,8 @@ class Hologram(spawnLocation: Location, builder: HologramBuilder) : Entity(spawn
}
fun addStaticLine(line: StaticContentLine) {
- val lineIndex = lines.size
lines.add(line)
+ if (viewers.isEmpty()) return
viewers.forEach(::updateFull)
}
@@ -73,8 +73,8 @@ class Hologram(spawnLocation: Location, builder: HologramBuilder) : Entity(spawn
}
fun addPlayerLine(line: PlayerContentLine) {
- val lineIndex = lines.size
lines.add(line)
+ if (viewers.isEmpty()) return
viewers.forEach(::updateFull)
}
diff --git a/src/main/kotlin/io/github/dockyardmc/apis/sidebar/Sidebar.kt b/src/main/kotlin/io/github/dockyardmc/apis/sidebar/Sidebar.kt
index f90a5cffc..e0b33e36e 100644
--- a/src/main/kotlin/io/github/dockyardmc/apis/sidebar/Sidebar.kt
+++ b/src/main/kotlin/io/github/dockyardmc/apis/sidebar/Sidebar.kt
@@ -80,12 +80,14 @@ class Sidebar(initialTitle: String, initialLines: Map) : Viewa
}
fun setGlobalLine(index: Int, value: String) {
+ if (viewers.isEmpty()) return
val before = indexToLineMap[index] as SidebarLine.Static?
indexToLineMap[index] = SidebarLine.Static(value)
if (before?.value != value) viewers.forEach { viewer -> sendLinePacket(viewer, index) }
}
fun setPlayerLine(index: Int, value: (Player) -> String) {
+ if (viewers.isEmpty()) return
indexToLineMap[index] = SidebarLine.Player(value)
viewers.forEach { viewer -> sendLinePacket(viewer, index) }
}
@@ -116,6 +118,7 @@ class Sidebar(initialTitle: String, initialLines: Map) : Viewa
init {
title.valueChanged { event ->
+ if (viewers.isEmpty()) return@valueChanged
val packet = ClientboundScoreboardObjectivePacket(objective, ScoreboardMode.EDIT_TEXT, event.newValue, ScoreboardType.INTEGER)
viewers.sendPacket(packet)
}
diff --git a/src/main/kotlin/io/github/dockyardmc/bindables/BindablePairMap.kt b/src/main/kotlin/io/github/dockyardmc/bindables/BindablePairMap.kt
deleted file mode 100644
index 21860ded4..000000000
--- a/src/main/kotlin/io/github/dockyardmc/bindables/BindablePairMap.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-package io.github.dockyardmc.bindables
-
-data class PairKey(val first: T, val second: T)
-
-class BindablePairMap(map: Map, V>) {
-
- constructor() : this(mutableMapOf())
-
- private var innerMap: MutableMap, V> = mutableMapOf()
- private var removeListener = mutableListOf>()
- private var changeListener = mutableListOf>()
- private var updateListener = mutableListOf>()
-
- init {
- map.forEach(innerMap::put)
- }
-
- // Custom operator for 2D-like key access
- operator fun set(first: T, second: T, value: V) {
- innerMap[PairKey(first, second)] = value
- changeListener.forEach { it.unit.invoke(BindablePairMapItemSetEvent(first, second, value)) }
- updateListener.forEach { it.unit.invoke() }
- }
-
- val values: Map, V>
- get() = innerMap.toMap()
-
- val size: Int
- get() = innerMap.size
-
- fun addIfNotPresent(key: PairKey, value: V) {
- if (!values.containsKey(key)) set(key.first, key.second, value)
- }
-
- fun removeIfPresent(key: PairKey) {
- if (values.contains(key)) remove(key)
- }
-
- fun remove(key: PairKey) {
- val item = innerMap[key] ?: return
- innerMap.remove(key)
- removeListener.forEach { it.unit.invoke(BindablePairMapItemRemovedEvent(key.first, key.second, item)) }
- updateListener.forEach { it.unit.invoke() }
- }
-
- operator fun contains(target: PairKey): Boolean = values.contains(target)
-
- class BindablePairMapItemSetEvent(val first: T, val second: T, val value: V)
- class BindablePairMapItemRemovedEvent(val first: T, val second: T, val value: V)
-
- fun itemRemoved(function: (event: BindablePairMapItemRemovedEvent) -> Unit) {
- removeListener.add(BindablePairMapItemRemoveListener(function))
- }
-
- fun itemSet(function: (event: BindablePairMapItemSetEvent) -> Unit) {
- changeListener.add(BindablePairMapItemChangeListener(function))
- }
-
- fun mapUpdated(function: () -> Unit) {
- updateListener.add(BindablePairMapUpdateListener(function))
- }
-
- fun setSilently(key: PairKey, value: V) {
- innerMap[key] = value
- }
-
- fun removeSilently(key: PairKey) {
- innerMap.remove(key)
- }
-
- fun triggerUpdate() {
- updateListener.forEach { it.unit.invoke() }
- }
-
- operator fun get(key: PairKey): V? = innerMap[key]
-
- fun clear(silent: Boolean = false) {
- val map = innerMap.toMutableMap()
- map.forEach {
- if (silent) {
- innerMap.remove(it.key)
- } else {
- remove(it.key)
- }
- }
- updateListener.forEach { it.unit.invoke() }
- }
-
- class BindablePairMapItemRemoveListener(val unit: (list: BindablePairMapItemRemovedEvent) -> Unit)
- class BindablePairMapItemChangeListener(val unit: (list: BindablePairMapItemSetEvent) -> Unit)
- class BindablePairMapUpdateListener(val unit: () -> Unit)
-}
diff --git a/src/main/kotlin/io/github/dockyardmc/data/DataComponentHasher.kt b/src/main/kotlin/io/github/dockyardmc/data/DataComponentHasher.kt
deleted file mode 100644
index 9a3213d49..000000000
--- a/src/main/kotlin/io/github/dockyardmc/data/DataComponentHasher.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.github.dockyardmc.data
-
-import io.github.dockyardmc.item.TranscoderCRC32C
-
-object DataComponentHasher {
- fun hash(component: DataComponent): Int {
- val format: TranscoderCRC32C.HashContainer<*> = if (component.isSingleField) {
- TranscoderCRC32C.HashContainerValue()
- } else {
- TranscoderCRC32C.HashContainerMap()
- }
-
-// (component.getHashCodec() as Codec).writeTranscoded(TranscoderCRC32C, format, component, "")
-
- return when (format) {
- is TranscoderCRC32C.HashContainerMap -> CRC32CHasher.ofMap(format.getValue())
- is TranscoderCRC32C.HashContainerValue -> format.getValue()
- else -> throw IllegalArgumentException("not supported")
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/data/DataComponentRegistry.kt b/src/main/kotlin/io/github/dockyardmc/data/DataComponentRegistry.kt
index 5e9558983..4c655e1f4 100644
--- a/src/main/kotlin/io/github/dockyardmc/data/DataComponentRegistry.kt
+++ b/src/main/kotlin/io/github/dockyardmc/data/DataComponentRegistry.kt
@@ -4,12 +4,11 @@ import io.github.dockyardmc.data.components.*
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
-import java.util.concurrent.atomic.AtomicInteger
import kotlin.reflect.KClass
object DataComponentRegistry {
- val protocolIdCounter = AtomicInteger()
+ var protocolIdCounter = 0
val dataComponentsById = Int2ObjectOpenHashMap>()
val dataComponentsByIdentifier = Object2ObjectOpenHashMap>()
@@ -113,13 +112,14 @@ object DataComponentRegistry {
val SHULKER_COLOR = register("minecraft:shulker/color", ShulkerColorComponent::class)
fun register(identifier: String, kclass: KClass): KClass {
- val protocolId = protocolIdCounter.getAndIncrement()
+ val protocolId = protocolIdCounter
dataComponentsById[protocolId] = kclass
dataComponentsByIdReversed[kclass] = protocolId
dataComponentsByIdentifier[identifier] = kclass
dataComponentsByIdentifierReversed[kclass] = identifier
+ protocolIdCounter++
return kclass
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/data/components/PotionContentsComponent.kt b/src/main/kotlin/io/github/dockyardmc/data/components/PotionContentsComponent.kt
index 91544098c..4884c5646 100644
--- a/src/main/kotlin/io/github/dockyardmc/data/components/PotionContentsComponent.kt
+++ b/src/main/kotlin/io/github/dockyardmc/data/components/PotionContentsComponent.kt
@@ -33,7 +33,7 @@ class PotionContentsComponent(
override fun write(buffer: ByteBuf) {
buffer.writeOptional(potion?.getProtocolId(), ByteBuf::writeVarInt)
buffer.writeOptional(customColor, CustomColor::writePackedInt)
- buffer.writeList(effects, ByteBuf::writeAppliedPotionEffect)
+ buffer.writeList(effects, AppliedPotionEffect::write)
buffer.writeOptional(customName, ByteBuf::writeString)
}
@@ -42,7 +42,7 @@ class PotionContentsComponent(
return PotionContentsComponent(
buffer.readOptional(ByteBuf::readVarInt)?.let { PotionTypeRegistry.getByProtocolId(it) },
buffer.readOptional(ByteBuf::readInt)?.let { CustomColor.fromRGBInt(it) },
- buffer.readAppliedPotionEffectsList(),
+ buffer.readList(AppliedPotionEffect::read),
buffer.readOptional(ByteBuf::readString)
)
}
diff --git a/src/main/kotlin/io/github/dockyardmc/events/Event.kt b/src/main/kotlin/io/github/dockyardmc/events/Event.kt
index b4e0fcda6..bb162b655 100644
--- a/src/main/kotlin/io/github/dockyardmc/events/Event.kt
+++ b/src/main/kotlin/io/github/dockyardmc/events/Event.kt
@@ -17,13 +17,27 @@ interface Event {
other: Set = setOf(),
val isGlobalEvent: Boolean = false
) {
- // what the fuck
- val players = players + entities.filterIsInstance()
- var entities = entities + players
- val locations = locations + this.entities.map { it.location }
- val worlds = worlds + this.locations.map { it.world }
+ // combining sets is expensive and is done in initialization of every event.
+ // In most cases, either none or only one is accessed. Let's make them lazy so they are
+ // computed only when needed
+ val players: Set by lazy {
+ players + entities.filterIsInstance()
+ }
- val other: Set = this.players + this.entities + this.worlds + this.locations + other
+ val entities: Set by lazy {
+ entities + players
+ }
+
+ val locations: Set by lazy {
+ locations + this.entities.map { entity -> entity.location }
+ }
+ val worlds: Set by lazy {
+ worlds + this.locations.map { location -> location.world }
+ }
+
+ val other: Set by lazy {
+ this.players + this.entities + this.worlds + this.locations + other
+ }
operator fun contains(element: Any) = other.contains(element)
diff --git a/src/main/kotlin/io/github/dockyardmc/events/system/EventSystem.kt b/src/main/kotlin/io/github/dockyardmc/events/system/EventSystem.kt
index d198c5750..3f53fac3e 100644
--- a/src/main/kotlin/io/github/dockyardmc/events/system/EventSystem.kt
+++ b/src/main/kotlin/io/github/dockyardmc/events/system/EventSystem.kt
@@ -3,12 +3,14 @@ package io.github.dockyardmc.events.system
import io.github.dockyardmc.events.*
import io.github.dockyardmc.events.EventListener
import io.github.dockyardmc.utils.Disposable
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import java.util.*
import kotlin.reflect.KClass
+@Suppress("UNCHECKED_CAST")
abstract class EventSystem : Disposable {
- val eventMap = mutableMapOf, HandlerList>()
+ val eventMap = Object2ObjectOpenHashMap, HandlerList>()
var filter = EventFilter.empty()
val children = ObjectOpenHashSet()
diff --git a/src/main/kotlin/io/github/dockyardmc/extentions/ExtendedByteBuf.kt b/src/main/kotlin/io/github/dockyardmc/extentions/ExtendedByteBuf.kt
index a29e7c65f..57b60655c 100644
--- a/src/main/kotlin/io/github/dockyardmc/extentions/ExtendedByteBuf.kt
+++ b/src/main/kotlin/io/github/dockyardmc/extentions/ExtendedByteBuf.kt
@@ -2,21 +2,12 @@ package io.github.dockyardmc.extentions
import cz.lukynka.prettylog.LogType
import cz.lukynka.prettylog.log
-import io.github.dockyardmc.item.ItemStack
import io.github.dockyardmc.maths.positiveCeilDiv
-import io.github.dockyardmc.maths.vectors.Vector3
-import io.github.dockyardmc.maths.vectors.Vector3d
-import io.github.dockyardmc.maths.vectors.Vector3f
-import io.github.dockyardmc.registry.AppliedPotionEffect
-import io.github.dockyardmc.registry.AppliedPotionEffectSettings
import io.github.dockyardmc.registry.Registry
import io.github.dockyardmc.registry.RegistryEntry
-import io.github.dockyardmc.registry.registries.*
import io.github.dockyardmc.scroll.Component
import io.github.dockyardmc.scroll.CustomColor
import io.github.dockyardmc.scroll.extensions.toComponent
-import io.github.dockyardmc.sounds.Sound
-import io.github.dockyardmc.sounds.SoundEvent
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufInputStream
import io.netty.buffer.Unpooled
@@ -27,20 +18,11 @@ import net.kyori.adventure.nbt.CompoundBinaryTag
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.nio.charset.StandardCharsets
-import java.time.Instant
import java.util.*
-import kotlin.experimental.inv
-private const val SEGMENT_BITS: Byte = 0x7F
-private const val CONTINUE_BIT = 0x80
-
-fun ByteBuf.writeOptionalOLD(item: Any?, unit: (ByteBuf) -> Unit) {
- val isPresent = item != null
- this.writeBoolean(isPresent)
- if (isPresent) {
- unit.invoke(this)
- }
-}
+private const val SEGMENT_BITS: Int = 0x7F
+private const val CONTINUE_BIT: Int = 0x80
+private const val MAXIMUM_VAR_INT_SIZE = 5
fun ByteBuf.readList(reader: (ByteBuf) -> T): List {
val list = mutableListOf()
@@ -64,18 +46,10 @@ fun ByteBuf.readTextComponent(): Component {
return this.readNBTCompound().toComponent()
}
-fun ByteBuf.writeItemStackList(list: Collection) {
- this.writeVarInt(list.size)
- list.forEach {
- it.write(this)
- }
-}
-
fun ByteBuf.writeColor(color: CustomColor) {
this.writeInt(color.getPackedInt())
}
-
fun ByteBuf.readUUID(): UUID {
val most = this.readLong()
val least = this.readLong()
@@ -176,16 +150,13 @@ fun ByteBuf.writeVarLong(long: Long): ByteBuf {
}
fun ByteBuf.readVarLong(): Long {
- var b: Byte
- var long = 0L
- var iteration = 0
- do {
- b = this.readByte()
- long = long or ((b.toInt() and 0x7F).toLong() shl iteration++ * 7)
- if (iteration <= 10) continue
- throw RuntimeException("VarLong too big")
- } while (hasContinuationBit(b))
- return long
+ var result = 0L
+ for (shift in 0 until 56 step 7) {
+ val b = this.readByte()
+ result = result or ((b.toLong() and 0x7F) shl shift)
+ if (b >= 0) return result
+ }
+ return result or ((this.readByte().toLong() and 0xFF) shl 56)
}
fun hasContinuationBit(byte: Byte): Boolean = byte.toInt() and 0x80 == 128
@@ -201,19 +172,27 @@ fun > ByteBuf.writeByteEnum(value: T) {
this.writeByte(value.ordinal)
}
-
fun ByteBuf.readVarInt(): Int {
- var value = 0
- var position = 0
- var currentByte: Byte
- while (this.isReadable) {
- currentByte = readByte()
- value = value or (currentByte.toInt() and SEGMENT_BITS.toInt() shl position)
- if (currentByte.toInt() and CONTINUE_BIT == 0) break
- position += 7
- if (position >= 32) throw java.lang.RuntimeException("VarInt is too big")
+ val readable = this.readableBytes()
+ if (readable == 0) throw DecoderException("Invalid VarInt")
+
+ // decode only one byte first as this is the most common size of varints
+ var current = this.readByte().toInt()
+ if ((current and CONTINUE_BIT) != 128) {
+ return current
}
- return value
+
+ // no point in while loop that has higher overhead instead of for loop with max size of the varint
+ val maxRead = MAXIMUM_VAR_INT_SIZE.coerceAtMost(readable)
+ var varInt = current and SEGMENT_BITS
+ for (i in 1..) {
@@ -222,20 +201,52 @@ fun ByteBuf.writeStringArray(list: Collection) {
}
+// dark magic but its 2.05 nanoseconds per write
+// https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
+// little bit modified to write bytes directly because kotlin fucks up the byte order
fun ByteBuf.writeVarInt(int: Int) {
- var value = int
- while (true) {
- if (value and SEGMENT_BITS.inv().toInt() == 0) {
- writeByte(value)
- return
+ when {
+ // 1-byte
+ int and (-1 shl 7) == 0 -> {
+ this.writeByte(int)
+ }
+
+ // 2-byte
+ int and (-1 shl 14) == 0 -> {
+ val w = (int and SEGMENT_BITS or CONTINUE_BIT) shl 8 or (int ushr 7)
+ this.writeShort(w)
+ }
+
+ // 3-byte
+ int and (-1 shl 21) == 0 -> {
+ this.writeByte(int and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte((int ushr 7) and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte(int ushr 14)
+ }
+
+ // 4-byte
+ int and (-1 shl 28) == 0 -> {
+ this.writeByte(int and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte((int ushr 7) and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte((int ushr 14) and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte(int ushr 21)
+ }
+
+ // 5-byte
+ else -> {
+ this.writeByte(int and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte((int ushr 7) and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte((int ushr 14) and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte((int ushr 21) and SEGMENT_BITS or CONTINUE_BIT)
+ this.writeByte(int ushr 28)
}
- writeByte(value and SEGMENT_BITS.toInt() or CONTINUE_BIT)
- value = value ushr 7
}
}
fun ByteBuf.readString() = readString(Short.MAX_VALUE.toInt())
+
fun ByteBuf.readUtfAndLength() = readUtfAndLength(Short.MAX_VALUE.toInt())
+
fun ByteBuf.readString(i: Int): String {
val maxSize = i * 3
val size = this.readVarInt()
@@ -247,6 +258,7 @@ fun ByteBuf.readString(i: Int): String {
return string
}
+@Suppress("UNCHECKED_CAST")
fun ByteBuf.readRegistryEntry(registry: Registry): T {
return registry.getByProtocolId(this.readVarInt()) as T
}
@@ -255,14 +267,6 @@ fun ByteBuf.writeRegistryEntry(entry: RegistryEntry) {
this.writeVarInt(entry.getProtocolId())
}
-fun ByteBuf.readStringList(): List {
- val list = mutableListOf()
- for (i in 0 until this.readVarInt()) {
- list.add(this.readString())
- }
- return list
-}
-
fun ByteBuf.readRemainingBytesAsByteArray(): ByteArray {
val bytes = ByteArray(this.readableBytes())
this.readBytes(bytes)
@@ -299,153 +303,8 @@ fun ByteBuf.toByteArraySafe(): ByteArray {
return bytes
}
-fun ByteBuf.readAppliedPotionEffect(): AppliedPotionEffect {
- val id = this.readVarInt()
- val settings = AppliedPotionEffectSettings.read(this)
-
- val effect = PotionEffectRegistry.getByProtocolId(id)
-
- return AppliedPotionEffect(effect, settings)
-}
-
-fun ByteBuf.writeAppliedPotionEffect(effect: AppliedPotionEffect) {
- this.writeVarInt(PotionEffectRegistry[effect.effect.identifier].getProtocolId())
- effect.settings.write(this)
-}
-
-fun ByteBuf.readAppliedPotionEffectsList(): List {
- val list = mutableListOf()
- for (i in 0 until this.readVarInt()) {
- list.add(this.readAppliedPotionEffect())
- }
- return list
-}
-
-
fun ByteArray.toByteBuf(): ByteBuf = Unpooled.copiedBuffer(this)
-inline fun ByteBuf.readOptionalOrDefault(default: T): T {
- val optional = this.readOptionalOrNull() ?: return default
- return optional
-}
-
-inline fun ByteBuf.readOptionalOrNull(): T? {
- val isPresent = this.readBoolean()
- if (!isPresent) return null
- return when (T::class) {
- Int::class -> this.readVarInt() as T
- String::class -> this.readString() as T
- Boolean::class -> this.readBoolean() as T
- Float::class -> this.readFloat() as T
- Double::class -> this.readDouble() as T
- Long::class -> this.readLong() as T
- UUID::class -> this.readUUID() as T
- ItemStack::class -> ItemStack.read(this) as T
- Byte::class -> this.readByte() as T
- Vector3::class -> Vector3.read(this) as T
- Vector3d::class -> Vector3d.read(this) as T
- Vector3f::class -> Vector3f.read(this) as T
- BinaryTag::class -> (this.readNBT() as CompoundBinaryTag) as T
- CompoundBinaryTag::class -> this.readNBTCompound() as T
- Sound::class -> Sound(SoundEvent.read(this).identifier) as T
- EntityType::class -> EntityTypeRegistry[this.readString()] as T
- PotionEffect::class -> PotionEffectRegistry.getByProtocolId(this.readVarInt()) as T
- CustomColor::class -> CustomColor.fromRGBInt(this.readInt()) as T
- else -> throw IllegalArgumentException("This primitive doesn't have serializer")
- }
-}
-
-
-fun ByteBuf.readItemList(): MutableList- {
- val size = this.readVarInt()
- val list = mutableListOf
- ()
- for (i in 0 until size) {
- list.add(ItemRegistry[this.readString()])
- }
- return list
-}
-
-fun ByteBuf.readPotionEffectHolder(): PotionEffect {
- val type = this.readVarInt()
- if (type == 0) {
- val identifier = this.readString()
- return PotionEffectRegistry[identifier]
- }
- return PotionEffectRegistry.getByProtocolId(type - 1)
-}
-
-fun ByteBuf.writeAppliedPotionEffectsList(list: Collection) {
- this.writeVarInt(list.size)
- list.forEach { this.writeAppliedPotionEffect(it) }
-}
-
-fun ByteBuf.readCustomColor(): CustomColor {
- return CustomColor.fromRGBInt(this.readInt())
-}
-
-fun ByteBuf.readCustomColorList(): List {
- val list = mutableListOf()
- for (i in 0 until this.readVarInt()) {
- list.add(this.readCustomColor())
- }
- return list
-}
-
-fun ByteBuf.writeCustomColorList(list: Collection) {
- this.writeVarInt(list.size)
- list.forEach {
- this.writeInt(it.getPackedInt())
- }
-}
-
-fun ByteBuf.readEntityTypes(): List {
- val present = this.readBoolean()
- if (!present) return emptyList()
-
- val type = this.readVarInt() - 1
- if (type == -1) {
- val identifier = this.readString()
- return listOf(EntityTypeRegistry[identifier])
- }
- val list = mutableListOf()
- for (i in 0 until type) {
- list.add(readEntityTypeHolder())
- }
- return list
-}
-
-fun ByteBuf.readEntityTypeHolder(): EntityType {
- val type = this.readVarInt()
- if (type == 0) {
- val identifier = this.readString()
- return EntityTypeRegistry[identifier]
- }
- return EntityTypeRegistry.getByProtocolId(type - 1)
-}
-
-fun ByteBuf.readRepairable(): List
- {
- val type = this.readVarInt() - 1
- if (type == -1) {
- val identifier = this.readString()
- return listOf() //TODO tag registry
- }
- val list = mutableListOf
- ()
- for (i in 0 until type) {
- list.add(readItemHolder())
- }
- return list
-}
-
-
-fun ByteBuf.readItemHolder(): Item {
- val type = this.readVarInt()
- if (type == 0) {
- val identifier = this.readString()
- return ItemRegistry[identifier]
- }
- return ItemRegistry.getByProtocolId(type - 1)
-}
-
fun ByteBuf.writeByte(byte: Byte) {
this.writeByte(byte.toInt())
}
diff --git a/src/main/kotlin/io/github/dockyardmc/implementations/commands/ClearCommand.kt b/src/main/kotlin/io/github/dockyardmc/implementations/commands/ClearCommand.kt
index cc0349461..61cc80388 100644
--- a/src/main/kotlin/io/github/dockyardmc/implementations/commands/ClearCommand.kt
+++ b/src/main/kotlin/io/github/dockyardmc/implementations/commands/ClearCommand.kt
@@ -9,7 +9,7 @@ class ClearCommand {
init {
Commands.add("/clear") {
withPermission("dockyard.commands.clear")
- withDescription("Clears your inventory")
+ withDescription("Clears inventory")
addOptionalArgument("player", PlayerArgument())
execute { ctx ->
val player = getArgumentOrNull("player") ?: ctx.getPlayerOrThrow()
diff --git a/src/main/kotlin/io/github/dockyardmc/implementations/commands/EffectCommand.kt b/src/main/kotlin/io/github/dockyardmc/implementations/commands/EffectCommand.kt
index acd4aa40d..98471f725 100644
--- a/src/main/kotlin/io/github/dockyardmc/implementations/commands/EffectCommand.kt
+++ b/src/main/kotlin/io/github/dockyardmc/implementations/commands/EffectCommand.kt
@@ -15,6 +15,7 @@ class EffectCommand {
init {
Commands.add("/effect") {
withPermission("dockyard.commands.effect")
+ withDescription("Manages effects on players")
addSubcommand("give") {
addArgument("player", PlayerArgument())
diff --git a/src/main/kotlin/io/github/dockyardmc/implementations/commands/GamemodeCommand.kt b/src/main/kotlin/io/github/dockyardmc/implementations/commands/GamemodeCommand.kt
index 19c89485d..98b065e4a 100644
--- a/src/main/kotlin/io/github/dockyardmc/implementations/commands/GamemodeCommand.kt
+++ b/src/main/kotlin/io/github/dockyardmc/implementations/commands/GamemodeCommand.kt
@@ -11,7 +11,7 @@ class GamemodeCommand {
init {
Commands.add("/gamemode") {
- withDescription("Changes your gamemode")
+ withDescription("Manages game mode of players")
withPermission("dockyard.commands.gamemode")
addArgument("game_mode", EnumArgument(GameMode::class))
addOptionalArgument("player", PlayerArgument())
diff --git a/src/main/kotlin/io/github/dockyardmc/implementations/commands/ListCommand.kt b/src/main/kotlin/io/github/dockyardmc/implementations/commands/ListCommand.kt
index 726334e7a..ae20c9f4e 100644
--- a/src/main/kotlin/io/github/dockyardmc/implementations/commands/ListCommand.kt
+++ b/src/main/kotlin/io/github/dockyardmc/implementations/commands/ListCommand.kt
@@ -7,6 +7,8 @@ class ListCommand {
init {
Commands.add("/list") {
+ withDescription("Lists all players online")
+
execute { ctx ->
val size = PlayerManager.players.size
if(size == 0) {
diff --git a/src/main/kotlin/io/github/dockyardmc/implementations/commands/SchedulerCommand.kt b/src/main/kotlin/io/github/dockyardmc/implementations/commands/SchedulerCommand.kt
index 00fe86ff9..3ee793ba2 100644
--- a/src/main/kotlin/io/github/dockyardmc/implementations/commands/SchedulerCommand.kt
+++ b/src/main/kotlin/io/github/dockyardmc/implementations/commands/SchedulerCommand.kt
@@ -12,7 +12,7 @@ class SchedulerCommand {
init {
Commands.add("/scheduler") {
withPermission("dockyard.commands.scheduler")
- withDescription("Lets you change tickrate/pause/resume scheduler of a world")
+ withDescription("Manages tickrate and state of world scheduler")
addSubcommand("tickrate") {
addArgument("world", WorldArgument())
diff --git a/src/main/kotlin/io/github/dockyardmc/implementations/commands/SoundCommand.kt b/src/main/kotlin/io/github/dockyardmc/implementations/commands/SoundCommand.kt
index 9a9b342f4..e679c9a83 100644
--- a/src/main/kotlin/io/github/dockyardmc/implementations/commands/SoundCommand.kt
+++ b/src/main/kotlin/io/github/dockyardmc/implementations/commands/SoundCommand.kt
@@ -11,7 +11,7 @@ class SoundCommand {
init {
Commands.add("/playsound") {
withPermission("dockyard.commands.playsound")
- withDescription("Plays a sound to player")
+ withDescription("Plays sounds to players")
addArgument("sound", SoundArgument())
addArgument("category", EnumArgument(SoundCategory::class))
diff --git a/src/main/kotlin/io/github/dockyardmc/motd/ServerStatus.kt b/src/main/kotlin/io/github/dockyardmc/motd/ServerStatus.kt
index 70e7d03bd..309883c65 100644
--- a/src/main/kotlin/io/github/dockyardmc/motd/ServerStatus.kt
+++ b/src/main/kotlin/io/github/dockyardmc/motd/ServerStatus.kt
@@ -9,7 +9,6 @@ import io.github.dockyardmc.scroll.Component
import io.github.dockyardmc.scroll.extensions.toComponent
import io.github.dockyardmc.utils.DockyardBranding
import kotlinx.serialization.Serializable
-import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File
import java.net.URL
@@ -35,8 +34,8 @@ object ServerStatusManager {
fun getCache(ip: String?): ServerStatus {
val endpoint = endpointCache[ip]
- if(ip == null || endpoint == null) {
- if(!::defaultCache.isInitialized) updateCache()
+ if (ip == null || endpoint == null) {
+ if (!::defaultCache.isInitialized) updateCache()
return defaultCache
}
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/NetworkCompression.kt b/src/main/kotlin/io/github/dockyardmc/protocol/NetworkCompression.kt
index 26d80e524..033bb33b4 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/NetworkCompression.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/NetworkCompression.kt
@@ -2,46 +2,54 @@ package io.github.dockyardmc.protocol
import cz.lukynka.prettylog.LogType
import cz.lukynka.prettylog.log
+import io.github.dockyardmc.utils.ObjectPool
import java.io.ByteArrayOutputStream
import java.util.zip.Deflater
import java.util.zip.Inflater
object NetworkCompression {
- var compressionThreshold: Int = -1
+ var COMPRESSION_THRESHOLD: Int = -1
+ private val INFLATER_POOL = ObjectPool(::Inflater)
+ private val DEFLATER_POOL = ObjectPool(::Deflater)
fun decompress(input: ByteArray): ByteArray {
- val inflater = Inflater()
+ val inflater = INFLATER_POOL.get()
inflater.setInput(input)
val outputStream = ByteArrayOutputStream()
val output = ByteArray(1024)
try {
- while(!inflater.finished()) {
+ while (!inflater.finished()) {
val decompressionSize = inflater.inflate(output)
outputStream.write(output, 0, decompressionSize)
}
} catch (ex: Exception) {
log("Data of the input is not valid compressed data", LogType.ERROR)
log(ex)
+ } finally {
+ inflater.reset()
+ INFLATER_POOL.add(inflater)
}
return outputStream.toByteArray()
}
fun compress(input: ByteArray): ByteArray {
- val deflater = Deflater()
+ val deflater = DEFLATER_POOL.get()
deflater.setInput(input)
deflater.finish()
val outputStream = ByteArrayOutputStream()
val output = ByteArray(1024)
- while(!deflater.finished()) {
+ while (!deflater.finished()) {
val compressedSize = deflater.deflate(output)
outputStream.write(output, 0, compressedSize)
}
+ deflater.reset()
+ DEFLATER_POOL.add(deflater)
return outputStream.toByteArray()
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/encoders/CompressionEncoder.kt b/src/main/kotlin/io/github/dockyardmc/protocol/encoders/CompressionEncoder.kt
index f05d89c30..a454ada0d 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/encoders/CompressionEncoder.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/encoders/CompressionEncoder.kt
@@ -15,7 +15,7 @@ class CompressionEncoder(val processor: PlayerNetworkManager) : MessageToByteEnc
override fun encode(connection: ChannelHandlerContext, buffer: ByteBuf, out: ByteBuf) {
try {
val dataLength = buffer.readableBytes()
- if (dataLength < NetworkCompression.compressionThreshold) {
+ if (dataLength < NetworkCompression.COMPRESSION_THRESHOLD) {
out.writeVarInt(0)
out.writeBytes(buffer)
} else {
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/packets/login/LoginHandler.kt b/src/main/kotlin/io/github/dockyardmc/protocol/packets/login/LoginHandler.kt
index baa13a107..c39579fcb 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/packets/login/LoginHandler.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/packets/login/LoginHandler.kt
@@ -128,9 +128,9 @@ class LoginHandler(var networkManager: PlayerNetworkManager) : PacketHandler(net
list.add(texturesPropertyMap)
player.profile = texturesPropertyMap
- player.sendPacket(ClientboundSetCompressionPacket(NetworkCompression.compressionThreshold))
+ player.sendPacket(ClientboundSetCompressionPacket(NetworkCompression.COMPRESSION_THRESHOLD))
- if(NetworkCompression.compressionThreshold > -1) {
+ if(NetworkCompression.COMPRESSION_THRESHOLD > -1) {
val pipeline = connection.channel().pipeline()
pipeline.addBefore(ChannelHandlers.RAW_PACKET_DECODER, ChannelHandlers.PACKET_COMPRESSION_DECODER, CompressionDecoder(player.networkManager))
pipeline.addBefore(ChannelHandlers.RAW_PACKET_ENCODER, ChannelHandlers.PACKET_COMPRESSION_ENCODER, CompressionEncoder(player.networkManager))
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundAddResourcepackPacket.kt b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundAddResourcepackPacket.kt
index d474060f0..726ac4163 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundAddResourcepackPacket.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundAddResourcepackPacket.kt
@@ -1,11 +1,12 @@
package io.github.dockyardmc.protocol.packets.play.clientbound
-import io.github.dockyardmc.extentions.writeOptionalOLD
import io.github.dockyardmc.extentions.writeString
import io.github.dockyardmc.extentions.writeTextComponent
import io.github.dockyardmc.extentions.writeUUID
import io.github.dockyardmc.protocol.packets.ClientboundPacket
+import io.github.dockyardmc.protocol.writeOptional
import io.github.dockyardmc.resourcepack.Resourcepack
+import io.netty.buffer.ByteBuf
class ClientboundAddResourcepackPacket(resourcepack: Resourcepack) : ClientboundPacket() {
@@ -14,8 +15,6 @@ class ClientboundAddResourcepackPacket(resourcepack: Resourcepack) : Clientbound
buffer.writeString(resourcepack.url)
buffer.writeString("what")
buffer.writeBoolean(resourcepack.required)
- buffer.writeOptionalOLD(resourcepack.promptMessage) {
- it.writeTextComponent(resourcepack.promptMessage!!)
- }
+ buffer.writeOptional(resourcepack.promptMessage, ByteBuf::writeTextComponent)
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt
index 84d14aefc..6a3ef1fc6 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt
@@ -1,12 +1,10 @@
package io.github.dockyardmc.protocol.packets.play.clientbound
-import io.github.dockyardmc.extentions.writeNBT
-import io.github.dockyardmc.extentions.writeOptionalOLD
-import io.github.dockyardmc.extentions.writeUUID
-import io.github.dockyardmc.extentions.writeVarInt
+import io.github.dockyardmc.extentions.*
import io.github.dockyardmc.player.*
import io.github.dockyardmc.protocol.packets.ClientboundPacket
-import io.github.dockyardmc.scroll.extensions.toComponent
+import io.github.dockyardmc.protocol.writeOptional
+import io.netty.buffer.ByteBuf
import kotlin.experimental.or
class ClientboundPlayerInfoUpdatePacket(vararg updates: PlayerInfoUpdate) : ClientboundPacket() {
@@ -26,9 +24,7 @@ class ClientboundPlayerInfoUpdatePacket(vararg updates: PlayerInfoUpdate) : Clie
is SetListedInfoUpdateAction -> buffer.writeBoolean(updateAction.listed)
is UpdateLatencyInfoUpdateAction -> buffer.writeVarInt(updateAction.ping)
is SetDisplayNameInfoUpdateAction -> {
- buffer.writeOptionalOLD(updateAction.displayName) { optional ->
- optional.writeNBT(updateAction.displayName!!.toComponent().toNBT())
- }
+ buffer.writeOptional(updateAction.displayName, ByteBuf::writeTextComponent)
}
}
}
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundRemoveResourcepackPacket.kt b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundRemoveResourcepackPacket.kt
index 16c79a755..bd95f41f1 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundRemoveResourcepackPacket.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundRemoveResourcepackPacket.kt
@@ -1,15 +1,14 @@
package io.github.dockyardmc.protocol.packets.play.clientbound
-import io.github.dockyardmc.extentions.writeOptionalOLD
import io.github.dockyardmc.extentions.writeUUID
import io.github.dockyardmc.protocol.packets.ClientboundPacket
+import io.github.dockyardmc.protocol.writeOptional
+import io.netty.buffer.ByteBuf
import java.util.*
class ClientboundRemoveResourcepackPacket(uuid: UUID?) : ClientboundPacket() {
init {
- buffer.writeOptionalOLD(uuid) {
- buffer.writeUUID(uuid!!)
- }
+ buffer.writeOptional(uuid, ByteBuf::writeUUID)
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundSetContainerContentPacket.kt b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundSetContainerContentPacket.kt
index e00268ebf..3b08208ea 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundSetContainerContentPacket.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/clientbound/ClientboundSetContainerContentPacket.kt
@@ -1,17 +1,17 @@
package io.github.dockyardmc.protocol.packets.play.clientbound
-import io.github.dockyardmc.extentions.writeItemStackList
import io.github.dockyardmc.extentions.writeVarInt
import io.github.dockyardmc.item.ItemStack
import io.github.dockyardmc.player.Player
import io.github.dockyardmc.protocol.packets.ClientboundPacket
+import io.github.dockyardmc.protocol.types.writeList
class ClientboundSetContainerContentPacket(player: Player, items: List) : ClientboundPacket() {
init {
buffer.writeVarInt(if(player.currentlyOpenScreen != null) 1 else 0)
buffer.writeVarInt(0)
- buffer.writeItemStackList(items)
+ buffer.writeList(items, ItemStack::write)
player.inventory.cursorItem.value.write(buffer)
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/serverbound/ServerboundPickItemFromEntityPacket.kt b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/serverbound/ServerboundPickItemFromEntityPacket.kt
index 2a0d0bf9e..43201fe44 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/serverbound/ServerboundPickItemFromEntityPacket.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/packets/play/serverbound/ServerboundPickItemFromEntityPacket.kt
@@ -1,12 +1,12 @@
package io.github.dockyardmc.protocol.packets.play.serverbound
import io.github.dockyardmc.entity.EntityManager
+import io.github.dockyardmc.events.Event
import io.github.dockyardmc.events.Events
import io.github.dockyardmc.events.PlayerPickItemFromEntityEvent
import io.github.dockyardmc.extentions.readVarInt
import io.github.dockyardmc.protocol.PlayerNetworkManager
import io.github.dockyardmc.protocol.packets.ServerboundPacket
-import io.github.dockyardmc.utils.getPlayerEventContext
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
@@ -15,10 +15,7 @@ class ServerboundPickItemFromEntityPacket(val entityId: Int, val includeData: Bo
override fun handle(processor: PlayerNetworkManager, connection: ChannelHandlerContext, size: Int, id: Int) {
val entity = EntityManager.getByIdOrNull(entityId) ?: return
- val context = getPlayerEventContext(processor.player)
- val contextEntitiesMutable = context.entities.toMutableSet()
- contextEntitiesMutable.add(entity)
- context.entities = contextEntitiesMutable
+ val context = Event.Context(players = setOf(processor.player), entities = setOf(entity))
val event = PlayerPickItemFromEntityEvent(processor.player, entity, includeData, context)
Events.dispatch(event)
diff --git a/src/main/kotlin/io/github/dockyardmc/protocol/types/ConsumeEffect.kt b/src/main/kotlin/io/github/dockyardmc/protocol/types/ConsumeEffect.kt
index 69df552bf..9ee41e8b1 100644
--- a/src/main/kotlin/io/github/dockyardmc/protocol/types/ConsumeEffect.kt
+++ b/src/main/kotlin/io/github/dockyardmc/protocol/types/ConsumeEffect.kt
@@ -3,7 +3,9 @@ package io.github.dockyardmc.protocol.types
import io.github.dockyardmc.data.CRC32CHasher
import io.github.dockyardmc.data.HashHolder
import io.github.dockyardmc.data.StaticHash
-import io.github.dockyardmc.extentions.*
+import io.github.dockyardmc.extentions.read
+import io.github.dockyardmc.extentions.readVarInt
+import io.github.dockyardmc.extentions.writeVarInt
import io.github.dockyardmc.protocol.DataComponentHashable
import io.github.dockyardmc.protocol.NetworkReadable
import io.github.dockyardmc.protocol.NetworkWritable
@@ -51,7 +53,7 @@ interface ConsumeEffect : NetworkWritable, DataComponentHashable {
override fun write(buffer: ByteBuf) {
buffer.writeVarInt(ConsumeEffect.effects.getByValue(this::class))
- buffer.writeList(effects, ByteBuf::writeAppliedPotionEffect)
+ buffer.writeList(effects, AppliedPotionEffect::write)
buffer.writeFloat(probability)
}
@@ -59,7 +61,7 @@ interface ConsumeEffect : NetworkWritable, DataComponentHashable {
const val ID = 0
override fun read(buffer: ByteBuf): ApplyEffects {
- return ApplyEffects(buffer.readList(ByteBuf::readAppliedPotionEffect), buffer.readFloat())
+ return ApplyEffects(buffer.readList(AppliedPotionEffect::read), buffer.readFloat())
}
}
diff --git a/src/main/kotlin/io/github/dockyardmc/registry/PotionEffects.kt b/src/main/kotlin/io/github/dockyardmc/registry/PotionEffects.kt
index d609f5c96..05136ad82 100644
--- a/src/main/kotlin/io/github/dockyardmc/registry/PotionEffects.kt
+++ b/src/main/kotlin/io/github/dockyardmc/registry/PotionEffects.kt
@@ -2,10 +2,13 @@ package io.github.dockyardmc.registry
import io.github.dockyardmc.data.CRC32CHasher
import io.github.dockyardmc.data.HashHolder
+import io.github.dockyardmc.extentions.readRegistryEntry
import io.github.dockyardmc.extentions.readVarInt
-import io.github.dockyardmc.extentions.writeOptionalOLD
import io.github.dockyardmc.extentions.writeVarInt
import io.github.dockyardmc.protocol.DataComponentHashable
+import io.github.dockyardmc.protocol.NetworkReadable
+import io.github.dockyardmc.protocol.NetworkWritable
+import io.github.dockyardmc.protocol.writeOptional
import io.github.dockyardmc.registry.registries.PotionEffect
import io.github.dockyardmc.registry.registries.PotionEffectRegistry
import io.github.dockyardmc.scheduler.runnables.inWholeMinecraftTicks
@@ -59,7 +62,18 @@ data class AppliedPotionEffect(
var effect: PotionEffect,
val settings: AppliedPotionEffectSettings,
var startTime: Long? = null,
-) : DataComponentHashable {
+) : DataComponentHashable, NetworkWritable {
+
+ override fun write(buffer: ByteBuf) {
+ effect.write(buffer)
+ settings.write(buffer)
+ }
+
+ companion object : NetworkReadable {
+ override fun read(buffer: ByteBuf): AppliedPotionEffect {
+ return AppliedPotionEffect(buffer.readRegistryEntry(PotionEffectRegistry), AppliedPotionEffectSettings.read(buffer))
+ }
+ }
override fun hashStruct(): HashHolder {
return CRC32CHasher.of {
@@ -68,6 +82,7 @@ data class AppliedPotionEffect(
//start field is only for server-side use
}
}
+
}
data class AppliedPotionEffectSettings(
@@ -111,8 +126,6 @@ data class AppliedPotionEffectSettings(
buffer.writeBoolean(isAmbient)
buffer.writeBoolean(showIcon)
buffer.writeBoolean(showIcon)
- buffer.writeOptionalOLD(hiddenEffect) {
- write(it)
- }
+ buffer.writeOptional(hiddenEffect, AppliedPotionEffectSettings::write)
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt b/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt
index f5dfc150c..b99de588d 100644
--- a/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt
+++ b/src/main/kotlin/io/github/dockyardmc/schematics/Schematic.kt
@@ -5,6 +5,7 @@ package io.github.dockyardmc.schematics
import cz.lukynka.prettylog.LogType
import cz.lukynka.prettylog.log
import io.github.dockyardmc.extentions.readVarInt
+import io.github.dockyardmc.extentions.reversed
import io.github.dockyardmc.extentions.toByteBuf
import io.github.dockyardmc.location.Location
import io.github.dockyardmc.registry.Blocks
@@ -13,17 +14,21 @@ import io.github.dockyardmc.maths.vectors.Vector3
import io.github.dockyardmc.world.chunk.Chunk
import io.github.dockyardmc.world.World
import io.github.dockyardmc.world.block.Block
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
+import it.unimi.dsi.fastutil.objects.ObjectArrayList
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import java.util.concurrent.CompletableFuture
data class Schematic(
var size: Vector3,
var offset: Vector3,
- var pallete: MutableMap,
+ var palette: Object2IntOpenHashMap,
var blocks: ByteArray,
) {
companion object {
- val empty = Schematic(Vector3(), Vector3(), mutableMapOf(), ByteArray(0))
+ val empty = Schematic(Vector3(), Vector3(), Object2IntOpenHashMap(), ByteArray(0))
+ val RED_STAINED_GLASS = Blocks.RED_STAINED_GLASS.toBlock()
}
}
@@ -38,11 +43,10 @@ fun World.placeSchematic(
location: Location,
) {
val blocks = schematic.blocks.toByteBuf()
- val updateChunks = mutableSetOf()
- val loadChunk = mutableSetOf>()
- val batchBlockUpdate = mutableListOf>()
-
- val flippedPallet = schematic.pallete.entries.associateBy({ it.value }) { it.key }
+ val updateChunks = ObjectOpenHashSet()
+ val loadChunk = ObjectOpenHashSet>()
+ val batchBlockUpdate = ObjectArrayList>()
+ val flippedPallet = schematic.palette.reversed()
for (y in 0 until schematic.size.y) {
for (z in 0 until schematic.size.z) {
@@ -50,7 +54,7 @@ fun World.placeSchematic(
val placeLoc = Location(x, y, z, location.world).add(location)
val id = blocks.readVarInt()
- val block = flippedPallet[id] ?: Blocks.RED_STAINED_GLASS.toBlock()
+ val block = flippedPallet[id] ?: Schematic.RED_STAINED_GLASS
val chunkX = ChunkUtils.getChunkCoordinate(placeLoc.x)
val chunkZ = ChunkUtils.getChunkCoordinate(placeLoc.z)
diff --git a/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt b/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt
index 5c7c947e1..87847d001 100644
--- a/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt
+++ b/src/main/kotlin/io/github/dockyardmc/schematics/SchematicReader.kt
@@ -3,6 +3,7 @@ package io.github.dockyardmc.schematics
import io.github.dockyardmc.maths.vectors.Vector3
import io.github.dockyardmc.scroll.extensions.contains
import io.github.dockyardmc.world.block.Block
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
import net.kyori.adventure.nbt.BinaryTagIO
import net.kyori.adventure.nbt.CompoundBinaryTag
import net.kyori.adventure.nbt.IntBinaryTag
@@ -11,7 +12,7 @@ import java.io.File
object SchematicReader {
- val READER = BinaryTagIO.reader(Long.MAX_VALUE)
+ val READER = BinaryTagIO.unlimitedReader()
fun read(file: File): Schematic {
if (!file.exists()) throw Exception("File $file does not exist!")
@@ -54,23 +55,20 @@ object SchematicReader {
blockArray = nbt.getByteArray("BlockData")
}
- val blocks = mutableMapOf()
+ val blocks = Object2IntOpenHashMap()
pallet.forEach { entry ->
val id = (entry.value as IntBinaryTag).value()
val block = Block.getBlockFromStateString(entry.key)
blocks[block] = id
}
-
val schematic = Schematic(
size = Vector3(width, height, length),
offset = offset,
- pallete = blocks.toMutableMap(),
+ palette = blocks,
blocks = blockArray.copyOf()
)
-// if(ConfigManager.config.implementationConfig.cacheSchematics) {
-// cache[getFileHash(file, "SHA-256")] = schematic
-// }
+
return schematic
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/io/github/dockyardmc/utils/ObjectPool.kt b/src/main/kotlin/io/github/dockyardmc/utils/ObjectPool.kt
new file mode 100644
index 000000000..2c1c54073
--- /dev/null
+++ b/src/main/kotlin/io/github/dockyardmc/utils/ObjectPool.kt
@@ -0,0 +1,46 @@
+package io.github.dockyardmc.utils
+
+import org.jctools.queues.MessagePassingQueue
+import org.jctools.queues.MpmcUnboundedXaddArrayQueue
+import java.lang.ref.Cleaner
+import java.lang.ref.SoftReference
+import java.util.function.UnaryOperator
+
+class ObjectPool(val supplier: () -> T, val sanitizer: UnaryOperator = UnaryOperator.identity()) {
+ companion object {
+ const val QUEUE_SIZE = 32_768
+ val CLEANER = Cleaner.create()
+ }
+
+ val size: Int get() = pool.size()
+ private val pool: MessagePassingQueue> = MpmcUnboundedXaddArrayQueue(QUEUE_SIZE)
+
+ fun get(): T {
+ var ref: SoftReference?
+ while (pool.poll().also { ref = it } != null) {
+ val result = ref?.get()
+ if (result != null) {
+ return result
+ }
+ }
+ return supplier.invoke()
+ }
+
+ fun add(obj: T) {
+ this.pool.offer(SoftReference(sanitizer.apply(obj)))
+ }
+
+ fun clear() {
+ this.pool.clear()
+ }
+
+ fun register(ref: Any, obj: T) {
+ CLEANER.register(ref, BufferedCleaner(this, obj))
+ }
+
+ class BufferedCleaner(val pool: ObjectPool, val obj: T) : Runnable {
+ override fun run() {
+ this.pool.add(obj)
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/io/github/dockyard/tests/network/VarIntTest.kt b/src/test/kotlin/io/github/dockyard/tests/network/VarIntTest.kt
new file mode 100644
index 000000000..02ba3f73d
--- /dev/null
+++ b/src/test/kotlin/io/github/dockyard/tests/network/VarIntTest.kt
@@ -0,0 +1,32 @@
+package io.github.dockyard.tests.network
+
+import io.github.dockyardmc.extentions.readVarInt
+import io.github.dockyardmc.extentions.writeVarInt
+import io.netty.buffer.Unpooled
+import org.junit.jupiter.api.Test
+import kotlin.test.assertEquals
+
+class VarIntTest {
+
+ @Test
+ fun testBoundaryValues() {
+ testValue(0)
+ testValue(127)
+ testValue(128)
+ testValue(16383)
+ testValue(16384)
+ testValue(2097151)
+ testValue(2097152)
+ testValue(268435455)
+ testValue(268435456)
+ testValue(Int.MAX_VALUE)
+ testValue(Int.MIN_VALUE)
+ }
+
+ private fun testValue(value: Int) {
+ val buffer = Unpooled.buffer()
+ buffer.writeVarInt(value)
+ val read = buffer.readVarInt()
+ assertEquals(value, read)
+ }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt b/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt
index 871d4e719..f1782348a 100644
--- a/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt
+++ b/src/test/kotlin/io/github/dockyard/tests/schematic/SchematicTest.kt
@@ -19,17 +19,14 @@ class SchematicTest {
}
@Test
- fun testParsing() {
+ fun testSchematicReadingAndPlacing() {
val world = WorldManager.mainWorld
assertDoesNotThrow {
val schematic = SchematicReader.read(Resources.getFile("test.schem").readBytes())
-
world.placeSchematic(schematic, world.locationAt(0, 0, 0))
-
- assertEquals(Blocks.RED_WOOL, world.locationAt(0, 0, 0).block.registryBlock)
- assertEquals(Blocks.NETHER_BRICK_FENCE, world.locationAt(4, 1, 5).block.registryBlock)
- assertEquals(Blocks.STONE, world.locationAt(27, 1, 23).block.registryBlock)
-
}
+ assertEquals(Blocks.RED_WOOL, world.locationAt(0, 0, 0).block.registryBlock)
+ assertEquals(Blocks.NETHER_BRICK_FENCE, world.locationAt(4, 1, 5).block.registryBlock)
+ assertEquals(Blocks.STONE, world.locationAt(27, 1, 23).block.registryBlock)
}
}
\ No newline at end of file