Closed
Description
What happened?
When a player moves from one world to another very quickly, when all the chunks in that world have not yet been sent, the client randomly disconnects with a message:
Also, the client does not actually disconnect and continues to receive packets from the server on the disconnect screen...
Code used to reproduce the issue:
main.go:
package main
import (
"fmt"
"github.com/df-mc/dragonfly/server"
"github.com/df-mc/dragonfly/server/block"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/player"
"github.com/df-mc/dragonfly/server/player/chat"
"github.com/df-mc/dragonfly/server/world"
"github.com/pelletier/go-toml"
"github.com/sirupsen/logrus"
"math/rand"
"os"
"time"
)
// sleep sleeps for five ticks.
// For the bug showcase.
// - Sleep for five ticks, to imitate user's manual fast world switch.
func sleep() {
time.Sleep(time.Second / 20 * 5)
}
// prepareWorld prepares the world for bug showcase:
// - Fills area with random block sequence;
// - Stops all world events like time and weather.
func prepareWorld(w *world.World) {
const (
randBoundXZ = 50
randBoundY
)
for x := -randBoundXZ; x < randBoundXZ; x++ {
for z := -randBoundXZ; z < randBoundXZ; z++ {
for y := 0; y < randBoundY; y++ {
var b world.Block = block.Bedrock{}
if rand.Int()%5 == 2 {
b = block.Stone{}
}
w.SetBlock(cube.Pos{x, y, z}, b, nil)
}
}
}
w.SetSpawn(cube.Pos{0, randBoundY + 5, 0})
w.SetTime(6000)
w.StopTime()
w.StopThundering()
w.StopRaining()
w.StopWeatherCycle()
}
func main() {
log := logrus.New()
log.Formatter = &logrus.TextFormatter{ForceColors: true}
log.Level = logrus.DebugLevel
chat.Global.Subscribe(chat.StdoutSubscriber{})
conf, err := readConfig(log)
if err != nil {
log.Fatalln(err)
}
srv := conf.New()
srv.CloseOnProgramEnd()
// Create two temporary worlds.
w1 := world.Config{
Generator: world.NopGenerator{},
RandomTickSpeed: 0,
Entities: world.EntityRegistry{},
}.New()
prepareWorld(w1)
w2 := world.Config{
Generator: world.NopGenerator{},
RandomTickSpeed: 0,
Entities: world.EntityRegistry{},
}.New()
prepareWorld(w2)
srv.Listen()
for srv.Accept(func(p *player.Player) {
go func() {
for i := 0; i < 10; i++ {
w1.AddEntity(p)
p.Teleport(w1.Spawn().Vec3Centre())
sleep()
w2.AddEntity(p)
p.Teleport(w2.Spawn().Vec3Centre())
sleep()
}
}()
}) {
}
}
// readConfig reads the configuration from the config.toml file, or creates the
// file if it does not yet exist.
func readConfig(log server.Logger) (server.Config, error) {
c := server.DefaultConfig()
var zero server.Config
if _, err := os.Stat("config.toml"); os.IsNotExist(err) {
data, err := toml.Marshal(c)
if err != nil {
return zero, fmt.Errorf("encode default config: %v", err)
}
if err := os.WriteFile("config.toml", data, 0644); err != nil {
return zero, fmt.Errorf("create default config: %v", err)
}
return c.Config(log)
}
data, err := os.ReadFile("config.toml")
if err != nil {
return zero, fmt.Errorf("read config: %v", err)
}
if err := toml.Unmarshal(data, &c); err != nil {
return zero, fmt.Errorf("decode config: %v", err)
}
return c.Config(log)
}
Metadata
Metadata
Assignees
Labels
No labels