Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The client randomly disconnects after a quick world switch. #853

Closed
Dasciam opened this issue Mar 10, 2024 · 0 comments · Fixed by #859
Closed

The client randomly disconnects after a quick world switch. #853

Dasciam opened this issue Mar 10, 2024 · 0 comments · Fixed by #859

Comments

@Dasciam
Copy link
Contributor

Dasciam commented Mar 10, 2024

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:

image

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)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant