Skip to content

Commit

Permalink
server/session.go: Handle new server bound packets
Browse files Browse the repository at this point in the history
  • Loading branch information
TwistedAsylumMC committed Aug 15, 2024
1 parent b98787c commit 408171b
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 1 deletion.
29 changes: 29 additions & 0 deletions server/player/diagnostics/diagnostics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package diagnostics

// Diagnostics represents the latest diagnostics data of the client.
type Diagnostics struct {
// AverageFramesPerSecond is the average amount of frames per second that the client has been
// running at.
AverageFramesPerSecond float64
// AverageServerSimTickTime is the average time that the server spends simulating a single tick
// in milliseconds.
AverageServerSimTickTime float64
// AverageClientSimTickTime is the average time that the client spends simulating a single tick
// in milliseconds.
AverageClientSimTickTime float64
// AverageBeginFrameTime is the average time that the client spends beginning a frame in
// milliseconds.
AverageBeginFrameTime float64
// AverageInputTime is the average time that the client spends processing input in milliseconds.
AverageInputTime float64
// AverageRenderTime is the average time that the client spends rendering in milliseconds.
AverageRenderTime float64
// AverageEndFrameTime is the average time that the client spends ending a frame in milliseconds.
AverageEndFrameTime float64
// AverageRemainderTimePercent is the average percentage of time that the client spends on
// tasks that are not accounted for.
AverageRemainderTimePercent float64
// AverageUnaccountedTimePercent is the average percentage of time that the client spends on
// unaccounted tasks.
AverageUnaccountedTimePercent float64
}
6 changes: 6 additions & 0 deletions server/player/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/df-mc/dragonfly/server/cmd"
"github.com/df-mc/dragonfly/server/event"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/player/diagnostics"
"github.com/df-mc/dragonfly/server/player/skin"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl64"
Expand Down Expand Up @@ -135,6 +136,10 @@ type Handler interface {
// HandleQuit handles the closing of a player. It is always called when the player is disconnected,
// regardless of the reason.
HandleQuit()
// HandleDiagnostics handles the latest diagnostics data that the player has sent to the server. This is
// not sent by every client however, only those with the "Creator > Enable Client Diagnostics" setting
// enabled.
HandleDiagnostics(d diagnostics.Diagnostics)
}

// NopHandler implements the Handler interface but does not execute any code when an event is called. The
Expand Down Expand Up @@ -178,3 +183,4 @@ func (NopHandler) HandleFoodLoss(*event.Context, int, *int)
func (NopHandler) HandleDeath(world.DamageSource, *bool) {}
func (NopHandler) HandleRespawn(*mgl64.Vec3, **world.World) {}
func (NopHandler) HandleQuit() {}
func (NopHandler) HandleDiagnostics(d diagnostics.Diagnostics) {}
11 changes: 11 additions & 0 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package player

import (
"fmt"
"github.com/df-mc/dragonfly/server/player/diagnostics"
"math"
"math/rand"
"net"
Expand Down Expand Up @@ -2048,6 +2049,11 @@ func (p *Player) Rotation() cube.Rotation {
return cube.Rotation{p.yaw.Load(), p.pitch.Load()}
}

// ChangingDimension returns whether the player is currently changing dimension or not.
func (p *Player) ChangingDimension() bool {
return p.session().ChangingDimension()
}

// Collect makes the player collect the item stack passed, adding it to the inventory. The amount of items that could
// be added is returned.
func (p *Player) Collect(s item.Stack) int {
Expand Down Expand Up @@ -2715,6 +2721,11 @@ func (p *Player) PunchAir() {
p.World().PlaySound(p.Position(), sound.Attack{})
}

// UpdateDiagnostics updates the diagnostics of the player.
func (p *Player) UpdateDiagnostics(d diagnostics.Diagnostics) {
p.Handler().HandleDiagnostics(d)
}

// damageItem damages the item stack passed with the damage passed and returns the new stack. If the item
// broke, a breaking sound is played.
// If the player is not survival, the original stack is returned.
Expand Down
3 changes: 3 additions & 0 deletions server/session/controllable.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/item/inventory"
"github.com/df-mc/dragonfly/server/player/chat"
"github.com/df-mc/dragonfly/server/player/diagnostics"
"github.com/df-mc/dragonfly/server/player/form"
"github.com/df-mc/dragonfly/server/player/skin"
"github.com/df-mc/dragonfly/server/world"
Expand Down Expand Up @@ -99,4 +100,6 @@ type Controllable interface {
// entity looks in the world.
Skin() skin.Skin
SetSkin(skin.Skin)

UpdateDiagnostics(diagnostics.Diagnostics)
}
29 changes: 29 additions & 0 deletions server/session/handler_server_bound_diagnostics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package session

import (
"github.com/df-mc/atomic"
"github.com/df-mc/dragonfly/server/player/diagnostics"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)

// ServerBoundDiagnosticsHandler handles diagnostic updates from the client.
type ServerBoundDiagnosticsHandler struct {
currentID atomic.Uint32
}

// Handle ...
func (h *ServerBoundDiagnosticsHandler) Handle(p packet.Packet, s *Session) error {
pk := p.(*packet.ServerBoundDiagnostics)
s.c.UpdateDiagnostics(diagnostics.Diagnostics{
AverageFramesPerSecond: float64(pk.AverageFramesPerSecond),
AverageServerSimTickTime: float64(pk.AverageServerSimTickTime),
AverageClientSimTickTime: float64(pk.AverageClientSimTickTime),
AverageBeginFrameTime: float64(pk.AverageBeginFrameTime),
AverageInputTime: float64(pk.AverageInputTime),
AverageRenderTime: float64(pk.AverageRenderTime),
AverageEndFrameTime: float64(pk.AverageEndFrameTime),
AverageRemainderTimePercent: float64(pk.AverageRemainderTimePercent),
AverageUnaccountedTimePercent: float64(pk.AverageUnaccountedTimePercent),
})
return nil
}
32 changes: 32 additions & 0 deletions server/session/handler_server_bound_loading_screen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package session

import (
"fmt"
"github.com/df-mc/atomic"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)

// ServerBoundLoadingScreenHandler handles loading screen updates from the clients. It is used to ensure that
// the server knows when the client is loading a screen, and when it is done loading it.
type ServerBoundLoadingScreenHandler struct {
currentID atomic.Uint32
expectedID atomic.Uint32
}

// Handle ...
func (h *ServerBoundLoadingScreenHandler) Handle(p packet.Packet, s *Session) error {
pk := p.(*packet.ServerBoundLoadingScreen)
if h.expectedID.Load() == 0 {
return fmt.Errorf("unexpected loading screen packet")
}
v, ok := pk.LoadingScreenID.Value()
if !ok {
return fmt.Errorf("expected loading screen ID %d, got nothing", h.expectedID.Load())
} else if v != h.expectedID.Load() {
return fmt.Errorf("expected loading screen ID %d, got %d", h.expectedID.Load(), v)
} else if pk.Type == packet.LoadingScreenTypeEnd {
s.changingDimension.Store(false)
h.expectedID.Store(0)
}
return nil
}
19 changes: 18 additions & 1 deletion server/session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type Session struct {
openedWindow atomic.Value[*inventory.Inventory]
openedPos atomic.Value[cube.Pos]
swingingArm atomic.Bool
changingDimension atomic.Bool

recipes map[uint32]recipe.Recipe

Expand Down Expand Up @@ -399,7 +400,16 @@ func (s *Session) handleWorldSwitch(w *world.World) {
// changeDimension changes the dimension of the client. If silent is set to true, the portal noise will be stopped
// immediately.
func (s *Session) changeDimension(dim int32, silent bool) {
s.writePacket(&packet.ChangeDimension{Dimension: dim, Position: vec64To32(s.c.Position().Add(entityOffset(s.c)))})
s.changingDimension.Store(true)
h := s.handlers[packet.IDServerBoundLoadingScreen].(*ServerBoundLoadingScreenHandler)
id := h.currentID.Add(1)
h.expectedID.Store(id)

s.writePacket(&packet.ChangeDimension{
Dimension: dim,
Position: vec64To32(s.c.Position().Add(entityOffset(s.c))),
LoadingScreenID: protocol.Option(id),
})
s.writePacket(&packet.StopSound{StopAll: silent})
s.writePacket(&packet.PlayStatus{Status: packet.PlayStatusPlayerSpawn})

Expand All @@ -411,6 +421,11 @@ func (s *Session) changeDimension(dim int32, silent bool) {
})
}

// ChangingDimension returns whether the session is currently changing dimension or not.
func (s *Session) ChangingDimension() bool {
return s.changingDimension.Load()
}

// handlePacket handles an incoming packet, processing it accordingly. If the packet had invalid data or was
// otherwise not valid in its context, an error is returned.
func (s *Session) handlePacket(pk packet.Packet) error {
Expand Down Expand Up @@ -463,6 +478,8 @@ func (s *Session) registerHandlers() {
packet.IDSubChunkRequest: &SubChunkRequestHandler{},
packet.IDText: &TextHandler{},
packet.IDTickSync: nil,
packet.IDServerBoundLoadingScreen: &ServerBoundLoadingScreenHandler{},
packet.IDServerBoundDiagnostics: &ServerBoundDiagnosticsHandler{},
}
}

Expand Down

0 comments on commit 408171b

Please sign in to comment.