package main import ( "bytes" "encoding/json" "errors" "github.com/google/uuid" "math/rand" "time" ) func getHandshakePacket(data *bytes.Buffer) (version int32, address string, port uint16, nextState int32, err error) { version, err = receiveVarint(data) address, err = receiveString(data) port = receiveUint16(data) nextState, err = receiveVarint(data) return } func encodeTextComponent(buffer *bytes.Buffer, component TextComponent) (err error) { // First, serialize the component to JSON jsonData, err := json.Marshal(component) if err != nil { return err } addString(buffer, string(jsonData)) return } func getPingPacket(data *bytes.Buffer) (payload int64, err error) { payload = receiveInt64(data) return } func getLoginStart(data *bytes.Buffer) (userName string, playerUUID uuid.UUID, err error) { userName, err = receiveString(data) playerUUID, err = receiveUUID(data) return } // Decodes encryption response data from the buffer. func getEncryptionResponse(data *bytes.Buffer) (sharedSecret []byte, verifyToken []byte, err error) { // Read sharedSecret length using VarInt sharedSecretLen, err := receiveVarint(data) if err != nil { return nil, nil, err } // Read sharedSecret bytes sharedSecret = make([]byte, sharedSecretLen) _, err = data.Read(sharedSecret) if err != nil { return nil, nil, err } // Read verifyToken length using VarInt verifyTokenLen, err := receiveVarint(data) if err != nil { return nil, nil, err } // Read verifyToken bytes verifyToken = make([]byte, verifyTokenLen) _, err = data.Read(verifyToken) if err != nil { return nil, nil, err } return sharedSecret, verifyToken, nil } func getClientInformation(data *bytes.Buffer) (locale string, viewDistance int8, chatMode int32, chatColors bool, skinParts uint8, isRightHanded bool, textFiltering bool, serverListing bool, err error) { var offset int32 // Decode locale string locale, err = receiveString(data) if err != nil { return } // Decode viewDistance viewDistance = int8(data.Bytes()[offset]) offset++ // Decode chatMode chatMode, err = receiveVarint(data) if err != nil { return } // Decode chatColors chatColors, err = receiveBool(data) if err != nil { return } // Decode skinParts skinParts = data.Bytes()[offset] offset++ // Decode isRightHanded mainHand, err := receiveVarint(data) if err != nil { return } isRightHanded = mainHand == 1 // Decode textFiltering textFiltering, err = receiveBool(data) if err != nil { return } // Decode serverListing serverListing, err = receiveBool(data) if err != nil { return } return } func getPluginPacket(inData *bytes.Buffer) (key string, data *bytes.Buffer, err error) { key, err = receiveString(inData) data = inData return } func (player *Player) getResourcePackPacket(data *bytes.Buffer) (err error) { packUUID, err := receiveUUID(data) if err != nil { return } result, err := receiveVarint(data) player.resourcePackResponse[packUUID] = result return } func (player *Player) getDataPacksPacket(data *bytes.Buffer) (err error) { packCount, err := receiveVarint(data) if err != nil { return err } for i := 0; i < int(packCount); i++ { namespace, err := receiveString(data) if err != nil { return err } id, err := receiveString(data) if err != nil { return err } version, err := receiveString(data) if err != nil { return err } player.knownPacks = append(player.knownPacks, DatapackInfo{ Namespace: namespace, ID: id, Version: version, }) } return } func (player *Player) sendPongPacket(payload int64) (err error) { var buf bytes.Buffer addInt64(&buf, payload) err = player.sendPacket(0x01, &buf) if err != nil { return } return } func (player *Player) sendDisconnect(reason string) (err error) { var buf bytes.Buffer addString(&buf, reason) switch player.state { case 2: //login err = player.sendPacket(0x00, &buf) case 3: //configuration err = player.sendPacket(0x02, &buf) case 4: //play err = player.sendPacket(0x1D, &buf) } return } func (player *Player) sendEncryptionRequest() error { var buf bytes.Buffer // Send an empty server ID addVarint(&buf, int32(len(serverID))) // VarInt length of server ID (0) if len(serverID) > 0 { buf.Write(serverID) } // Continue with the rest of the packet (public key, token, etc.) serverPubKeyBytes, err := ExportRSAPublicKey(serverPublicKey) if err != nil { return err } verifyToken, err := generateRandomBytes(4) if err != nil { return err } player.verifyToken = verifyToken addVarint(&buf, int32(len(serverPubKeyBytes))) buf.Write(serverPubKeyBytes) addVarint(&buf, int32(len(player.verifyToken))) buf.Write(player.verifyToken) // Indicate that encryption is enabled addBool(&buf, true) // Send the packet with ID 0x01 (encryption request) err = player.sendPacket(0x01, &buf) if err != nil { return err } return nil } func (player *Player) sendLoginSuccess() error { var buf bytes.Buffer addUUID(&buf, player.uuid) addString(&buf, player.Entity.Name) addVarint(&buf, int32(len(player.profile.Properties))) for _, property := range player.profile.Properties { addString(&buf, property.Name) addString(&buf, property.Value) isSigned := len(property.Signature) > 0 addBool(&buf, isSigned) if isSigned { addString(&buf, property.Signature) } } addBool(&buf, true) return player.sendPacket(0x02, &buf) } func (player *Player) sendKeepAlive() error { player.keepAlivePayload = rand.Int63() player.keepAliveSentTimestamp = time.Now().Unix() var buf bytes.Buffer addInt64(&buf, player.keepAlivePayload) switch player.state { case 3: return player.sendPacket(0x04, &buf) case 4: return player.sendPacket(0x26, &buf) } return errors.New("invalid keep alive state") } func (player *Player) sendKeepAlives() { for { err := player.sendKeepAlive() if err != nil { break } time.Sleep(18 * time.Second) } } func (player *Player) sendPingPacket() error { player.pingID = rand.Uint32() var buf bytes.Buffer addUint32(&buf, player.pingID) player.pingSentTimestamp = time.Now().Unix() switch player.state { case 3: return player.sendPacket(0x05, &buf) case 4: return player.sendPacket(0x36, &buf) } return errors.New("invalid ping state") } func (player *Player) getPongPacket(data *bytes.Buffer) (err error) { pingID, err := receiveUint32(data) if pingID == player.pingID { player.pingReceivedTimestamp = time.Now().Unix() } return } func (player *Player) sendResetChat() error { return player.sendPacket(0x06, &bytes.Buffer{}) } func (player *Player) sendRegistryData() (err error) { for _, registryData := range world.RegistryDataThings { var buf bytes.Buffer addString(&buf, registryData.RegistryID) addVarint(&buf, int32(len(registryData.Entries))) for _, entry := range registryData.Entries { addString(&buf, entry.EntryID) addBool(&buf, entry.HasNBT) if entry.HasNBT { buf.ReadFrom(entry.NBTData) } } err = player.sendPacket(0x07, &buf) if err != nil { return } } return nil } func (player *Player) removeResourcePack(packUUID uuid.UUID) (err error) { var buf bytes.Buffer hasUUID := packUUID != uuid.Nil addBool(&buf, hasUUID) if hasUUID { addUUID(&buf, packUUID) } switch player.state { case 3: return player.sendPacket(0x08, &buf) case 4: return player.sendPacket(0x45, &buf) } return player.sendPacket(0x08, &buf) } func (player *Player) addResourcePack(packUUID uuid.UUID, url string, hash string, forced bool, message string) (err error) { var buf bytes.Buffer addUUID(&buf, packUUID) addString(&buf, url) addString(&buf, hash) addBool(&buf, forced) hasMessage := len(message) > 0 addBool(&buf, hasMessage) if hasMessage { addString(&buf, message) } switch player.state { case 3: return player.sendPacket(0x09, &buf) case 4: return player.sendPacket(0x46, &buf) } return errors.New("invalid resource pack state") } func (player *Player) sendTransfer(host string, port uint16) (err error) { var buf bytes.Buffer addString(&buf, host) addVarint(&buf, int32(port)) switch player.state { case 3: return player.sendPacket(0x0B, &buf) case 4: return player.sendPacket(0x73, &buf) } return nil } func (player *Player) sendFeatureFlags() error { var buf bytes.Buffer addVarint(&buf, int32(len(world.FeatureFlags))) for _, featureFlag := range world.FeatureFlags { addString(&buf, featureFlag) } return player.sendPacket(0x0C, &buf) } func (player *Player) sendUpdateTags() error { var buf bytes.Buffer addVarint(&buf, int32(len(world.UpdateTags))) for _, updateTag := range world.UpdateTags { addString(&buf, updateTag.TagRegistryIdentifier) addVarint(&buf, int32(len(updateTag.Tags))) for _, tag := range updateTag.Tags { addString(&buf, tag.TagName) addVarint(&buf, int32(len(tag.Entries))) for _, entry := range tag.Entries { addVarint(&buf, entry) } } } switch player.state { case 3: return player.sendPacket(0x0D, &buf) case 4: return player.sendPacket(0x78, &buf) } return errors.New("invalid update tags state") } func (player *Player) sendDataPacks() error { var buf bytes.Buffer addVarint(&buf, int32(len(world.DataPacks))) for _, dataPack := range world.DataPacks { addString(&buf, dataPack.Namespace) addString(&buf, dataPack.ID) addString(&buf, dataPack.Version) } return player.sendPacket(0x0E, &buf) } func (player *Player) sendReportDetails() (err error) { var buf bytes.Buffer addVarint(&buf, int32(len(world.ReportDetails))) for key, value := range world.ReportDetails { addString(&buf, key) addString(&buf, value) } switch player.state { case 3: return player.sendPacket(0x0F, &buf) case 4: return player.sendPacket(0x7A, &buf) } return errors.New("invalid report details state") } func (player *Player) sendServerLinks() error { var buf bytes.Buffer addVarint(&buf, int32(len(world.ServerLinks))) for _, serverLink := range world.ServerLinks { if len(serverLink.LabelString) > 0 { addBool(&buf, false) addString(&buf, serverLink.LabelString) } else { addBool(&buf, true) addVarint(&buf, serverLink.LabelInt) } addString(&buf, serverLink.URL) } switch player.state { case 3: return player.sendPacket(0x10, &buf) case 4: return player.sendPacket(0x7B, &buf) } return errors.New("invalid server links state") } func (player *Player) sendPluginMessage(channel string, data *bytes.Buffer) (err error) { var buf bytes.Buffer addString(&buf, channel) _, err = buf.ReadFrom(data) if err != nil { return err } switch player.state { case 3: return player.sendPacket(0x01, &buf) case 4: return player.sendPacket(0x19, &buf) } return errors.New("unknown player state") } func (player *Player) sendConfigurationFinish() error { return player.sendPacket(0x03, &bytes.Buffer{}) } func (player *Player) sendCompression() error { var buf bytes.Buffer addVarint(&buf, CompressionThreshold) return player.sendPacket(0x03, &buf) } func (player *Player) sendStatusResponse(description string) (err error) { if player.state == 1 { var playerSamples []PlayerSample for _, player := range world.Players { if !player.serverListing || player.uuid == uuid.Nil { continue } playerSamples = append(playerSamples, PlayerSample{ Name: player.Entity.Name, ID: player.uuid.String(), }) } status := ServerStatus{ Version: Version{ Name: VERSION, Protocol: ProtocolVersion, }, Players: Players{ Max: maxPlayers, Online: len(world.Players) - 1, Sample: playerSamples, }, Description: Description{description}, Favicon: icon, EnforcesSecureChat: false, } jsonData, err := json.Marshal(status) if err != nil { return err } var outBuffer bytes.Buffer addString(&outBuffer, string(jsonData)) err = player.sendPacket(0x00, &outBuffer) if err != nil { return err } } return nil }