This commit is contained in:
Bruno Rybársky 2024-09-24 07:05:00 +02:00
parent a3fa859804
commit 78b2a2f022
2 changed files with 310 additions and 13 deletions

@ -3,7 +3,11 @@ package main
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"errors"
"github.com/Tnze/go-mc/nbt" "github.com/Tnze/go-mc/nbt"
"github.com/google/uuid"
"math/rand/v2"
"time"
) )
func (player *Player) sendBundleDelimiter() error { func (player *Player) sendBundleDelimiter() error {
@ -356,6 +360,140 @@ func (player *Player) sendPlayStart() error {
} }
//func (player *Player) sendMapItemData(mapId int32) error { func (player *Player) sendMapItemData(mapId int32) error {
// mapEntry := world.m var buf bytes.Buffer
//} mapEntry, found := world.Maps[mapId]
if found {
mapEntry.add(&buf)
}
return player.sendPacket(0x2C, &buf)
}
func (player *Player) sendMerchantOffers(windowID int32, entity *VillagerEntity) error {
var buf bytes.Buffer
entity.addOffers(&buf, windowID)
return player.sendPacket(0x2D, &buf)
}
func (player *Player) sendEntityPositionUpdate(entity *Entity, deltas []int16) error {
if len(deltas) != 3 {
return errors.New("invalid deltas")
}
var buf bytes.Buffer
addVarint(&buf, entity.ID)
addInt16(&buf, deltas[0])
addInt16(&buf, deltas[1])
addInt16(&buf, deltas[2])
addBool(&buf, entity.onGround())
return player.sendPacket(0x2E, &buf)
}
func (player *Player) sendEntityPositionRotationUpdate(entity *Entity, deltas []int16) error {
if len(deltas) != 3 {
return errors.New("invalid deltas")
}
var buf bytes.Buffer
addVarint(&buf, entity.ID)
addInt16(&buf, deltas[0])
addInt16(&buf, deltas[1])
addInt16(&buf, deltas[2])
addByte(&buf, entity.Rotation.Yaw)
addByte(&buf, entity.Rotation.Pitch)
addBool(&buf, entity.onGround())
return player.sendPacket(0x2F, &buf)
}
func (player *Player) sendEntityRotationUpdate(entity *Entity) error {
var buf bytes.Buffer
addVarint(&buf, entity.ID)
addByte(&buf, entity.Rotation.Yaw)
addByte(&buf, entity.Rotation.Pitch)
addBool(&buf, entity.onGround())
return player.sendPacket(0x30, &buf)
}
func (player *Player) sendVehicleMove() error {
if player.Entity.Vehicle != nil {
var buf bytes.Buffer
player.Entity.Vehicle.Position.add(&buf)
addFloat32(&buf, float32(player.Entity.Vehicle.Rotation.Yaw))
addFloat32(&buf, float32(player.Entity.Vehicle.Rotation.Pitch))
return player.sendPacket(0x31, &buf)
}
return errors.New("no vehicle")
}
func (player *Player) sendBookOpen(isOffHand bool) error {
var buf bytes.Buffer
hand := int32(0)
if isOffHand {
hand = 1
}
addVarint(&buf, hand)
return player.sendPacket(0x32, &buf)
}
func (player *Player) sendOpenScreen(windowID int32, window *Window, title TextComponent) error {
var buf bytes.Buffer
addVarint(&buf, windowID)
addVarint(&buf, window.ID)
addTextComponent(&buf, title)
return player.sendPacket(0x33, &buf)
}
func (player *Player) sendOpenSignEditor(blockPosition BlockPosition, front bool) error {
var buf bytes.Buffer
blockPosition.add(&buf)
addBool(&buf, front)
return player.sendPacket(0x34, &buf)
}
//0x35 is ping to client
//0x36 is pong
func (player *Player) sendGhostRecipe(windowID uint8, recipe string) error {
var buf bytes.Buffer
addByte(&buf, windowID)
addString(&buf, recipe)
return player.sendPacket(0x37, &buf)
}
func (player *Player) sendAbilities() error {
var buf bytes.Buffer
addByte(&buf, player.Abilites.export())
addFloat32(&buf, player.FlyingSpeed)
addFloat32(&buf, player.FOVModifier)
return player.sendPacket(0x38, &buf)
}
func (player *Player) sendChatMessage(sender *Player, message string) error {
var buf bytes.Buffer
//TODO IMPLEMENT
addUUID(&buf, sender.uuid)
addVarint(&buf, sender.MessageIndex)
addBool(&buf, false)
addString(&buf, message)
addInt64(&buf, time.Now().Unix())
addInt64(&buf, rand.Int64())
//not implementing secure chat
return player.sendPacket(0x39, &buf)
}
func (player *Player) sendDeath(message TextComponent) error {
var buf bytes.Buffer
addVarint(&buf, player.Entity.ID)
addTextComponent(&buf, message)
return player.sendPacket(0x3C, &buf)
}
func (player *Player) sendRemoveFromTab(playersToRemove []uuid.UUID) error {
if len(playersToRemove) > 0 {
var buf bytes.Buffer
addVarint(&buf, int32(len(playersToRemove)))
for _, playerToRemove := range playersToRemove {
addUUID(&buf, playerToRemove)
}
return player.sendPacket(0x3D, &buf)
}
return errors.New("no playersToRemove")
}

@ -8,6 +8,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"math" "math"
"net" "net"
"time"
) )
type Version struct { type Version struct {
@ -38,6 +39,29 @@ type ServerStatus struct {
EnforcesSecureChat bool `json:"enforcesSecureChat"` EnforcesSecureChat bool `json:"enforcesSecureChat"`
} }
type PlayerAbilites struct {
Invulnerable bool
Flying bool
AllowFlying bool
CreativeMode bool
}
func (abilities *PlayerAbilites) export() (out byte) {
if abilities.Invulnerable {
out |= 0x01
}
if abilities.Flying {
out |= 0x02
}
if abilities.AllowFlying {
out |= 0x04
}
if abilities.CreativeMode {
out |= 0x08
}
return
}
type Player struct { type Player struct {
conn net.Conn conn net.Conn
@ -59,6 +83,14 @@ type Player struct {
DeathDimension *Dimension DeathDimension *Dimension
DeathPosition BlockPosition DeathPosition BlockPosition
Abilites PlayerAbilites
FlyingSpeed float32
FOVModifier float32
MessageIndex int32
CombatStart int64
CombatEnd int64
Position EntityPosition Position EntityPosition
GameMode uint8 GameMode uint8
@ -88,6 +120,21 @@ type Player struct {
uuid uuid.UUID uuid uuid.UUID
} }
func (player *Player) startCombat() {
player.CombatStart = time.Now().Unix()
_ = player.sendPacket(0x3B, &bytes.Buffer{})
}
func (player *Player) endCombat() {
player.CombatEnd = time.Now().Unix()
length := player.CombatEnd - player.CombatStart
if length >= 0 && player.CombatEnd != 0 && player.CombatStart != 0 && player.CombatEnd > player.CombatStart {
var buf bytes.Buffer
addInt64(&buf, length)
_ = player.sendPacket(0x3A, &buf)
}
}
type Dimension struct { type Dimension struct {
ID int32 ID int32
Name string Name string
@ -370,6 +417,21 @@ func (slot *Slot) add(buf *bytes.Buffer) {
} }
} }
func (slot *Slot) addTrade(buf *bytes.Buffer) {
addVarint(buf, slot.Count)
if slot.Count > 0 {
addVarint(buf, slot.ItemID)
addVarint(buf, int32(len(slot.ComponentsToAdd)))
for componentID, component := range slot.ComponentsToAdd {
addVarint(buf, componentID)
component = component //TODO IMPLEMENT ALL THESE STUPID COMPONENTS
}
for _, componentID := range slot.ComponentsToRemove {
addVarint(buf, componentID)
}
}
}
// PalettedContainer represents a palette-based storage of entries. // PalettedContainer represents a palette-based storage of entries.
type PalettedContainer struct { type PalettedContainer struct {
BitsPerEntry uint8 BitsPerEntry uint8
@ -621,16 +683,62 @@ func (velocity *Velocity) add(buf *bytes.Buffer) {
} }
type Entity struct { type Entity struct {
ID int32 World *World
UUID uuid.UUID ID int32
Type int32 UUID uuid.UUID
Position EntityPosition Type int32
Rotation EntityRotation Position EntityPosition
Data int32 Rotation EntityRotation
Velocity Velocity Data int32
Animation uint8 Velocity Velocity
status int8 Animation uint8
PortalCooldown int32 status int8
PortalCooldown int32
Vehicle *Entity
PlayersInformed []*Player
}
// Function to calculate the Euclidean distance between two points in 3D space
func distance(p1, p2 EntityPosition) float64 {
dx := p2.X - p1.X
dy := p2.Y - p1.Y
dz := p2.Z - p1.Z
return math.Sqrt(dx*dx + dy*dy + dz*dz)
}
func getDeltas(p1, p2 EntityPosition) []int16 {
return []int16{
int16((p2.X * 4096) - (p1.X * 4096)),
int16((p2.Y * 4096) - (p1.Y * 4096)),
int16((p2.Z * 4096) - (p1.Z * 4096)),
}
}
func (entity *Entity) move(newPos EntityPosition, withRotation bool) {
diff := distance(entity.Position, newPos)
if diff <= 7 {
if withRotation {
for _, player := range entity.PlayersInformed {
player.sendEntityPositionRotationUpdate(entity, getDeltas(entity.Position, newPos))
}
} else {
for _, player := range entity.PlayersInformed {
player.sendEntityPositionUpdate(entity, getDeltas(entity.Position, newPos))
}
}
} else {
for _, player := range entity.PlayersInformed {
//TODO make entity teleport
player = player
//player.sendEntityTeleport(entity, newPos)
}
}
entity.Position = newPos
}
func (entity *Entity) onGround() bool {
//TODO ADD THIS
return true
} }
func (entity *Entity) add(buf *bytes.Buffer) { func (entity *Entity) add(buf *bytes.Buffer) {
@ -714,3 +822,54 @@ func (Map *Map) add(buf *bytes.Buffer) {
} }
} }
} }
type VillageTrade struct {
In1 Slot
In2 *Slot
Out Slot
Disabled bool
Uses int32
MaxUses int32
XP int32
Modifier int32
Multiplier float32
Demand int32
}
func (villageTrade *VillageTrade) add(buf *bytes.Buffer) {
villageTrade.In1.addTrade(buf)
villageTrade.Out.add(buf)
villageTrade.In2.addTrade(buf)
addBool(buf, villageTrade.Disabled)
addInt32(buf, villageTrade.Uses)
addInt32(buf, villageTrade.MaxUses)
addInt32(buf, villageTrade.XP)
addInt32(buf, villageTrade.Modifier)
addFloat32(buf, villageTrade.Multiplier)
addInt32(buf, villageTrade.Demand)
}
type VillagerEntity struct {
Entity *Entity
Trades []VillageTrade
Level int32
XP int32
Wandering bool
CanRestock bool
}
func (VillagerEntity *VillagerEntity) addOffers(buf *bytes.Buffer, windowID int32) {
addVarint(buf, windowID)
addVarint(buf, int32(len(VillagerEntity.Trades)))
for _, trade := range VillagerEntity.Trades {
trade.add(buf)
}
addVarint(buf, VillagerEntity.Level)
addVarint(buf, VillagerEntity.XP)
addBool(buf, !VillagerEntity.Wandering)
addBool(buf, VillagerEntity.CanRestock)
}
type Window struct {
ID int32
}