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

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"},
}
}