init
This commit is contained in:
812
packetLib.go
Normal file
812
packetLib.go
Normal file
@@ -0,0 +1,812 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func generateRandomBytes(size int) ([]byte, error) {
|
||||
randomBytes := make([]byte, size)
|
||||
_, err := rand.Read(randomBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return randomBytes, nil
|
||||
}
|
||||
|
||||
func serverIDCreate() ([]byte, error) {
|
||||
result := make([]byte, 20)
|
||||
charRange := 0x7E - 0x21 + 1
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
// Generate a random number in the range [charStart, charEnd]
|
||||
num, err := rand.Int(rand.Reader, big.NewInt(int64(charRange)))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
result[i] = byte(0x21 + num.Int64())
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type TextPiece struct {
|
||||
Text string `json:"text,omitempty"`
|
||||
Color string `json:"color,omitempty"`
|
||||
CleanText string `json:"cleantext,omitempty"`
|
||||
}
|
||||
|
||||
type TextComponent struct {
|
||||
Text string `json:"text,omitempty"`
|
||||
Extra []TextPiece `json:"extra,omitempty"`
|
||||
CleanText string `json:"cleantext,omitempty"`
|
||||
}
|
||||
|
||||
type RegistryEntry struct {
|
||||
EntryID string `json:"entryID,omitempty"`
|
||||
HasNBT bool `json:"hasNBT,omitempty"`
|
||||
//TODO implement the nbt data
|
||||
NBTData *bytes.Buffer `json:"nbtData,omitempty"`
|
||||
}
|
||||
|
||||
type RegistryData struct {
|
||||
RegistryID string `json:"registryID,omitempty"`
|
||||
Entries []RegistryEntry `json:"entries,omitempty"`
|
||||
}
|
||||
|
||||
type TagArray struct {
|
||||
TagName string `json:"tagName,omitempty"`
|
||||
Entries []int32 `json:"entries,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateTag struct {
|
||||
TagRegistryIdentifier string `json:"tagRegistryIdentifier,omitempty"`
|
||||
Tags []TagArray `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
type DatapackInfo struct {
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
type ServerLink struct {
|
||||
LabelString string `json:"labelString,omitempty"`
|
||||
LabelInt int32 `json:"labelInt,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// GenerateRSAKeyPair generates an RSA key pair and returns the public and private keys.
|
||||
func GenerateRSAKeyPair() (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return privateKey, &privateKey.PublicKey, nil
|
||||
}
|
||||
|
||||
// ExportRSAPublicKey exports the public key in ASN.1 DER format.
|
||||
func ExportRSAPublicKey(pubKey *rsa.PublicKey) ([]byte, error) {
|
||||
// Marshal the public key to ASN.1 DER format
|
||||
pubASN1, err := x509.MarshalPKIXPublicKey(pubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Return the raw DER-encoded bytes
|
||||
return pubASN1, nil
|
||||
}
|
||||
|
||||
type cfb8 struct {
|
||||
b cipher.Block
|
||||
blockSize int
|
||||
in []byte
|
||||
out []byte
|
||||
|
||||
decrypt bool
|
||||
}
|
||||
|
||||
func (x *cfb8) XORKeyStream(dst, src []byte) {
|
||||
for i := range src {
|
||||
x.b.Encrypt(x.out, x.in)
|
||||
copy(x.in[:x.blockSize-1], x.in[1:])
|
||||
if x.decrypt {
|
||||
x.in[x.blockSize-1] = src[i]
|
||||
}
|
||||
dst[i] = src[i] ^ x.out[0]
|
||||
if !x.decrypt {
|
||||
x.in[x.blockSize-1] = dst[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewCFB8Encryptor returns a Stream which encrypts with cipher feedback mode
|
||||
// (segment size = 8), using the given Block. The iv must be the same length as
|
||||
// the Block's block size.
|
||||
func newCFB8Encryptor(block cipher.Block, iv []byte) cipher.Stream {
|
||||
return newCFB8(block, iv, false)
|
||||
}
|
||||
|
||||
// NewCFB8Decryptor returns a Stream which decrypts with cipher feedback mode
|
||||
// (segment size = 8), using the given Block. The iv must be the same length as
|
||||
// the Block's block size.
|
||||
func newCFB8Decryptor(block cipher.Block, iv []byte) cipher.Stream {
|
||||
return newCFB8(block, iv, true)
|
||||
}
|
||||
|
||||
func newCFB8(block cipher.Block, iv []byte, decrypt bool) cipher.Stream {
|
||||
blockSize := block.BlockSize()
|
||||
if len(iv) != blockSize {
|
||||
// stack trace will indicate whether it was de or encryption
|
||||
panic("cipher.newCFB: IV length must equal block size")
|
||||
}
|
||||
x := &cfb8{
|
||||
b: block,
|
||||
blockSize: blockSize,
|
||||
out: make([]byte, blockSize),
|
||||
in: make([]byte, blockSize),
|
||||
decrypt: decrypt,
|
||||
}
|
||||
copy(x.in, iv)
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
// NewCFB8Cipher Initialize AES/CFB8 encryption using the shared secret
|
||||
func NewCFB8Cipher(secret []byte) (cipher.Stream, cipher.Stream, error) {
|
||||
block, err := aes.NewCipher(secret)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Create CFB8 encryption/decryption ciphers using the custom implementation
|
||||
iv := secret // Initial vector (IV) is the same as the secret in this case
|
||||
encryptStream := newCFB8Encryptor(block, iv)
|
||||
decryptStream := newCFB8Decryptor(block, iv)
|
||||
|
||||
return encryptStream, decryptStream, nil
|
||||
}
|
||||
|
||||
func AuthDigest(parts [][]byte) string {
|
||||
h := sha1.New()
|
||||
|
||||
// Hash each part incrementally
|
||||
for _, part := range parts {
|
||||
io.WriteString(h, string(part))
|
||||
}
|
||||
|
||||
// Finalize the hash
|
||||
hash := h.Sum(nil)
|
||||
|
||||
// Check for negative hashes
|
||||
negative := (hash[0] & 0x80) == 0x80
|
||||
if negative {
|
||||
hash = twosComplement(hash)
|
||||
}
|
||||
|
||||
// Trim away zeroes
|
||||
res := strings.TrimLeft(hex.EncodeToString(hash), "0")
|
||||
if negative {
|
||||
res = "-" + res
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// little endian
|
||||
func twosComplement(p []byte) []byte {
|
||||
carry := true
|
||||
for i := len(p) - 1; i >= 0; i-- {
|
||||
p[i] = ^p[i]
|
||||
if carry {
|
||||
carry = p[i] == 0xff
|
||||
p[i]++
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type MojangProfile struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Properties []MojangProperty `json:"properties"`
|
||||
}
|
||||
|
||||
type MojangProperty struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
Signature string `json:"signature"`
|
||||
}
|
||||
|
||||
func (player *Player) hasJoinedSession(sharedSecret []byte) (bool, error) {
|
||||
serverKey, err := ExportRSAPublicKey(serverPublicKey)
|
||||
serverIDHash := AuthDigest([][]byte{serverID, sharedSecret, serverKey})
|
||||
remoteAddr := strings.Split(player.conn.RemoteAddr().String(), ":")[0]
|
||||
url := fmt.Sprintf("https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s", player.name, serverIDHash, remoteAddr)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return false, fmt.Errorf("failed to verify session: %s", resp.Status)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var profile MojangProfile
|
||||
err = json.Unmarshal(body, &profile)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
player.profile = profile
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// EncryptPacket encrypts a packet using the AES/CFB8 cipher stream.
|
||||
func EncryptPacket(stream cipher.Stream, data *bytes.Buffer) *bytes.Buffer {
|
||||
if stream == nil {
|
||||
return data
|
||||
}
|
||||
encryptedData := make([]byte, data.Len())
|
||||
stream.XORKeyStream(encryptedData, data.Bytes())
|
||||
return bytes.NewBuffer(encryptedData)
|
||||
}
|
||||
|
||||
// DecryptingReader returns a *bufio.Reader that provides decrypted data from the original reader.
|
||||
func DecryptingReader(stream cipher.Stream, reader *bufio.Reader) *bufio.Reader {
|
||||
pr, pw := io.Pipe() // create a pipe to stream decrypted data
|
||||
|
||||
go func() {
|
||||
defer pw.Close() // ensure the pipe writer is closed when done
|
||||
buf := make([]byte, 4096) // buffer size, adjust as needed
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
pw.CloseWithError(err) // propagate any non-EOF error to the pipe reader
|
||||
return
|
||||
}
|
||||
|
||||
data := buf[:n]
|
||||
decryptedBlock := make([]byte, len(data))
|
||||
if stream != nil {
|
||||
stream.XORKeyStream(decryptedBlock, data) // decrypt the data
|
||||
} else {
|
||||
decryptedBlock = data // if no stream, just pass the data through
|
||||
}
|
||||
|
||||
_, err = pw.Write(decryptedBlock) // write decrypted data to the pipe writer
|
||||
if err != nil {
|
||||
pw.CloseWithError(err) // propagate write errors
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return bufio.NewReader(pr) // wrap the pipe reader in a bufio.Reader
|
||||
}
|
||||
|
||||
// Function to clean Minecraft formatting from a text
|
||||
func cleanMinecraftFormatting(text string) string {
|
||||
// Regex to match Minecraft formatting codes like § and &
|
||||
regex := regexp.MustCompile(`(?i)§[0-9A-FK-OR]`)
|
||||
return regex.ReplaceAllString(text, "")
|
||||
}
|
||||
|
||||
// Decompress function using zlib
|
||||
func decompress(data *bytes.Buffer) (buf *bytes.Buffer, err error) {
|
||||
reader, err := zlib.NewReader(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func(reader io.ReadCloser) {
|
||||
_ = reader.Close()
|
||||
}(reader)
|
||||
|
||||
var decompressedData bytes.Buffer
|
||||
_, err = io.Copy(&decompressedData, reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return &decompressedData, nil
|
||||
}
|
||||
|
||||
// Compress function using zlib
|
||||
func compress(data *bytes.Buffer) (*bytes.Buffer, error) {
|
||||
var compressedData bytes.Buffer
|
||||
writer := zlib.NewWriter(&compressedData)
|
||||
|
||||
_, err := writer.Write(data.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = writer.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &compressedData, nil
|
||||
}
|
||||
|
||||
// Modified version of `sendPacket` with hexdump logging, including unencrypted data
|
||||
func (player *Player) sendPacket(packetID int32, packetData *bytes.Buffer) (err error) {
|
||||
var origDataBuffer bytes.Buffer
|
||||
addVarint(&origDataBuffer, packetID) // Add the Packet ID as a VarInt
|
||||
_, err = origDataBuffer.ReadFrom(packetData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var outBuffer bytes.Buffer
|
||||
var outTempBuffer bytes.Buffer
|
||||
length := int32(origDataBuffer.Len()) // Get the length of the uncompressed packet
|
||||
compressed := false // Track if the packet is compressed
|
||||
|
||||
// Compression based on a threshold
|
||||
if player.compressionThreshold >= 0 && length >= player.compressionThreshold {
|
||||
compressed = true // Mark that compression was applied
|
||||
compressedData, err := compress(&origDataBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
origDataBuffer = *compressedData
|
||||
|
||||
// Add the uncompressed length to outTempBuffer
|
||||
addVarint(&outTempBuffer, length)
|
||||
}
|
||||
encrypted := player.encryptStream != nil
|
||||
|
||||
// Log the unencrypted packet data
|
||||
log.Printf("Unencrypted Packet ID: %d", packetID)
|
||||
log.Printf("Unencrypted Packet Length: %d (compressed: %v, encrypted: %v)", origDataBuffer.Len(), compressed, encrypted)
|
||||
log.Printf("Hexdump of Unencrypted Packet:\n%s", hex.Dump(origDataBuffer.Bytes()))
|
||||
|
||||
// Encrypt the (compressed or uncompressed) data buffer
|
||||
dataBuffer := origDataBuffer
|
||||
|
||||
// Append the (compressed or uncompressed) data buffer to outTempBuffer
|
||||
_, err = outTempBuffer.ReadFrom(&dataBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add the total packet length to outBuffer
|
||||
addVarint(&outBuffer, int32(outTempBuffer.Len()))
|
||||
_, err = outBuffer.ReadFrom(&outTempBuffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if encrypted {
|
||||
outBuffer = *EncryptPacket(player.encryptStream, &outBuffer)
|
||||
}
|
||||
_, err = player.conn.Write(outBuffer.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Modified version of `readPacket` with hexdump logging
|
||||
func (player *Player) readPacket() (packetID int32, packetData *bytes.Buffer, err error) {
|
||||
packetData = &bytes.Buffer{}
|
||||
finalReader := player.reader
|
||||
if player.decryptStream != nil {
|
||||
finalReader = DecryptingReader(player.decryptStream, player.reader)
|
||||
}
|
||||
packetLength, _, err := readVarint(finalReader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
packetDataBytes := make([]byte, packetLength)
|
||||
nt, err := io.ReadFull(finalReader, packetDataBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = packetData.Write(packetDataBytes)
|
||||
if err != nil {
|
||||
return 0, &bytes.Buffer{}, err
|
||||
}
|
||||
n := int32(nt)
|
||||
if n != packetLength {
|
||||
err = errors.New("packet read length mismatch")
|
||||
return
|
||||
}
|
||||
|
||||
var dataLength int
|
||||
compressed := false // Track if the packet is compressed
|
||||
if player.compressionThreshold > 0 {
|
||||
dataLengthTemp, errTemp := receiveVarint(packetData)
|
||||
err = errTemp
|
||||
dataLength = int(dataLengthTemp)
|
||||
}
|
||||
|
||||
// If dataLength > 0, it means the packet is compressed
|
||||
if dataLength > 0 {
|
||||
compressed = true
|
||||
packetData, err = decompress(packetData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Extract packet ID
|
||||
packetID, err = receiveVarint(packetData)
|
||||
|
||||
// Log the packet information
|
||||
log.Printf("Received Packet ID: %d", packetID)
|
||||
log.Printf("Packet Length: %d (compressed: %v)", packetLength, compressed)
|
||||
log.Printf("Hexdump of Decoded Packet:\n%s", hex.Dump(packetData.Bytes()))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func addVarint(buffer *bytes.Buffer, value int32) {
|
||||
uValue := uint32(value) // Explicitly cast to an unsigned type
|
||||
for {
|
||||
b := byte(uValue & 0x7F)
|
||||
uValue >>= 7
|
||||
|
||||
if (uValue != 0 && uValue != 0xFFFFFFFF) || (b&0x40 != 0) {
|
||||
b |= 0x80
|
||||
}
|
||||
|
||||
addByte(buffer, b)
|
||||
|
||||
if uValue == 0 || uValue == 0xFFFFFFFF {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addVarlong(buffer *bytes.Buffer, value int64) {
|
||||
uValue := uint64(value) // Explicitly cast to an unsigned type
|
||||
for {
|
||||
b := byte(uValue & 0x7F)
|
||||
uValue >>= 7
|
||||
|
||||
if (uValue != 0 && uValue != 0xFFFFFFFFFFFFFFFF) || (b&0x40 != 0) {
|
||||
b |= 0x80
|
||||
}
|
||||
|
||||
addByte(buffer, b)
|
||||
|
||||
if uValue == 0 || uValue == 0xFFFFFFFFFFFFFFFF {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readVarint(r *bufio.Reader) (value int32, length uint32, err error) {
|
||||
var (
|
||||
b byte
|
||||
shift uint64
|
||||
uValue uint32
|
||||
)
|
||||
|
||||
for {
|
||||
b, err = r.ReadByte()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
length++
|
||||
|
||||
uValue |= (uint32(b) & 0x7F) << shift
|
||||
shift += 7
|
||||
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if shift < 8*uint64(length) && b&0x40 != 0 {
|
||||
uValue |= ^uint32(0) << shift
|
||||
}
|
||||
value = int32(uValue)
|
||||
return
|
||||
}
|
||||
|
||||
func receiveVarint(buf *bytes.Buffer) (value int32, err error) {
|
||||
var (
|
||||
b byte
|
||||
shift uint64
|
||||
uValue uint32
|
||||
length uint32
|
||||
)
|
||||
|
||||
for i := 0; i < buf.Len(); i++ {
|
||||
b, err = buf.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
length++
|
||||
|
||||
uValue |= (uint32(b) & 0x7F) << shift
|
||||
shift += 7
|
||||
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if shift < 8*uint64(length) && b&0x40 != 0 {
|
||||
uValue |= ^uint32(0) << shift
|
||||
}
|
||||
value = int32(uValue)
|
||||
return
|
||||
}
|
||||
|
||||
func receiveVarlong(buf *bytes.Buffer) (currentValue int64) {
|
||||
var (
|
||||
b byte
|
||||
shift uint64
|
||||
uValue uint64
|
||||
length uint32
|
||||
)
|
||||
|
||||
for i := 0; i < buf.Len(); i++ {
|
||||
bx, err := buf.ReadByte()
|
||||
b = bx
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
length++
|
||||
|
||||
uValue |= (uint64(b) & 0x7F) << shift
|
||||
shift += 7
|
||||
|
||||
if b&0x80 == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if shift < 8*uint64(length) && b&0x40 != 0 {
|
||||
uValue |= ^uint64(0) << shift
|
||||
}
|
||||
currentValue = int64(uValue)
|
||||
return currentValue
|
||||
}
|
||||
|
||||
func addUUID(buffer *bytes.Buffer, inUUID uuid.UUID) int32 {
|
||||
binaryUUID, err := inUUID.MarshalBinary()
|
||||
if err != nil {
|
||||
log.Println("Error marshalling UUID:", err)
|
||||
return 0
|
||||
}
|
||||
buffer.Write(binaryUUID)
|
||||
return int32(len(binaryUUID))
|
||||
}
|
||||
|
||||
// Decodes a UUID from the buffer.
|
||||
func receiveUUID(buffer *bytes.Buffer) (value uuid.UUID, err error) {
|
||||
b := make([]byte, 16)
|
||||
_, err = buffer.Read(b)
|
||||
if err != nil {
|
||||
return uuid.UUID{}, err
|
||||
}
|
||||
value, err = uuid.FromBytes(b)
|
||||
if err != nil {
|
||||
return uuid.UUID{}, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func addByte(buffer *bytes.Buffer, byte byte) {
|
||||
buffer.WriteByte(byte)
|
||||
}
|
||||
|
||||
func addBool(buffer *bytes.Buffer, boolean bool) {
|
||||
var boolByte byte = 0x00
|
||||
if boolean {
|
||||
boolByte = 0x01
|
||||
}
|
||||
buffer.WriteByte(boolByte)
|
||||
}
|
||||
|
||||
func receiveBool(buffer *bytes.Buffer) (boolean bool, err error) {
|
||||
b, err := buffer.ReadByte()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
boolean = b == 1
|
||||
return
|
||||
}
|
||||
|
||||
func addUint16(buffer *bytes.Buffer, value uint16) {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, value)
|
||||
buffer.Write(b)
|
||||
}
|
||||
|
||||
// Decodes an uint16 from the buffer.
|
||||
func receiveUint16(buffer *bytes.Buffer) (value uint16) {
|
||||
// Create a byte slice to hold the 2 bytes for the uint16.
|
||||
b := make([]byte, 2)
|
||||
|
||||
// Read exactly 2 bytes from the buffer.
|
||||
_, err := buffer.Read(b)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Convert the byte slice to uint16 using BigEndian.
|
||||
value = binary.BigEndian.Uint16(b)
|
||||
return value
|
||||
}
|
||||
|
||||
func addInt64(buffer *bytes.Buffer, value int64) {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, uint64(value))
|
||||
buffer.Write(b)
|
||||
}
|
||||
|
||||
func receiveInt64(buffer *bytes.Buffer) (value int64) {
|
||||
b := make([]byte, 8)
|
||||
_, err := buffer.Read(b)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
value = int64(binary.BigEndian.Uint64(b))
|
||||
return
|
||||
}
|
||||
|
||||
func addFloat32(buffer *bytes.Buffer, value float32) {
|
||||
bits := math.Float32bits(value)
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, bits)
|
||||
buffer.Write(b)
|
||||
}
|
||||
|
||||
// Decodes a float32 from the buffer.
|
||||
func receiveFloat32(buffer *bytes.Buffer) (value float32) {
|
||||
b := make([]byte, 4)
|
||||
_, err := buffer.Read(b)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
value = math.Float32frombits(binary.BigEndian.Uint32(b))
|
||||
return
|
||||
}
|
||||
|
||||
func addFloat64(buffer *bytes.Buffer, value float64) {
|
||||
bits := math.Float64bits(value)
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, bits)
|
||||
buffer.Write(b)
|
||||
}
|
||||
|
||||
// Decodes a float64 from the buffer.
|
||||
func receiveFloat64(buffer *bytes.Buffer) (value float64) {
|
||||
b := make([]byte, 8)
|
||||
_, err := buffer.Read(b)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
value = math.Float64frombits(binary.BigEndian.Uint64(b))
|
||||
return
|
||||
}
|
||||
|
||||
func addInt32(buffer *bytes.Buffer, value int32) {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, uint32(value))
|
||||
buffer.Write(b)
|
||||
}
|
||||
|
||||
// Decodes an int32 from the buffer.
|
||||
func receiveInt32(buffer *bytes.Buffer) (value int32) {
|
||||
b := make([]byte, 4)
|
||||
_, err := buffer.Read(b)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
value = int32(binary.BigEndian.Uint32(b))
|
||||
return
|
||||
}
|
||||
|
||||
func addInt16(buffer *bytes.Buffer, value int16) {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, uint16(value))
|
||||
buffer.Write(b)
|
||||
}
|
||||
|
||||
func addUint32(buffer *bytes.Buffer, value uint32) {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, value)
|
||||
buffer.Write(b)
|
||||
}
|
||||
|
||||
// Decodes an uint32 from the buffer.
|
||||
func receiveUint32(buffer *bytes.Buffer) (value uint32, err error) {
|
||||
b := make([]byte, 4)
|
||||
if _, err = buffer.Read(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
value = binary.BigEndian.Uint32(b)
|
||||
return
|
||||
}
|
||||
|
||||
func addString(buffer *bytes.Buffer, str string) {
|
||||
// Encode string length using VarInt.
|
||||
addVarint(buffer, int32(len(str)))
|
||||
// Append the string bytes.
|
||||
buffer.Write([]byte(str))
|
||||
}
|
||||
|
||||
// Decodes a string from the buffer.
|
||||
func receiveString(buf *bytes.Buffer) (strOut string, err error) {
|
||||
stringLen, err := receiveVarint(buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
stringBytes := make([]byte, stringLen)
|
||||
_, err = buf.Read(stringBytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
strOut = string(stringBytes)
|
||||
return
|
||||
}
|
||||
|
||||
// addTextComponent serializes a TextComponent to JSON and adds it to the buffer
|
||||
func addTextComponent(buffer *bytes.Buffer, component TextComponent) {
|
||||
// Serialize the TextComponent to a JSON string
|
||||
jsonBytes, err := json.Marshal(component)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Convert JSON bytes to a string
|
||||
jsonString := string(jsonBytes)
|
||||
|
||||
// Use addString to addExplosion the serialized TextComponent JSON to the buffer
|
||||
addString(buffer, jsonString)
|
||||
return
|
||||
}
|
||||
|
||||
func receiveTextComponent(buf *bytes.Buffer) (component TextComponent, err error) {
|
||||
jsonString, err := receiveString(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if strings.ContainsAny(jsonString, "") {
|
||||
}
|
||||
jsonDecoderText := json.NewDecoder(strings.NewReader(jsonString))
|
||||
err = jsonDecoderText.Decode(&component)
|
||||
if err != nil {
|
||||
err = nil
|
||||
component.Text = jsonString
|
||||
component.CleanText = cleanMinecraftFormatting(jsonString)
|
||||
}
|
||||
return
|
||||
}
|
Reference in New Issue
Block a user