Update submodule name

This commit is contained in:
2026-09-04 15:51:16 +08:00
parent ddc5e2aa17
commit 1d6012ea23
38 files changed
+7 -3

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
kotlin {
explicitApi()
linuxX64()
linuxArm64()
macosArm64()
mingwX64()
iosArm64()
iosSimulatorArm64()
jvm { compilerOptions.jvmTarget = JvmTarget.JVM_1_8 }
sourceSets {
jvmMain.dependencies {
// no dependencies needed
}
nativeMain.dependencies {
implementation("io.ktor:ktor-network:3.5.2")
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.9.1")
}
commonTest.dependencies {
implementation(kotlin("test"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0")
}
}
compilerOptions.freeCompilerArgs.addAll("-Xexpect-actual-classes")
}
@@ -0,0 +1,32 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
@Suppress("CLASSNAME")
public expect class _Buffer {
public constructor()
public constructor(bytes: ByteArray)
public fun writeByte(value: Byte)
public fun writeShort(value: Short, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
public fun writeInt(value: Int, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
public fun writeLong(value: Long, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
public fun writeBytes(bytes: ByteArray)
public fun readByte(): Byte
public fun readShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short
public fun readInt(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Int
public fun readLong(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Long
public fun readBytes(length: Int): ByteArray
public fun toByteArray(): ByteArray
public fun hasRemaining(): Boolean
public fun close()
public val size: Int
}
public fun ByteArray.wrap(): _Buffer = _Buffer(this)
@@ -0,0 +1,12 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/4
*/
package cn.rtast.libmc.common
public enum class ByteOrder {
BIG_ENDIAN, LITTLE_ENDIAN
}
@@ -0,0 +1,24 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
@Suppress("CLASSNAME")
public expect class _ReadChannel {
public fun readByte(): Byte
public fun readShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short
public fun readInt(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Int
public fun readLong(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Long
public fun readBytes(length: Int): ByteArray
public fun readFully(out: ByteArray, start: Int = 0, end: Int = out.size)
}
@Suppress("CLASSNAME")
public expect class _WriteChannel {
public fun writeFully(value: ByteArray, startIndex: Int = 0, endIndex: Int = value.size)
public fun flush()
}
@@ -0,0 +1,14 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
/**
* An object class used to pass some parameters
* that exists only on native targets
*/
public expect class LibMCContext()
@@ -0,0 +1,21 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
@Suppress("CLASSNAME")
public expect class _Socket public constructor(host: String, port: Int, context: LibMCContext) {
public fun openReadChannel(): _ReadChannel
public fun openWriteChannel(): _WriteChannel
public fun close()
}
@Suppress("CLASSNAME")
public expect class _UdpSocket public constructor(host: String, port: Int, context: LibMCContext) {
public fun sendAndReceive(data: ByteArray): ByteArray
public fun close()
}
@@ -0,0 +1,97 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
import java.io.ByteArrayOutputStream
@Suppress("CLASSNAME")
public actual class _Buffer {
private val outStream = ByteArrayOutputStream()
private var readBuffer: ByteArray? = null
private var readOffset = 0
public actual constructor()
public actual constructor(bytes: ByteArray) {
this.readBuffer = bytes
outStream.write(bytes)
}
public actual fun writeByte(value: Byte) {
readBuffer = null
outStream.write(value.toInt())
}
public actual fun writeShort(value: Short, endian: ByteOrder) {
val v = value.toInt()
if (endian == ByteOrder.BIG_ENDIAN) {
outStream.write(v shr 8)
outStream.write(v)
} else {
outStream.write(v)
outStream.write(v shr 8)
}
}
public actual fun writeInt(value: Int, endian: ByteOrder) {
if (endian == ByteOrder.BIG_ENDIAN) {
outStream.write(value shr 24)
outStream.write(value shr 16)
outStream.write(value shr 8)
outStream.write(value)
} else {
outStream.write(value)
outStream.write(value shr 8)
outStream.write(value shr 16)
outStream.write(value shr 24)
}
}
public actual fun writeLong(value: Long, endian: ByteOrder) {
if (endian == ByteOrder.BIG_ENDIAN) {
for (i in 56 downTo 0 step 8) outStream.write((value shr i).toInt())
} else {
for (i in 0..56 step 8) outStream.write((value shr i).toInt())
}
}
public actual fun writeBytes(bytes: ByteArray) {
readBuffer = null
outStream.write(bytes)
}
private fun ensureReadArray(): ByteArray {
var buf = readBuffer
if (buf == null) {
buf = outStream.toByteArray()
readBuffer = buf
}
return buf
}
public actual fun readByte(): Byte {
val array = ensureReadArray()
if (readOffset >= array.size) throw IndexOutOfBoundsException("Buffer underflow")
return array[readOffset++]
}
public actual fun readShort(endian: ByteOrder): Short = readBytes(2).toShort(endian)
public actual fun readInt(endian: ByteOrder): Int = readBytes(4).toInt(endian)
public actual fun readLong(endian: ByteOrder): Long = readBytes(8).toLong(endian)
public actual fun readBytes(length: Int): ByteArray {
val array = ensureReadArray()
if (readOffset + length > array.size) throw IndexOutOfBoundsException("Buffer underflow")
val result = array.copyOfRange(readOffset, readOffset + length)
readOffset += length
return result
}
public actual fun toByteArray(): ByteArray = outStream.toByteArray()
public actual fun hasRemaining(): Boolean = readOffset < ensureReadArray().size
public actual fun close(): Unit = outStream.close()
public actual val size: Int get() = outStream.size()
}
@@ -0,0 +1,58 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
import java.io.EOFException
import java.io.InputStream
import java.io.OutputStream
@Suppress("CLASSNAME")
public actual class _ReadChannel(private val _inputStream: InputStream) {
public actual fun readByte(): Byte = _inputStream.read().toByte()
public actual fun readBytes(length: Int): ByteArray = _inputStream.readNBytes(length)
public actual fun readFully(out: ByteArray, start: Int, end: Int) {
var bytesRead = 0
val length = end - start
while (bytesRead < length) {
val read = _inputStream.read(out, start + bytesRead, length - bytesRead)
if (read == -1) throw IllegalStateException("End of stream")
bytesRead += read
}
}
public actual fun readShort(endian: ByteOrder): Short = readBytes(2).toShort(endian)
public actual fun readInt(endian: ByteOrder): Int = readBytes(4).toInt(endian)
public actual fun readLong(endian: ByteOrder): Long = readBytes(8).toLong(endian)
}
@Suppress("CLASSNAME")
public actual class _WriteChannel {
private val _outputStream: OutputStream
public constructor(outputStream: OutputStream) {
_outputStream = outputStream
}
public actual fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int): Unit =
_outputStream.write(value, startIndex, endIndex - startIndex)
public actual fun flush(): Unit = _outputStream.flush()
}
private fun InputStream.readNBytes(length: Int): ByteArray {
val buffer = ByteArray(length)
var totalRead = 0
while (totalRead < length) {
val read = this.read(buffer, totalRead, length - totalRead)
if (read == -1) throw EOFException()
totalRead += read
}
return buffer
}
@@ -0,0 +1,12 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
/**
* No Context for jvm targets
*/
public actual class LibMCContext
@@ -0,0 +1,40 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/4
*/
package cn.rtast.libmc.common
internal fun ByteArray.toShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short {
val b1 = this[0].toInt() and 0xFF
val b2 = this[1].toInt() and 0xFF
return if (endian == ByteOrder.BIG_ENDIAN) {
((b1 shl 8) or b2).toShort()
} else {
((b2 shl 8) or b1).toShort()
}
}
internal fun ByteArray.toInt(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Int {
val b1 = this[0].toInt() and 0xFF
val b2 = this[1].toInt() and 0xFF
val b3 = this[2].toInt() and 0xFF
val b4 = this[3].toInt() and 0xFF
return if (endian == ByteOrder.BIG_ENDIAN) {
(b1 shl 24) or (b2 shl 16) or (b3 shl 8) or b4
} else {
(b4 shl 24) or (b3 shl 16) or (b2 shl 8) or b1
}
}
internal fun ByteArray.toLong(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Long {
var result = 0L
if (endian == ByteOrder.BIG_ENDIAN) {
for (b in this) result = (result shl 8) or (b.toLong() and 0xFF)
} else {
for (i in 7 downTo 0) result = (result shl 8) or (this[i].toLong() and 0xFF)
}
return result
}
@@ -0,0 +1,40 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetSocketAddress
import java.net.Socket as JvmSocket
@Suppress("CLASSNAME")
public actual class _Socket public actual constructor(host: String, port: Int, context: LibMCContext) {
private val socket = JvmSocket(host, port)
public actual fun openReadChannel(): _ReadChannel = _ReadChannel(socket.getInputStream())
public actual fun openWriteChannel(): _WriteChannel = _WriteChannel(socket.getOutputStream())
public actual fun close(): Unit = socket.close()
}
@Suppress("CLASSNAME")
public actual class _UdpSocket public actual constructor(host: String, port: Int, context: LibMCContext) {
private val socket = DatagramSocket().apply {
soTimeout = 3000
connect(InetSocketAddress(host, port))
}
public actual fun sendAndReceive(data: ByteArray): ByteArray {
socket.send(DatagramPacket(data, data.size))
val buf = ByteArray(2048)
val receivePacket = DatagramPacket(buf, buf.size)
socket.receive(receivePacket)
return buf.copyOf(receivePacket.length)
}
public actual fun close(): Unit = socket.close()
}
@@ -0,0 +1,73 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
import io.ktor.utils.io.bits.*
import kotlinx.io.Buffer
import kotlinx.io.readByteArray
@Suppress("CLASSNAME")
public actual class _Buffer {
private val _delegateBuf: Buffer
public actual constructor() {
_delegateBuf = Buffer()
}
public actual constructor(bytes: ByteArray) {
_delegateBuf = Buffer().apply { write(bytes) }
}
public actual fun writeByte(value: Byte): Unit = _delegateBuf.writeByte(value)
public actual fun writeShort(value: Short, endian: ByteOrder) {
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeShort(value)
else _delegateBuf.writeShort(value.reverseByteOrder())
}
public actual fun writeInt(value: Int, endian: ByteOrder) {
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeInt(value)
else _delegateBuf.writeInt(value.reverseByteOrder())
}
public actual fun writeLong(value: Long, endian: ByteOrder) {
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeLong(value)
else _delegateBuf.writeLong(value.reverseByteOrder())
}
public actual fun writeBytes(bytes: ByteArray): Unit = _delegateBuf.write(bytes)
public actual fun readByte(): Byte = _delegateBuf.readByte()
public actual fun readShort(endian: ByteOrder): Short {
val v = _delegateBuf.readShort()
return if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
}
public actual fun readInt(endian: ByteOrder): Int {
val v = _delegateBuf.readInt()
return if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
}
public actual fun readLong(endian: ByteOrder): Long {
val v = _delegateBuf.readLong()
return if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
}
public actual fun readBytes(length: Int): ByteArray = _delegateBuf.readByteArray(length)
public actual fun toByteArray(): ByteArray {
val copy = _delegateBuf.peek()
return try {
copy.readByteArray()
} finally {
copy.close()
}
}
public actual fun hasRemaining(): Boolean = !_delegateBuf.exhausted()
public actual fun close(): Unit = _delegateBuf.close()
public actual val size: Int
get() = _delegateBuf.size.toInt()
}
@@ -0,0 +1,49 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
import io.ktor.utils.io.*
import io.ktor.utils.io.bits.reverseByteOrder
import kotlinx.coroutines.runBlocking
@Suppress("CLASSNAME")
public actual class _ReadChannel(private val _readChannel: ByteReadChannel) {
public actual fun readByte(): Byte = runBlocking { _readChannel.readByte() }
public actual fun readBytes(length: Int): ByteArray = runBlocking { _readChannel.readByteArray(length) }
public actual fun readFully(out: ByteArray, start: Int, end: Int): Unit =
runBlocking { _readChannel.readFully(out, start, end) }
public actual fun readShort(endian: ByteOrder): Short = runBlocking {
val v = _readChannel.readShort()
if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
}
public actual fun readInt(endian: ByteOrder): Int = runBlocking {
val v = _readChannel.readInt()
if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
}
public actual fun readLong(endian: ByteOrder): Long = runBlocking {
val v = _readChannel.readLong()
if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
}
}
@Suppress("CLASSNAME")
public actual class _WriteChannel {
private val _writeChannel: ByteWriteChannel
public constructor(writeChannel: ByteWriteChannel) {
_writeChannel = writeChannel
}
public actual fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int): Unit =
runBlocking { _writeChannel.writeFully(value, startIndex, endIndex) }
public actual fun flush(): Unit = runBlocking { _writeChannel.flush() }
}
@@ -0,0 +1,23 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
@file:Suppress("PropertyName")
package cn.rtast.libmc.common
import io.ktor.network.selector.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
public actual class LibMCContext actual constructor() {
internal var _selectorManager: SelectorManager = SelectorManager(Dispatchers.IO)
internal var _autoCloseSelectorManager: Boolean = false
public constructor(selectorManager: SelectorManager, autoClose: Boolean = false) : this() {
_selectorManager = selectorManager
_autoCloseSelectorManager = autoClose
}
}
@@ -0,0 +1,47 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/3
*/
package cn.rtast.libmc.common
import io.ktor.network.sockets.*
import io.ktor.utils.io.core.*
import kotlinx.coroutines.runBlocking
import kotlinx.io.readByteArray
@Suppress("CLASSNAME")
public actual class _Socket public actual constructor(host: String, port: Int, context: LibMCContext) {
private val ctx = context
private val socket = runBlocking { aSocket(ctx._selectorManager).tcp().connect(host, port) }
public actual fun openReadChannel(): _ReadChannel = _ReadChannel(socket.openReadChannel())
public actual fun openWriteChannel(): _WriteChannel =
_WriteChannel(socket.openWriteChannel(autoFlush = true))
public actual fun close() {
socket.close()
if (ctx._autoCloseSelectorManager) ctx._selectorManager.close()
}
}
@Suppress("CLASSNAME")
public actual class _UdpSocket public actual constructor(host: String, port: Int, context: LibMCContext) {
private val ctx = context
// use bind to create an unconnected socket
private val socket = runBlocking { aSocket(ctx._selectorManager).udp().bind() }
private val remoteAddress = InetSocketAddress(host, port)
public actual fun sendAndReceive(data: ByteArray): ByteArray = runBlocking {
val packet = buildPacket { writeFully(data) }
socket.send(Datagram(packet, remoteAddress))
socket.receive().packet.readByteArray()
}
public actual fun close() {
socket.close()
if (ctx._autoCloseSelectorManager) ctx._selectorManager.close()
}
}