Initial commit

This commit is contained in:
SantianDev
2026-03-03 15:05:55 +03:00
commit a9c89f027a
37 changed files with 3256 additions and 0 deletions

81
net/info/info.go Normal file
View File

@@ -0,0 +1,81 @@
package info
const (
LatestProtocol = 113
MinProtocol = 105
LatestGameVersion = "v1.1.7"
LatestGameVersionNetwork = "1.1.7"
)
var SupportedProtocols = map[int32]string{
105: "1.1.0",
107: "1.1.3",
110: "1.1.5",
111: "1.1.6",
113: "1.1.7",
}
func IsSupported(protocol int32) bool {
_, ok := SupportedProtocols[protocol]
return ok
}
const (
IDLogin = 0x01
IDPlayStatus = 0x02
IDServerHandshake = 0x03
IDClientHandshake = 0x04
IDDisconnect = 0x05
IDResourcePackInfo = 0x06
IDResourcePackStack = 0x07
IDResourcePackClientResponse = 0x08
IDText = 0x09
IDSetTime = 0x0a
IDStartGame = 0x0b
IDAddPlayer = 0x0c
IDAddEntity = 0x0d
IDRemoveEntity = 0x0e
IDAddItemEntity = 0x0f
IDTakeItemEntity = 0x11
IDMoveEntity = 0x12
IDMovePlayer = 0x13
IDPlayerAction = 0x24
IDSetEntityData = 0x27
IDSetEntityMotion = 0x28
IDUpdateAttributes = 0x1d
IDInventoryTransaction = 0x1e
IDMobEquipment = 0x1f
IDMobArmorEquipment = 0x20
IDInteract = 0x21
IDBlockPickRequest = 0x22
IDEntityPickRequest = 0x23
IDAnimate = 0x2c
IDRespawn = 0x2d
IDContainerOpen = 0x2e
IDContainerClose = 0x2f
IDPlayerHotbar = 0x30
IDInventoryContent = 0x31
IDInventorySlot = 0x32
IDContainerSetData = 0x33
IDCraftingData = 0x34
IDCraftingEvent = 0x35
IDAdventureSettings = 0x37
IDBlockEntityData = 0x38
IDFullChunkData = 0x3a
IDSetGameMode = 0x3b
IDSetCommandsEnabled = 0x3b
IDSetDifficulty = 0x3c
IDChangeDimension = 0x3d
IDSetPlayerGameType = 0x3e
IDPlayerList = 0x3f
IDRequestChunkRadius = 0x45
IDChunkRadiusUpdated = 0x46
IDAvailableCommands = 0x4c
IDCommandRequest = 0x4d
IDResourcePackDataInfo = 0x52
IDResourcePackChunkData = 0x53
IDResourcePackChunkRequest = 0x54
IDTransfer = 0x55
IDSetTitle = 0x58
IDPlayerSkin = 0x5d
)

View File

@@ -0,0 +1,39 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type AdventureSettingsPacket struct {
*packets.Packet
Flags uint32
CommandPermission uint32
Flags2 uint32
PlayerPermission uint32
CustomFlags uint32
EntityID int64
}
func NewAdventureSettingsPacket() *AdventureSettingsPacket {
return &AdventureSettingsPacket{Packet: packets.NewPacket(info.IDAdventureSettings)}
}
func (pk *AdventureSettingsPacket) Encode() {
pk.PutUVarInt(pk.Flags)
pk.PutUVarInt(pk.CommandPermission)
pk.PutUVarInt(pk.Flags2)
pk.PutUVarInt(pk.PlayerPermission)
pk.PutUVarInt(pk.CustomFlags)
pk.PutLLong(pk.EntityID)
}
func (pk *AdventureSettingsPacket) Decode() {
pk.Flags = pk.GetUVarInt()
pk.CommandPermission = pk.GetUVarInt()
pk.Flags2 = pk.GetUVarInt()
pk.PlayerPermission = pk.GetUVarInt()
pk.CustomFlags = pk.GetUVarInt()
pk.EntityID = pk.GetLLong()
}

View File

@@ -0,0 +1,41 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type RequestChunkRadiusPacket struct {
*packets.Packet
Radius int32
}
func NewRequestChunkRadiusPacket() *RequestChunkRadiusPacket {
return &RequestChunkRadiusPacket{Packet: packets.NewPacket(info.IDRequestChunkRadius)}
}
func (pk *RequestChunkRadiusPacket) Encode() {}
func (pk *RequestChunkRadiusPacket) Decode() {
pk.Radius = pk.GetVarInt()
}
type ChunkRadiusUpdatedPacket struct {
*packets.Packet
Radius int32
}
func NewChunkRadiusUpdatedPacket(radius int32) *ChunkRadiusUpdatedPacket {
return &ChunkRadiusUpdatedPacket{
Packet: packets.NewPacket(info.IDChunkRadiusUpdated),
Radius: radius,
}
}
func (pk *ChunkRadiusUpdatedPacket) Encode() {
pk.PutVarInt(pk.Radius)
}
func (pk *ChunkRadiusUpdatedPacket) Decode() {}

View File

@@ -0,0 +1,35 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type DisconnectPacket struct {
*packets.Packet
HideScreen bool
Message string
}
func NewDisconnectPacket(message string, hideScreen bool) *DisconnectPacket {
return &DisconnectPacket{
Packet: packets.NewPacket(info.IDDisconnect),
HideScreen: hideScreen,
Message: message,
}
}
func (pk *DisconnectPacket) Encode() {
pk.PutBool(pk.HideScreen)
if !pk.HideScreen {
pk.PutString(pk.Message)
}
}
func (pk *DisconnectPacket) Decode() {
pk.HideScreen = pk.GetBool()
if !pk.HideScreen {
pk.Message = pk.GetString()
}
}

View File

@@ -0,0 +1,97 @@
package bedrock
import (
"bytes"
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type FullChunkDataPacket struct {
*packets.Packet
ChunkX int32
ChunkZ int32
Data []byte
}
func NewFullChunkDataPacket(cx, cz int32, data []byte) *FullChunkDataPacket {
return &FullChunkDataPacket{
Packet: packets.NewPacket(info.IDFullChunkData),
ChunkX: cx,
ChunkZ: cz,
Data: data,
}
}
func BuildFlatChunk() []byte {
buf := &bytes.Buffer{}
const numSubChunks = 8
buf.WriteByte(numSubChunks)
for sc := 0; sc < numSubChunks; sc++ {
buf.WriteByte(0)
blocks := make([]byte, 4096)
baseY := sc * 16
for x := 0; x < 16; x++ {
for z := 0; z < 16; z++ {
for y := 0; y < 16; y++ {
absY := baseY + y
idx := x*256 + z*16 + y
if absY == 0 {
blocks[idx] = 7
} else if absY < 62 {
blocks[idx] = 1
} else if absY == 62 {
blocks[idx] = 3
} else if absY == 63 {
blocks[idx] = 2
}
}
}
}
buf.Write(blocks)
buf.Write(make([]byte, 2048))
skylight := make([]byte, 2048)
for i := range skylight {
if baseY >= 64 {
skylight[i] = 0xFF
} else {
skylight[i] = 0x00
}
}
buf.Write(skylight)
buf.Write(make([]byte, 2048))
}
heightmap := make([]byte, 256)
for i := range heightmap {
heightmap[i] = 64
}
buf.Write(heightmap)
biomes := make([]byte, 256)
for i := range biomes {
biomes[i] = 1
}
buf.Write(biomes)
buf.WriteByte(0)
buf.WriteByte(0)
return buf.Bytes()
}
func (pk *FullChunkDataPacket) Encode() {
pk.PutVarInt(pk.ChunkX)
pk.PutVarInt(pk.ChunkZ)
pk.PutUVarInt(uint32(len(pk.Data)))
pk.PutBytes(pk.Data)
}
func (pk *FullChunkDataPacket) Decode() {}

View File

@@ -0,0 +1,165 @@
package bedrock
import (
"encoding/base64"
"encoding/binary"
"encoding/json"
"strings"
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
"github.com/google/uuid"
)
type LoginPacket struct {
*packets.Packet
Protocol int32
Username string
ClientUUID uuid.UUID
ClientXUID string
ClientID int64
ServerAddr string
Language string
SkinID string
SkinData []byte
CapeData []byte
GeometryName string
GeometryData string
}
func NewLoginPacket() *LoginPacket {
return &LoginPacket{
Packet: packets.NewPacket(info.IDLogin),
ClientUUID: uuid.New(),
}
}
func (pk *LoginPacket) Encode() {}
func (pk *LoginPacket) Decode() {
pk.Protocol = pk.GetInt()
pk.GetByte()
totalLen := int(pk.GetUVarInt())
if totalLen <= 0 || totalLen > pk.Remaining() {
pk.Username = "Player"
return
}
blob := pk.GetBytes(totalLen)
if len(blob) < 4 {
pk.Username = "Player"
return
}
chainLen := int(binary.LittleEndian.Uint32(blob[:4]))
if chainLen <= 0 || 4+chainLen > len(blob) {
pk.Username = "Player"
return
}
var chainData struct {
Chain []string `json:"chain"`
}
if err := json.Unmarshal(blob[4:4+chainLen], &chainData); err == nil {
for _, raw := range chainData.Chain {
pk.parseChain(raw)
}
}
offset := 4 + chainLen
if offset+4 > len(blob) {
if pk.Username == "" {
pk.Username = "Player"
}
return
}
clientLen := int(binary.LittleEndian.Uint32(blob[offset : offset+4]))
offset += 4
if clientLen > 0 && offset+clientLen <= len(blob) {
pk.parseClientData(string(blob[offset : offset+clientLen]))
}
if pk.Username == "" {
pk.Username = "Player"
}
}
func decodeJWTPayload(s string) ([]byte, error) {
b, err := base64.RawURLEncoding.DecodeString(s)
if err != nil {
switch len(s) % 4 {
case 2:
s += "=="
case 3:
s += "="
}
b, err = base64.URLEncoding.DecodeString(s)
}
return b, err
}
func (pk *LoginPacket) parseChain(raw string) {
parts := strings.Split(raw, ".")
if len(parts) < 2 {
return
}
payload, err := decodeJWTPayload(parts[1])
if err != nil {
return
}
var data struct {
ExtraData map[string]interface{} `json:"extraData"`
}
if err := json.Unmarshal(payload, &data); err != nil || data.ExtraData == nil {
return
}
if v, ok := data.ExtraData["displayName"]; ok {
if name, _ := v.(string); name != "" {
pk.Username = name
}
}
if v, ok := data.ExtraData["identity"]; ok {
if idStr, _ := v.(string); idStr != "" {
if u, err := uuid.Parse(idStr); err == nil {
pk.ClientUUID = u
}
}
}
if v, ok := data.ExtraData["XUID"]; ok {
pk.ClientXUID, _ = v.(string)
}
}
func (pk *LoginPacket) parseClientData(raw string) {
parts := strings.Split(raw, ".")
if len(parts) < 2 {
return
}
payload, err := decodeJWTPayload(parts[1])
if err != nil {
return
}
var data struct {
ClientRandomID int64 `json:"ClientRandomId"`
ServerAddress string `json:"ServerAddress"`
LanguageCode string `json:"LanguageCode"`
SkinID string `json:"SkinId"`
SkinData string `json:"SkinData"`
CapeData string `json:"CapeData"`
SkinGeomName string `json:"SkinGeometryName"`
SkinGeomData string `json:"SkinGeometry"`
}
if err := json.Unmarshal(payload, &data); err != nil {
return
}
pk.ClientID = data.ClientRandomID
pk.ServerAddr = data.ServerAddress
pk.Language = data.LanguageCode
if pk.Language == "" {
pk.Language = "en_US"
}
pk.SkinID = data.SkinID
pk.GeometryName = data.SkinGeomName
pk.SkinData, _ = base64.RawStdEncoding.DecodeString(data.SkinData)
pk.CapeData, _ = base64.RawStdEncoding.DecodeString(data.CapeData)
geomBytes, _ := base64.RawStdEncoding.DecodeString(data.SkinGeomData)
pk.GeometryData = string(geomBytes)
for len(pk.SkinData) < 8192 {
pk.SkinData = append(pk.SkinData, 0x00)
}
}

View File

@@ -0,0 +1,47 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type MovePlayerPacket struct {
*packets.Packet
RuntimeID uint64
X, Y, Z float32
Pitch, Yaw, HeadYaw float32
Mode byte
OnGround bool
RidingID uint64
}
func NewMovePlayerPacket() *MovePlayerPacket {
return &MovePlayerPacket{Packet: packets.NewPacket(info.IDMovePlayer)}
}
func (pk *MovePlayerPacket) Encode() {
pk.PutUVarLong(pk.RuntimeID)
pk.PutLFloat(pk.X)
pk.PutLFloat(pk.Y)
pk.PutLFloat(pk.Z)
pk.PutLFloat(pk.Pitch)
pk.PutLFloat(pk.Yaw)
pk.PutLFloat(pk.HeadYaw)
pk.PutByte(pk.Mode)
pk.PutBool(pk.OnGround)
pk.PutUVarLong(pk.RidingID)
}
func (pk *MovePlayerPacket) Decode() {
pk.RuntimeID = pk.GetUVarLong()
pk.X = pk.GetLFloat()
pk.Y = pk.GetLFloat()
pk.Z = pk.GetLFloat()
pk.Pitch = pk.GetLFloat()
pk.Yaw = pk.GetLFloat()
pk.HeadYaw = pk.GetLFloat()
pk.Mode = pk.GetByte()
pk.OnGround = pk.GetBool()
pk.RidingID = pk.GetUVarLong()
}

View File

@@ -0,0 +1,38 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
const (
PlayStatusLoginSuccess int32 = 0
PlayStatusLoginFailedClient int32 = 1
PlayStatusLoginFailedServer int32 = 2
PlayStatusPlayerSpawn int32 = 3
PlayStatusLoginFailedInvalidTenant int32 = 4
PlayStatusLoginFailedVanillaEdu int32 = 5
PlayStatusLoginFailedEduVanilla int32 = 6
)
type PlayStatusPacket struct {
*packets.Packet
Status int32
}
func NewPlayStatusPacket(status int32) *PlayStatusPacket {
pk := &PlayStatusPacket{
Packet: packets.NewPacket(info.IDPlayStatus),
Status: status,
}
return pk
}
func (pk *PlayStatusPacket) Encode() {
pk.PutInt(pk.Status)
}
func (pk *PlayStatusPacket) Decode() {
pk.Status = pk.GetInt()
}

View File

@@ -0,0 +1,37 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
const (
ResourcePackResponseRefused = 1
ResourcePackResponseSendPacks = 2
ResourcePackResponseAllPacksSent = 3
ResourcePackResponseCompleted = 4
)
type ResourcePackClientResponsePacket struct {
*packets.Packet
Status byte
PackIDs []string
}
func NewResourcePackClientResponsePacket() *ResourcePackClientResponsePacket {
return &ResourcePackClientResponsePacket{
Packet: packets.NewPacket(info.IDResourcePackClientResponse),
}
}
func (pk *ResourcePackClientResponsePacket) Encode() {}
func (pk *ResourcePackClientResponsePacket) Decode() {
pk.Status = pk.GetByte()
count := pk.GetLShort()
pk.PackIDs = make([]string, count)
for i := uint16(0); i < count; i++ {
pk.PackIDs[i] = pk.GetString()
}
}

View File

@@ -0,0 +1,27 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type ResourcePackInfoPacket struct {
*packets.Packet
MustAccept bool
}
func NewResourcePackInfoPacket(mustAccept bool) *ResourcePackInfoPacket {
return &ResourcePackInfoPacket{
Packet: packets.NewPacket(info.IDResourcePackInfo),
MustAccept: mustAccept,
}
}
func (pk *ResourcePackInfoPacket) Encode() {
pk.PutBool(pk.MustAccept)
pk.PutLShort(0)
pk.PutLShort(0)
}
func (pk *ResourcePackInfoPacket) Decode() {}

View File

@@ -0,0 +1,27 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type ResourcePackStackPacket struct {
*packets.Packet
MustAccept bool
}
func NewResourcePackStackPacket(mustAccept bool) *ResourcePackStackPacket {
return &ResourcePackStackPacket{
Packet: packets.NewPacket(info.IDResourcePackStack),
MustAccept: mustAccept,
}
}
func (pk *ResourcePackStackPacket) Encode() {
pk.PutBool(pk.MustAccept)
pk.PutLShort(0)
pk.PutLShort(0)
}
func (pk *ResourcePackStackPacket) Decode() {}

View File

@@ -0,0 +1,24 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type SetGameModePacket struct {
*packets.Packet
GameMode int32
}
func NewSetGameModePacket(gm int32) *SetGameModePacket {
return &SetGameModePacket{
Packet: packets.NewPacket(info.IDSetGameMode),
GameMode: gm,
}
}
func (pk *SetGameModePacket) Encode() {
pk.PutVarInt(pk.GameMode)
}
func (pk *SetGameModePacket) Decode() {}

View File

@@ -0,0 +1,25 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type SetTimePacket struct {
*packets.Packet
Time int32
}
func NewSetTimePacket(time int32) *SetTimePacket {
return &SetTimePacket{
Packet: packets.NewPacket(info.IDSetTime),
Time: time,
}
}
func (pk *SetTimePacket) Encode() {
pk.PutVarInt(pk.Time)
}
func (pk *SetTimePacket) Decode() {}

View File

@@ -0,0 +1,92 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type StartGamePacket struct {
*packets.Packet
EntityUniqueID int64
EntityRuntimeID uint64
PlayerGameMode int32
SpawnX float32
SpawnY float32
SpawnZ float32
Yaw float32
Pitch float32
Seed int32
Dimension int32
Generator int32
GameMode int32
Difficulty int32
SpawnBX int32
SpawnBY int32
SpawnBZ int32
AchievementsDisabled bool
Time int32
EduMode bool
RainLevel float32
LightningLevel float32
IsMultiplayer bool
BroadcastToLAN bool
CommandsEnabled bool
ForceTexturePacks bool
LevelName string
IsTrial bool
CurrentTick int64
EnchantmentSeed int32
}
func NewStartGamePacket() *StartGamePacket {
return &StartGamePacket{
Packet: packets.NewPacket(info.IDStartGame),
}
}
func (pk *StartGamePacket) Encode() {
pk.PutVarLong(pk.EntityUniqueID)
pk.PutUVarLong(pk.EntityRuntimeID)
pk.PutVarInt(pk.PlayerGameMode)
pk.PutLFloat(pk.SpawnX)
pk.PutLFloat(pk.SpawnY)
pk.PutLFloat(pk.SpawnZ)
pk.PutLFloat(pk.Yaw)
pk.PutLFloat(pk.Pitch)
pk.PutVarInt(pk.Seed)
pk.PutVarInt(pk.Dimension)
pk.PutVarInt(pk.Generator)
pk.PutVarInt(pk.GameMode)
pk.PutVarInt(pk.Difficulty)
pk.PutVarInt(pk.SpawnBX)
pk.PutUVarInt(uint32(pk.SpawnBY))
pk.PutVarInt(pk.SpawnBZ)
pk.PutBool(pk.AchievementsDisabled)
pk.PutVarInt(pk.Time)
pk.PutBool(pk.EduMode)
pk.PutLFloat(pk.RainLevel)
pk.PutLFloat(pk.LightningLevel)
pk.PutBool(pk.IsMultiplayer)
pk.PutBool(pk.BroadcastToLAN)
pk.PutBool(false)
pk.PutBool(pk.CommandsEnabled)
pk.PutBool(pk.ForceTexturePacks)
pk.PutUVarInt(0)
pk.PutBool(false)
pk.PutBool(false)
pk.PutBool(false)
pk.PutVarInt(1)
pk.PutLInt(4)
pk.PutBool(false)
pk.PutBool(false)
pk.PutBool(false)
pk.PutBool(false)
pk.PutBool(false)
pk.PutString(pk.LevelName)
pk.PutString("")
pk.PutBool(pk.IsTrial)
pk.PutLLong(pk.CurrentTick)
pk.PutVarInt(pk.EnchantmentSeed)
}
func (pk *StartGamePacket) Decode() {}

View File

@@ -0,0 +1,61 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
const (
TextTypeRaw = 0
TextTypeChat = 1
TextTypeTranslation = 2
TextTypePopup = 3
TextTypeTip = 4
TextTypeSystem = 5
TextTypeWhisper = 6
TextTypeAnnouncement = 7
)
type TextPacket struct {
*packets.Packet
TextType byte
Source string
Message string
XUID string
}
func NewTextPacket(textType byte, source, message string) *TextPacket {
return &TextPacket{
Packet: packets.NewPacket(info.IDText),
TextType: textType,
Source: source,
Message: message,
}
}
func (pk *TextPacket) Encode() {
pk.PutByte(pk.TextType)
switch pk.TextType {
case TextTypeChat, TextTypeWhisper, TextTypeAnnouncement:
pk.PutString(pk.Source)
pk.PutString(pk.Message)
case TextTypeRaw, TextTypeTip, TextTypeSystem, TextTypePopup:
pk.PutString(pk.Message)
case TextTypeTranslation:
pk.PutString(pk.Message)
pk.PutVarInt(0)
}
pk.PutString(pk.XUID)
}
func (pk *TextPacket) Decode() {
pk.TextType = pk.GetByte()
switch pk.TextType {
case TextTypeChat, TextTypeWhisper, TextTypeAnnouncement:
pk.Source = pk.GetString()
pk.Message = pk.GetString()
default:
pk.Message = pk.GetString()
}
}

View File

@@ -0,0 +1,53 @@
package bedrock
import (
"github.com/cubexteam/Frodding/net/info"
"github.com/cubexteam/Frodding/net/packets"
)
type Attribute struct {
Min float32
Max float32
Current float32
Default float32
Name string
}
type UpdateAttributesPacket struct {
*packets.Packet
RuntimeID uint64
Attributes []Attribute
}
func NewUpdateAttributesPacket(runtimeID uint64) *UpdateAttributesPacket {
return &UpdateAttributesPacket{
Packet: packets.NewPacket(info.IDUpdateAttributes),
RuntimeID: runtimeID,
}
}
func (pk *UpdateAttributesPacket) Encode() {
pk.PutUVarLong(pk.RuntimeID)
pk.PutUVarInt(uint32(len(pk.Attributes)))
for _, attr := range pk.Attributes {
pk.PutLFloat(attr.Min)
pk.PutLFloat(attr.Max)
pk.PutLFloat(attr.Current)
pk.PutLFloat(attr.Default)
pk.PutString(attr.Name)
}
}
func (pk *UpdateAttributesPacket) Decode() {}
func DefaultAttributes() []Attribute {
return []Attribute{
{Min: 0, Max: 20, Current: 20, Default: 20, Name: "minecraft:health"},
{Min: 0, Max: 20, Current: 20, Default: 20, Name: "minecraft:player.hunger"},
{Min: 0, Max: 5, Current: 5, Default: 5, Name: "minecraft:player.saturation"},
{Min: 0, Max: 5, Current: 0, Default: 0, Name: "minecraft:player.exhaustion"},
{Min: 0, Max: 24791, Current: 0, Default: 0, Name: "minecraft:player.level"},
{Min: 0, Max: 1, Current: 0, Default: 0, Name: "minecraft:player.experience"},
{Min: 0, Max: 10, Current: 0.1, Default: 0.1, Name: "minecraft:movement"},
}
}

195
net/packets/packet.go Normal file
View File

@@ -0,0 +1,195 @@
package packets
import (
"bytes"
"encoding/binary"
"math"
)
type IPacket interface {
GetID() byte
Encode()
Decode()
GetBuffer() []byte
SetBuffer([]byte)
}
type Packet struct {
id byte
buf *bytes.Buffer
raw []byte
pos int
}
func NewPacket(id byte) *Packet {
return &Packet{id: id, buf: &bytes.Buffer{}}
}
func (p *Packet) GetID() byte { return p.id }
func (p *Packet) GetBuffer() []byte { return p.buf.Bytes() }
func (p *Packet) SetBuffer(data []byte) { p.raw = data; p.pos = 0 }
func (p *Packet) PutByte(v byte) { p.buf.WriteByte(v) }
func (p *Packet) PutBytes(v []byte) { p.buf.Write(v) }
func (p *Packet) PutBool(v bool) {
if v {
p.buf.WriteByte(0x01)
} else {
p.buf.WriteByte(0x00)
}
}
func (p *Packet) PutShort(v int16) {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(v))
p.buf.Write(b)
}
func (p *Packet) PutLShort(v uint16) {
b := make([]byte, 2)
binary.LittleEndian.PutUint16(b, v)
p.buf.Write(b)
}
func (p *Packet) PutInt(v int32) {
b := make([]byte, 4)
binary.BigEndian.PutUint32(b, uint32(v))
p.buf.Write(b)
}
func (p *Packet) PutLInt(v int32) {
b := make([]byte, 4)
binary.LittleEndian.PutUint32(b, uint32(v))
p.buf.Write(b)
}
func (p *Packet) PutLLong(v int64) {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(v))
p.buf.Write(b)
}
func (p *Packet) PutLFloat(v float32) {
b := make([]byte, 4)
binary.LittleEndian.PutUint32(b, math.Float32bits(v))
p.buf.Write(b)
}
func (p *Packet) PutVarInt(v int32) {
p.PutUVarInt((uint32(v) << 1) ^ uint32(v>>31))
}
func (p *Packet) PutUVarInt(v uint32) {
for v >= 0x80 {
p.buf.WriteByte(byte(v&0x7f) | 0x80)
v >>= 7
}
p.buf.WriteByte(byte(v))
}
func (p *Packet) PutVarLong(v int64) {
p.PutUVarLong((uint64(v) << 1) ^ uint64(v>>63))
}
func (p *Packet) PutUVarLong(v uint64) {
for v >= 0x80 {
p.buf.WriteByte(byte(v&0x7f) | 0x80)
v >>= 7
}
p.buf.WriteByte(byte(v))
}
func (p *Packet) PutString(v string) {
p.PutUVarInt(uint32(len(v)))
p.buf.WriteString(v)
}
func (p *Packet) checkRead(n int) bool { return p.pos+n <= len(p.raw) }
func (p *Packet) GetByte() byte {
if !p.checkRead(1) { return 0 }
b := p.raw[p.pos]; p.pos++; return b
}
func (p *Packet) GetBytes(n int) []byte {
if !p.checkRead(n) { return nil }
b := p.raw[p.pos : p.pos+n]; p.pos += n; return b
}
func (p *Packet) GetBool() bool { return p.GetByte() != 0x00 }
func (p *Packet) GetShort() int16 {
b := p.GetBytes(2)
if b == nil { return 0 }
return int16(binary.BigEndian.Uint16(b))
}
func (p *Packet) GetLShort() uint16 {
b := p.GetBytes(2)
if b == nil { return 0 }
return binary.LittleEndian.Uint16(b)
}
func (p *Packet) GetInt() int32 {
b := p.GetBytes(4)
if b == nil { return 0 }
return int32(binary.BigEndian.Uint32(b))
}
func (p *Packet) GetLInt() int32 {
b := p.GetBytes(4)
if b == nil { return 0 }
return int32(binary.LittleEndian.Uint32(b))
}
func (p *Packet) GetLLong() int64 {
b := p.GetBytes(8)
if b == nil { return 0 }
return int64(binary.LittleEndian.Uint64(b))
}
func (p *Packet) GetLFloat() float32 {
b := p.GetBytes(4)
if b == nil { return 0 }
return math.Float32frombits(binary.LittleEndian.Uint32(b))
}
func (p *Packet) GetVarInt() int32 {
uv := p.GetUVarInt()
return int32((uv >> 1) ^ -(uv & 1))
}
func (p *Packet) GetUVarInt() uint32 {
var v uint32
for i := uint(0); i < 35; i += 7 {
b := p.GetByte()
v |= uint32(b&0x7f) << i
if b&0x80 == 0 { break }
}
return v
}
func (p *Packet) GetVarLong() int64 {
uv := p.GetUVarLong()
return int64((uv >> 1) ^ -(uv & 1))
}
func (p *Packet) GetUVarLong() uint64 {
var v uint64
for i := uint(0); i < 70; i += 7 {
b := p.GetByte()
v |= uint64(b&0x7f) << i
if b&0x80 == 0 { break }
}
return v
}
func (p *Packet) GetString() string {
return string(p.GetBytes(int(p.GetUVarInt())))
}
func (p *Packet) Remaining() int {
if p.pos >= len(p.raw) { return 0 }
return len(p.raw) - p.pos
}