make worlds a proper handler
This commit is contained in:
parent
f1cb7df05e
commit
4e7cfeb3b4
6
go.sum
6
go.sum
|
@ -10,6 +10,7 @@ git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr
|
|||
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo=
|
||||
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
|
||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/TeaEntityLab/fpGo/v2 v2.3.2 h1:qlGjFzXukp9IgVQl32cz4PosbiFEnwXa2EpDbwddHS8=
|
||||
github.com/TeaEntityLab/fpGo/v2 v2.3.2/go.mod h1:b06fRNLSnNiUwfSskBC3f3cocA4mAC2iySdtaP/T9uA=
|
||||
github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE=
|
||||
|
@ -19,6 +20,8 @@ github.com/benoitkugler/textlayout-testdata v0.1.1 h1:AvFxBxpfrQd8v55qH59mZOJOQj
|
|||
github.com/benoitkugler/textlayout-testdata v0.1.1/go.mod h1:i/qZl09BbUOtd7Bu/W1CAubRwTWrEXWq6JwMkw8wYxo=
|
||||
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9 h1:/G0ghZwrhou0Wq21qc1vXXMm/t/aKWkALWwITptKbE0=
|
||||
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9/go.mod h1:TOk10ahXejq9wkEaym3KPRNeuR/h5Jx+s8QRWIa2oTM=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/changkun/lockfree v0.0.1 h1:5WefVJLglY4IHRqOQmh6Ao6wkJYaJkarshKU8VUtId4=
|
||||
github.com/changkun/lockfree v0.0.1/go.mod h1:3bKiaXn/iNzIPlSvSOMSVbRQUQtAp8qUAyBUtzU11s4=
|
||||
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:Yg2hDs4b13Evkpj42FU2idX2cVXVFqQSheXYKM86Qsk=
|
||||
|
@ -102,6 +105,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF
|
|||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/repeale/fp-go v0.11.1 h1:Q/e+gNyyHaxKAyfdbBqvip3DxhVWH453R+kthvSr9Mk=
|
||||
github.com/repeale/fp-go v0.11.1/go.mod h1:4KrwQJB1VRY+06CA+jTc4baZetr6o2PeuqnKr5ybQUc=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49 h1:LuxslTBxJrrNeKfqoywIERWWhH43TgiVAiPEVlhgNBA=
|
||||
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49/go.mod h1:fY313ZGG810aWruFYcyq3coFpHDrWJVoMfSRI81y1r4=
|
||||
github.com/sandertv/go-raknet v1.12.0 h1:olUzZlIJyX/pgj/mrsLCZYjKLNDsYiWdvQ4NIm3z0DA=
|
||||
|
@ -110,6 +115,7 @@ github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQ
|
|||
github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (w *worldsServer) processChangeDimension(pk *packet.ChangeDimension) {
|
||||
func (w *worldsHandler) processChangeDimension(pk *packet.ChangeDimension) {
|
||||
if len(w.worldState.chunks) > 0 {
|
||||
w.SaveAndReset()
|
||||
} else {
|
||||
|
@ -18,13 +18,14 @@ func (w *worldsServer) processChangeDimension(pk *packet.ChangeDimension) {
|
|||
w.Reset(w.CurrentName())
|
||||
}
|
||||
dimensionID := pk.Dimension
|
||||
if w.serverState.ispre118 {
|
||||
if w.serverState.ispre118 && dimensionID == 0 {
|
||||
dimensionID += 10
|
||||
}
|
||||
w.worldState.Dim = dimensionIDMap[uint8(dimensionID)]
|
||||
d, _ := world.DimensionByID(int(dimensionID))
|
||||
w.worldState.dimension = d
|
||||
}
|
||||
|
||||
func (w *worldsServer) processLevelChunk(pk *packet.LevelChunk) {
|
||||
func (w *worldsHandler) processLevelChunk(pk *packet.LevelChunk) {
|
||||
// ignore empty chunks THANKS WEIRD SERVER SOFTWARE DEVS
|
||||
if len(pk.RawPayload) == 0 {
|
||||
logrus.Info(locale.Loc("empty_chunk", nil))
|
||||
|
@ -41,7 +42,7 @@ func (w *worldsServer) processLevelChunk(pk *packet.LevelChunk) {
|
|||
subChunkCount = int(pk.SubChunkCount)
|
||||
}
|
||||
|
||||
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, w.worldState.Dim.Range(), w.serverState.ispre118, w.bp.HasBlocks())
|
||||
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, w.worldState.dimension.Range(), w.serverState.ispre118, w.bp.HasBlocks())
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
|
@ -53,21 +54,19 @@ func (w *worldsServer) processLevelChunk(pk *packet.LevelChunk) {
|
|||
}
|
||||
w.worldState.chunks[pk.Position] = ch
|
||||
|
||||
max := w.worldState.Dim.Range().Height() / 16
|
||||
max := w.worldState.dimension.Range().Height() / 16
|
||||
switch pk.SubChunkCount {
|
||||
case protocol.SubChunkRequestModeLimited:
|
||||
max = int(pk.HighestSubChunk)
|
||||
fallthrough
|
||||
case protocol.SubChunkRequestModeLimitless:
|
||||
var offsetTable []protocol.SubChunkOffset
|
||||
r := w.worldState.Dim.Range()
|
||||
r := w.worldState.dimension.Range()
|
||||
for y := int8(r.Min() / 16); y < int8(r.Max()); y++ {
|
||||
offsetTable = append(offsetTable, protocol.SubChunkOffset{0, y, 0})
|
||||
}
|
||||
|
||||
dimId, ok := world.DimensionID(w.worldState.Dim)
|
||||
_ = ok
|
||||
|
||||
dimId, _ := world.DimensionID(w.worldState.dimension)
|
||||
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
|
||||
Dimension: int32(dimId),
|
||||
Position: protocol.SubChunkPos{
|
||||
|
@ -86,7 +85,7 @@ func (w *worldsServer) processLevelChunk(pk *packet.LevelChunk) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *worldsServer) processSubChunk(pk *packet.SubChunk) {
|
||||
func (w *worldsHandler) processSubChunk(pk *packet.SubChunk) {
|
||||
posToRedraw := make(map[protocol.ChunkPos]bool)
|
||||
|
||||
for _, sub := range pk.SubChunkEntries {
|
||||
|
@ -124,14 +123,16 @@ func blockPosInChunk(pos protocol.BlockPos) (uint8, int16, uint8) {
|
|||
return uint8(pos.X() & 0x0f), int16(pos.Y() & 0x0f), uint8(pos.Z() & 0x0f)
|
||||
}
|
||||
|
||||
func (w *worldsServer) ProcessChunkPackets(pk packet.Packet) packet.Packet {
|
||||
func (w *worldsHandler) ProcessChunkPackets(pk packet.Packet) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.ChangeDimension:
|
||||
w.processChangeDimension(pk)
|
||||
case *packet.LevelChunk:
|
||||
w.processLevelChunk(pk)
|
||||
|
||||
w.proxy.SendPopup(locale.Locm("popup_chunk_count", locale.Strmap{"Count": len(w.worldState.chunks), "Name": w.worldState.Name}, len(w.worldState.chunks)))
|
||||
w.proxy.SendPopup(locale.Locm("popup_chunk_count", locale.Strmap{
|
||||
"Count": len(w.worldState.chunks),
|
||||
"Name": w.worldState.Name,
|
||||
}, len(w.worldState.chunks)))
|
||||
case *packet.SubChunk:
|
||||
w.processSubChunk(pk)
|
||||
case *packet.BlockActorData:
|
||||
|
|
|
@ -61,7 +61,7 @@ func (e serverEntity) Type() world.EntityType {
|
|||
return e.EntityType
|
||||
}
|
||||
|
||||
func (w *worldsServer) processAddActor(pk *packet.AddActor) {
|
||||
func (w *worldsHandler) processAddActor(pk *packet.AddActor) {
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if !ok {
|
||||
e = &entityState{
|
||||
|
@ -141,47 +141,49 @@ func entityMetadataToNBT(metadata protocol.EntityMetadata, nbt map[string]any) {
|
|||
}
|
||||
}
|
||||
|
||||
if metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagNoAI) {
|
||||
nbt["IsAutonomous"] = false
|
||||
}
|
||||
for k, v := range flagNames {
|
||||
nbt[v] = metadata.Flag(protocol.EntityDataKeyFlags, k)
|
||||
}
|
||||
if _, ok := metadata[protocol.EntityDataKeyFlags]; ok {
|
||||
if metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagNoAI) {
|
||||
nbt["IsAutonomous"] = false
|
||||
}
|
||||
for k, v := range flagNames {
|
||||
nbt[v] = metadata.Flag(protocol.EntityDataKeyFlags, k)
|
||||
}
|
||||
|
||||
AlwaysShowName := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagAlwaysShowName)
|
||||
if AlwaysShowName {
|
||||
nbt["CustomNameVisible"] = true
|
||||
}
|
||||
AlwaysShowName := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagAlwaysShowName)
|
||||
if AlwaysShowName {
|
||||
nbt["CustomNameVisible"] = true
|
||||
}
|
||||
|
||||
type effect struct {
|
||||
Id byte
|
||||
Amplifier byte
|
||||
Duration int32
|
||||
DurationEasy int32
|
||||
DurationNormal int32
|
||||
DurationHard int32
|
||||
Ambient bool
|
||||
ShowParticles bool
|
||||
DisplayOnScreenTextureAnimation bool
|
||||
}
|
||||
type effect struct {
|
||||
Id byte
|
||||
Amplifier byte
|
||||
Duration int32
|
||||
DurationEasy int32
|
||||
DurationNormal int32
|
||||
DurationHard int32
|
||||
Ambient bool
|
||||
ShowParticles bool
|
||||
DisplayOnScreenTextureAnimation bool
|
||||
}
|
||||
|
||||
activeEffects := []effect{}
|
||||
addEffect := func(id int, showParticles bool) {
|
||||
activeEffects = append(activeEffects, effect{
|
||||
Id: byte(id),
|
||||
Amplifier: 1,
|
||||
Duration: 10000000,
|
||||
ShowParticles: false,
|
||||
})
|
||||
}
|
||||
activeEffects := []effect{}
|
||||
addEffect := func(id int, showParticles bool) {
|
||||
activeEffects = append(activeEffects, effect{
|
||||
Id: byte(id),
|
||||
Amplifier: 1,
|
||||
Duration: 10000000,
|
||||
ShowParticles: false,
|
||||
})
|
||||
}
|
||||
|
||||
invisible := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagInvisible)
|
||||
if invisible {
|
||||
addEffect(packet.EffectInvisibility, false)
|
||||
}
|
||||
invisible := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagInvisible)
|
||||
if invisible {
|
||||
addEffect(packet.EffectInvisibility, false)
|
||||
}
|
||||
|
||||
if len(activeEffects) > 0 {
|
||||
nbt["ActiveEffects"] = activeEffects
|
||||
if len(activeEffects) > 0 {
|
||||
nbt["ActiveEffects"] = activeEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +216,7 @@ func (s *entityState) ToServerEntity() serverEntity {
|
|||
return e
|
||||
}
|
||||
|
||||
func (w *worldsServer) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
||||
func (w *worldsHandler) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.AddActor:
|
||||
w.processAddActor(pk)
|
||||
|
|
|
@ -17,7 +17,7 @@ type itemContainer struct {
|
|||
Content *packet.InventoryContent
|
||||
}
|
||||
|
||||
func (w *worldsServer) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
||||
func (w *worldsHandler) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.ContainerOpen:
|
||||
// add to open containers
|
||||
|
@ -116,7 +116,7 @@ func (w *worldsServer) processItemPacketsServer(pk packet.Packet) packet.Packet
|
|||
return pk
|
||||
}
|
||||
|
||||
func (w *worldsServer) processItemPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
|
||||
func (w *worldsHandler) processItemPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.ItemStackRequest:
|
||||
var requests []protocol.ItemStackRequest
|
||||
|
@ -187,7 +187,7 @@ func stackToItem(it protocol.ItemStack) item.Stack {
|
|||
return nbtconv.ReadItem(it.NBTData, &s)
|
||||
}
|
||||
|
||||
func (w *worldsServer) playerData() (ret map[string]any) {
|
||||
func (w *worldsHandler) playerData() (ret map[string]any) {
|
||||
ret = map[string]any{
|
||||
"format_version": "1.12.0",
|
||||
"identifier": "minecraft:player",
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/bedrock-tool/bedrocktool/locale"
|
||||
"github.com/bedrock-tool/bedrocktool/ui/messages"
|
||||
"github.com/bedrock-tool/bedrocktool/utils"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"golang.design/x/lockfree"
|
||||
|
||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||
|
@ -79,10 +80,10 @@ type MapUI struct {
|
|||
l sync.RWMutex
|
||||
|
||||
ticker *time.Ticker
|
||||
w *worldsServer
|
||||
w *worldsHandler
|
||||
}
|
||||
|
||||
func NewMapUI(w *worldsServer) *MapUI {
|
||||
func NewMapUI(w *worldsHandler) *MapUI {
|
||||
m := &MapUI{
|
||||
img: image.NewRGBA(image.Rect(0, 0, 128, 128)),
|
||||
zoomLevel: 16,
|
||||
|
@ -265,14 +266,29 @@ func (m *MapUI) SetChunk(pos protocol.ChunkPos, ch *chunk.Chunk, complete bool)
|
|||
m.SchedRedraw()
|
||||
}
|
||||
|
||||
func (w *worldsServer) ProcessAnimate(pk *packet.Animate) {
|
||||
func (w *worldsHandler) ProcessAnimate(pk *packet.Animate) {
|
||||
if pk.ActionType == packet.AnimateActionSwingArm {
|
||||
w.mapUI.ChangeZoom()
|
||||
w.proxy.SendPopup(locale.Loc("zoom_level", locale.Strmap{"Level": w.mapUI.zoomLevel}))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worldsServer) processMapPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
|
||||
func (w *worldsHandler) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
|
||||
last := w.serverState.PlayerPos
|
||||
current := TPlayerPos{
|
||||
Position: Position,
|
||||
Pitch: Pitch,
|
||||
Yaw: Yaw,
|
||||
HeadYaw: HeadYaw,
|
||||
}
|
||||
w.serverState.PlayerPos = current
|
||||
|
||||
if int(last.Position.X()) != int(current.Position.X()) || int(last.Position.Z()) != int(current.Position.Z()) {
|
||||
w.mapUI.SchedRedraw()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worldsHandler) processMapPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.MovePlayer:
|
||||
w.SetPlayerPos(pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
|
||||
|
|
|
@ -41,7 +41,7 @@ type TPlayerPos struct {
|
|||
|
||||
// the state used for drawing and saving
|
||||
|
||||
type worldSettings struct {
|
||||
type WorldSettings struct {
|
||||
// settings
|
||||
voidGen bool
|
||||
withPacks bool
|
||||
|
@ -50,7 +50,7 @@ type worldSettings struct {
|
|||
}
|
||||
|
||||
type worldState struct {
|
||||
Dim world.Dimension
|
||||
dimension world.Dimension
|
||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||
blockNBT map[protocol.SubChunkPos][]map[string]any
|
||||
entities map[uint64]*entityState
|
||||
|
@ -69,7 +69,7 @@ type serverState struct {
|
|||
Name string
|
||||
}
|
||||
|
||||
type worldsServer struct {
|
||||
type worldsHandler struct {
|
||||
ctx context.Context
|
||||
proxy *utils.ProxyContext
|
||||
mapUI *MapUI
|
||||
|
@ -78,53 +78,10 @@ type worldsServer struct {
|
|||
|
||||
worldState worldState
|
||||
serverState serverState
|
||||
settings worldSettings
|
||||
settings WorldSettings
|
||||
}
|
||||
|
||||
func NewWorldsServer(ctx context.Context, proxy *utils.ProxyContext, ServerName string, ui utils.UI) *worldsServer {
|
||||
w := &worldsServer{
|
||||
ctx: ctx,
|
||||
proxy: proxy,
|
||||
mapUI: nil,
|
||||
gui: ui,
|
||||
bp: behaviourpack.New(ServerName),
|
||||
|
||||
serverState: serverState{
|
||||
ispre118: false,
|
||||
worldCounter: 0,
|
||||
ChunkRadius: 0,
|
||||
|
||||
playerInventory: nil,
|
||||
PlayerPos: TPlayerPos{},
|
||||
|
||||
Name: ServerName,
|
||||
},
|
||||
|
||||
settings: worldSettings{},
|
||||
}
|
||||
w.mapUI = NewMapUI(w)
|
||||
w.Reset(w.CurrentName())
|
||||
|
||||
w.gui.Message(messages.Init{
|
||||
Handler: nil,
|
||||
})
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
var dimensionIDMap = map[uint8]world.Dimension{
|
||||
0: world.Overworld,
|
||||
1: world.Nether,
|
||||
2: world.End,
|
||||
// < 1.18
|
||||
10: world.Overworld_legacy,
|
||||
11: world.Nether,
|
||||
12: world.End,
|
||||
}
|
||||
|
||||
var (
|
||||
black16x16 = image.NewRGBA(image.Rect(0, 0, 16, 16))
|
||||
)
|
||||
var black16x16 = image.NewRGBA(image.Rect(0, 0, 16, 16))
|
||||
|
||||
func init() {
|
||||
for i := 3; i < len(black16x16.Pix); i += 4 {
|
||||
|
@ -161,24 +118,87 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
|||
return err
|
||||
}
|
||||
|
||||
w := NewWorldsServer(ctx, proxy, hostname, ui)
|
||||
w.settings = worldSettings{
|
||||
proxy.AlwaysGetPacks = true
|
||||
proxy.AddHandler(NewWorldsHandler(ctx, ui, WorldSettings{
|
||||
voidGen: c.EnableVoid,
|
||||
withPacks: c.Packs,
|
||||
saveImage: c.SaveImage,
|
||||
}
|
||||
}))
|
||||
|
||||
proxy.AlwaysGetPacks = true
|
||||
proxy.GameDataModifier = func(gd *minecraft.GameData) {
|
||||
gd.ClientSideGeneration = false
|
||||
ui.Message(messages.SetUIState(messages.UIStateConnect))
|
||||
err = proxy.Run(ctx, serverAddress, hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ui.Message(messages.SetUIState(messages.UIStateFinished))
|
||||
return nil
|
||||
}
|
||||
|
||||
proxy.AddHandler(&utils.ProxyHandler{
|
||||
Name: "Worlds",
|
||||
ConnectCB: w.OnConnect,
|
||||
func NewWorldsHandler(ctx context.Context, ui utils.UI, settings WorldSettings) *utils.ProxyHandler {
|
||||
w := &worldsHandler{
|
||||
ctx: ctx,
|
||||
mapUI: nil,
|
||||
gui: ui,
|
||||
bp: nil,
|
||||
|
||||
serverState: serverState{
|
||||
ispre118: false,
|
||||
worldCounter: 0,
|
||||
ChunkRadius: 0,
|
||||
|
||||
playerInventory: nil,
|
||||
PlayerPos: TPlayerPos{},
|
||||
},
|
||||
|
||||
settings: WorldSettings{},
|
||||
}
|
||||
w.mapUI = NewMapUI(w)
|
||||
w.Reset(w.CurrentName())
|
||||
|
||||
return &utils.ProxyHandler{
|
||||
Name: "Worlds",
|
||||
ProxyRef: func(pc *utils.ProxyContext) {
|
||||
w.proxy = pc
|
||||
|
||||
w.proxy.AddCommand(utils.IngameCommand{
|
||||
Exec: func(cmdline []string) bool {
|
||||
return w.setWorldName(strings.Join(cmdline, " "), false)
|
||||
},
|
||||
Cmd: protocol.Command{
|
||||
Name: "setname",
|
||||
Description: locale.Loc("setname_desc", nil),
|
||||
Overloads: []protocol.CommandOverload{{
|
||||
Parameters: []protocol.CommandParameter{{
|
||||
Name: "name",
|
||||
Type: protocol.CommandArgTypeString,
|
||||
Optional: false,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
})
|
||||
|
||||
w.proxy.AddCommand(utils.IngameCommand{
|
||||
Exec: func(cmdline []string) bool {
|
||||
return w.setVoidGen(!w.settings.voidGen, false)
|
||||
},
|
||||
Cmd: protocol.Command{
|
||||
Name: "void",
|
||||
Description: locale.Loc("void_desc", nil),
|
||||
},
|
||||
})
|
||||
},
|
||||
AddressAndName: func(address, hostname string) error {
|
||||
w.bp = behaviourpack.New(hostname)
|
||||
w.serverState.Name = hostname
|
||||
return nil
|
||||
},
|
||||
OnClientConnect: func(conn *minecraft.Conn) {
|
||||
w.gui.Message(messages.SetUIState(messages.UIStateConnecting))
|
||||
},
|
||||
GameDataModifier: func(gd *minecraft.GameData) {
|
||||
gd.ClientSideGeneration = false
|
||||
},
|
||||
ConnectCB: w.OnConnect,
|
||||
PacketCB: func(pk packet.Packet, toServer bool, timeReceived time.Time) (packet.Packet, error) {
|
||||
forward := true
|
||||
|
||||
|
@ -203,34 +223,13 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
|||
}
|
||||
return pk, nil
|
||||
},
|
||||
})
|
||||
|
||||
w.gui.Message(messages.SetUIState(messages.UIStateConnect))
|
||||
err = w.proxy.Run(ctx, serverAddress, hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.SaveAndReset()
|
||||
ui.Message(messages.SetUIState(messages.UIStateFinished))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worldsServer) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
|
||||
last := w.serverState.PlayerPos
|
||||
current := TPlayerPos{
|
||||
Position: Position,
|
||||
Pitch: Pitch,
|
||||
Yaw: Yaw,
|
||||
HeadYaw: HeadYaw,
|
||||
}
|
||||
w.serverState.PlayerPos = current
|
||||
|
||||
if int(last.Position.X()) != int(current.Position.X()) || int(last.Position.Z()) != int(current.Position.Z()) {
|
||||
w.mapUI.SchedRedraw()
|
||||
OnEnd: func() {
|
||||
w.SaveAndReset()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worldsServer) setVoidGen(val bool, fromUI bool) bool {
|
||||
func (w *worldsHandler) setVoidGen(val bool, fromUI bool) bool {
|
||||
w.settings.voidGen = val
|
||||
var s = locale.Loc("void_generator_false", nil)
|
||||
if w.settings.voidGen {
|
||||
|
@ -247,7 +246,7 @@ func (w *worldsServer) setVoidGen(val bool, fromUI bool) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (w *worldsServer) setWorldName(val string, fromUI bool) bool {
|
||||
func (w *worldsHandler) setWorldName(val string, fromUI bool) bool {
|
||||
w.worldState.Name = val
|
||||
w.proxy.SendMessage(locale.Loc("worldname_set", locale.Strmap{"Name": w.worldState.Name}))
|
||||
|
||||
|
@ -260,7 +259,7 @@ func (w *worldsServer) setWorldName(val string, fromUI bool) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (w *worldsServer) CurrentName() string {
|
||||
func (w *worldsHandler) CurrentName() string {
|
||||
worldName := "world"
|
||||
if w.serverState.worldCounter > 1 {
|
||||
worldName = fmt.Sprintf("world-%d", w.serverState.worldCounter)
|
||||
|
@ -268,9 +267,9 @@ func (w *worldsServer) CurrentName() string {
|
|||
return worldName
|
||||
}
|
||||
|
||||
func (w *worldsServer) Reset(newName string) {
|
||||
func (w *worldsHandler) Reset(newName string) {
|
||||
w.worldState = worldState{
|
||||
Dim: nil,
|
||||
dimension: nil,
|
||||
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
||||
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
||||
entities: make(map[uint64]*entityState),
|
||||
|
@ -280,23 +279,63 @@ func (w *worldsServer) Reset(newName string) {
|
|||
w.mapUI.Reset()
|
||||
}
|
||||
|
||||
// SaveAndReset writes the world to a folder, resets all the chunks
|
||||
func (w *worldsServer) SaveAndReset() {
|
||||
|
||||
// cull empty chunks
|
||||
keys := make([]protocol.ChunkPos, 0, len(w.worldState.chunks))
|
||||
for cp := range w.worldState.chunks {
|
||||
func (w *worldState) cullChunks() {
|
||||
keys := make([]protocol.ChunkPos, 0, len(w.chunks))
|
||||
for cp := range w.chunks {
|
||||
keys = append(keys, cp)
|
||||
}
|
||||
|
||||
for _, cp := range fp.Filter(func(cp protocol.ChunkPos) bool {
|
||||
return !fp.Some(func(sc *chunk.SubChunk) bool {
|
||||
return !sc.Empty()
|
||||
})(w.worldState.chunks[cp].Sub())
|
||||
})(w.chunks[cp].Sub())
|
||||
})(keys) {
|
||||
delete(w.worldState.chunks, cp)
|
||||
delete(w.chunks, cp)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worldState) Save(folder string) (*mcdb.Provider, error) {
|
||||
provider, err := mcdb.New(logrus.StandardLogger(), folder, opt.DefaultCompression)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// save chunk data
|
||||
for cp, c := range w.chunks {
|
||||
provider.SaveChunk((world.ChunkPos)(cp), c, w.dimension)
|
||||
}
|
||||
|
||||
// save block nbt data
|
||||
blockNBT := make(map[world.ChunkPos][]map[string]any)
|
||||
for scp, v := range w.blockNBT { // 3d to 2d
|
||||
cp := world.ChunkPos{scp.X(), scp.Z()}
|
||||
blockNBT[cp] = append(blockNBT[cp], v...)
|
||||
}
|
||||
for cp, v := range blockNBT {
|
||||
err = provider.SaveBlockNBT(cp, v, w.dimension)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// save entities
|
||||
chunkEntities := make(map[world.ChunkPos][]world.Entity)
|
||||
for _, es := range w.entities {
|
||||
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
|
||||
chunkEntities[cp] = append(chunkEntities[cp], es.ToServerEntity())
|
||||
}
|
||||
for cp, v := range chunkEntities {
|
||||
err = provider.SaveEntities(cp, v, w.dimension)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return provider, err
|
||||
}
|
||||
|
||||
// SaveAndReset writes the world to a folder, resets all the chunks
|
||||
func (w *worldsHandler) SaveAndReset() {
|
||||
w.worldState.cullChunks()
|
||||
if len(w.worldState.chunks) == 0 {
|
||||
w.Reset(w.CurrentName())
|
||||
return
|
||||
|
@ -312,42 +351,10 @@ func (w *worldsServer) SaveAndReset() {
|
|||
folder := path.Join("worlds", fmt.Sprintf("%s/%s", w.serverState.Name, w.worldState.Name))
|
||||
os.RemoveAll(folder)
|
||||
os.MkdirAll(folder, 0o777)
|
||||
|
||||
provider, err := mcdb.New(logrus.StandardLogger(), folder, opt.DefaultCompression)
|
||||
provider, err := w.worldState.Save(folder)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
// save chunk data
|
||||
for cp, c := range w.worldState.chunks {
|
||||
provider.SaveChunk((world.ChunkPos)(cp), c, w.worldState.Dim)
|
||||
}
|
||||
|
||||
// save block nbt data
|
||||
blockNBT := make(map[world.ChunkPos][]map[string]any)
|
||||
for scp, v := range w.worldState.blockNBT { // 3d to 2d
|
||||
cp := world.ChunkPos{scp.X(), scp.Z()}
|
||||
blockNBT[cp] = append(blockNBT[cp], v...)
|
||||
}
|
||||
for cp, v := range blockNBT {
|
||||
err = provider.SaveBlockNBT(cp, v, w.worldState.Dim)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// save entities
|
||||
chunkEntities := make(map[world.ChunkPos][]world.Entity)
|
||||
for _, es := range w.worldState.entities {
|
||||
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
|
||||
chunkEntities[cp] = append(chunkEntities[cp], es.ToServerEntity())
|
||||
}
|
||||
|
||||
for cp, v := range chunkEntities {
|
||||
err = provider.SaveEntities(cp, v, w.worldState.Dim)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = provider.SaveLocalPlayerData(w.playerData())
|
||||
|
@ -366,6 +373,7 @@ func (w *worldsServer) SaveAndReset() {
|
|||
// set gamerules
|
||||
ld := provider.LevelDat()
|
||||
gd := w.proxy.Server.GameData()
|
||||
ld.RandomSeed = int64(gd.WorldSeed)
|
||||
for _, gr := range gd.GameRules {
|
||||
switch gr.Name {
|
||||
case "commandblockoutput":
|
||||
|
@ -434,8 +442,6 @@ func (w *worldsServer) SaveAndReset() {
|
|||
}
|
||||
}
|
||||
|
||||
ld.RandomSeed = int64(gd.WorldSeed)
|
||||
|
||||
// void world
|
||||
if w.settings.voidGen {
|
||||
ld.FlatWorldLayers = `{"biome_id":1,"block_layers":[{"block_data":0,"block_id":0,"count":1},{"block_data":0,"block_id":0,"count":2},{"block_data":0,"block_id":0,"count":1}],"encoding_version":3,"structure_options":null}`
|
||||
|
@ -545,9 +551,8 @@ func (w *worldsServer) SaveAndReset() {
|
|||
w.gui.Message(messages.SetUIState(messages.UIStateMain))
|
||||
}
|
||||
|
||||
func (w *worldsServer) OnConnect(err error) bool {
|
||||
func (w *worldsHandler) OnConnect(err error) bool {
|
||||
w.gui.Message(messages.SetUIState(messages.UIStateMain))
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
@ -592,40 +597,14 @@ func (w *worldsServer) OnConnect(err error) bool {
|
|||
dimensionID := gd.Dimension
|
||||
if w.serverState.ispre118 {
|
||||
logrus.Info(locale.Loc("using_under_118", nil))
|
||||
dimensionID += 10
|
||||
if dimensionID == 0 {
|
||||
dimensionID += 10
|
||||
}
|
||||
}
|
||||
w.worldState.Dim = dimensionIDMap[uint8(dimensionID)]
|
||||
w.worldState.dimension, _ = world.DimensionByID(int(dimensionID))
|
||||
}
|
||||
|
||||
w.proxy.SendMessage(locale.Loc("use_setname", nil))
|
||||
|
||||
w.proxy.AddCommand(utils.IngameCommand{
|
||||
Exec: func(cmdline []string) bool {
|
||||
return w.setWorldName(strings.Join(cmdline, " "), false)
|
||||
},
|
||||
Cmd: protocol.Command{
|
||||
Name: "setname",
|
||||
Description: locale.Loc("setname_desc", nil),
|
||||
Overloads: []protocol.CommandOverload{{
|
||||
Parameters: []protocol.CommandParameter{{
|
||||
Name: "name",
|
||||
Type: protocol.CommandArgTypeString,
|
||||
Optional: false,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
})
|
||||
|
||||
w.proxy.AddCommand(utils.IngameCommand{
|
||||
Exec: func(cmdline []string) bool {
|
||||
return w.setVoidGen(!w.settings.voidGen, false)
|
||||
},
|
||||
Cmd: protocol.Command{
|
||||
Name: "void",
|
||||
Description: locale.Loc("void_desc", nil),
|
||||
},
|
||||
})
|
||||
|
||||
w.mapUI.Start()
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
|
|||
go func() {
|
||||
defer p.Router.Wg.Done()
|
||||
utils.InitDNS()
|
||||
utils.InitExtraDebug(p.Router.Ctx)
|
||||
|
||||
err := cmd.Execute(p.Router.Ctx, utils.CurrentUI)
|
||||
if err != nil {
|
||||
|
|
|
@ -28,12 +28,12 @@ func dumpPacket(f io.WriteCloser, toServer bool, payload []byte) {
|
|||
f.Write([]byte{0xBB, 0xBB, 0xBB, 0xBB})
|
||||
}
|
||||
|
||||
type PacketCapturer struct {
|
||||
type packetCapturer struct {
|
||||
proxy *utils.ProxyContext
|
||||
fio *os.File
|
||||
}
|
||||
|
||||
func (p *PacketCapturer) AddressAndName(address, hostname string) error {
|
||||
func (p *packetCapturer) AddressAndName(address, hostname string) error {
|
||||
os.Mkdir("captures", 0o775)
|
||||
fio, err := os.Create(fmt.Sprintf("captures/%s-%s.pcap2", hostname, time.Now().Format("2006-01-02_15-04-05")))
|
||||
if err != nil {
|
||||
|
@ -44,7 +44,7 @@ func (p *PacketCapturer) AddressAndName(address, hostname string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *PacketCapturer) PacketFunc(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||
func (p *packetCapturer) PacketFunc(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||
IsfromClient := utils.ClientAddr.String() == src.String()
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
@ -54,14 +54,14 @@ func (p *PacketCapturer) PacketFunc(header packet.Header, payload []byte, src, d
|
|||
}
|
||||
|
||||
func NewPacketCapturer() *utils.ProxyHandler {
|
||||
p := &PacketCapturer{}
|
||||
p := &packetCapturer{}
|
||||
return &utils.ProxyHandler{
|
||||
Name: "Packet Capturer",
|
||||
ProxyRef: func(pc *utils.ProxyContext) {
|
||||
p.proxy = pc
|
||||
},
|
||||
PacketFunc: p.PacketFunc,
|
||||
AddressAndName: p.AddressAndName,
|
||||
PacketFunc: p.PacketFunc,
|
||||
OnEnd: func() {
|
||||
p.fio.Close()
|
||||
},
|
||||
|
|
|
@ -10,22 +10,12 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ChatLogger struct {
|
||||
type chatLogger struct {
|
||||
Verbose bool
|
||||
fio *os.File
|
||||
}
|
||||
|
||||
func (c *ChatLogger) AddressAndName(address, hostname string) error {
|
||||
filename := fmt.Sprintf("%s_%s_chat.log", hostname, time.Now().Format("2006-01-02_15-04-05_Z07"))
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.fio = f
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ChatLogger) PacketCB(pk packet.Packet, toServer bool, t time.Time) (packet.Packet, error) {
|
||||
func (c *chatLogger) PacketCB(pk packet.Packet, toServer bool, t time.Time) (packet.Packet, error) {
|
||||
if text, ok := pk.(*packet.Text); ok {
|
||||
logLine := text.Message
|
||||
if c.Verbose {
|
||||
|
@ -42,13 +32,21 @@ func (c *ChatLogger) PacketCB(pk packet.Packet, toServer bool, t time.Time) (pac
|
|||
}
|
||||
|
||||
func NewChatLogger() *utils.ProxyHandler {
|
||||
p := &ChatLogger{}
|
||||
c := &chatLogger{}
|
||||
return &utils.ProxyHandler{
|
||||
Name: "Packet Capturer",
|
||||
PacketCB: p.PacketCB,
|
||||
AddressAndName: p.AddressAndName,
|
||||
Name: "Packet Capturer",
|
||||
PacketCB: c.PacketCB,
|
||||
AddressAndName: func(address, hostname string) error {
|
||||
filename := fmt.Sprintf("%s_%s_chat.log", hostname, time.Now().Format("2006-01-02_15-04-05_Z07"))
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.fio = f
|
||||
return nil
|
||||
},
|
||||
OnEnd: func() {
|
||||
p.fio.Close()
|
||||
c.fio.Close()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package seconduser
|
||||
|
||||
import (
|
||||
"github.com/bedrock-tool/bedrocktool/locale"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (s *secondaryUser) ResetWorld() {
|
||||
s.chunks = make(map[world.ChunkPos]*chunk.Chunk)
|
||||
s.blockNBT = make(map[protocol.SubChunkPos][]map[string]any)
|
||||
}
|
||||
|
||||
func (s *secondaryUser) processChangeDimension(pk *packet.ChangeDimension) {
|
||||
s.ResetWorld()
|
||||
dimensionID := pk.Dimension
|
||||
if s.ispre118 && dimensionID == 0 {
|
||||
dimensionID += 10
|
||||
}
|
||||
s.dimension, _ = world.DimensionByID(int(dimensionID))
|
||||
}
|
||||
|
||||
func (s *secondaryUser) processLevelChunk(pk *packet.LevelChunk) {
|
||||
// ignore empty chunks THANKS WEIRD SERVER SOFTWARE DEVS
|
||||
if len(pk.RawPayload) == 0 {
|
||||
logrus.Info(locale.Loc("empty_chunk", nil))
|
||||
return
|
||||
}
|
||||
|
||||
var subChunkCount int
|
||||
switch pk.SubChunkCount {
|
||||
case protocol.SubChunkRequestModeLimited:
|
||||
fallthrough
|
||||
case protocol.SubChunkRequestModeLimitless:
|
||||
subChunkCount = 0
|
||||
default:
|
||||
subChunkCount = int(pk.SubChunkCount)
|
||||
}
|
||||
|
||||
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, s.dimension.Range(), s.ispre118, s.hasCustomBlocks)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
if blockNBTs != nil {
|
||||
s.blockNBT[protocol.SubChunkPos{
|
||||
pk.Position.X(), 0, pk.Position.Z(),
|
||||
}] = blockNBTs
|
||||
}
|
||||
s.chunks[world.ChunkPos(pk.Position)] = ch
|
||||
|
||||
switch pk.SubChunkCount {
|
||||
case protocol.SubChunkRequestModeLimited:
|
||||
case protocol.SubChunkRequestModeLimitless:
|
||||
default:
|
||||
}
|
||||
|
||||
for _, p := range s.server.Players() {
|
||||
p.Session().ViewChunk(world.ChunkPos(pk.Position), ch, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *secondaryUser) processSubChunk(pk *packet.SubChunk) {
|
||||
offsets := make([]protocol.SubChunkOffset, 0, len(pk.SubChunkEntries))
|
||||
for _, sub := range pk.SubChunkEntries {
|
||||
offsets = append(offsets, sub.Offset)
|
||||
var (
|
||||
absX = pk.Position[0] + int32(sub.Offset[0])
|
||||
absY = pk.Position[1] + int32(sub.Offset[1])
|
||||
absZ = pk.Position[2] + int32(sub.Offset[2])
|
||||
subPos = protocol.SubChunkPos{absX, absY, absZ}
|
||||
pos = world.ChunkPos{absX, absZ}
|
||||
)
|
||||
ch, ok := s.chunks[pos]
|
||||
if !ok {
|
||||
logrus.Error(locale.Loc("subchunk_before_chunk", nil))
|
||||
continue
|
||||
}
|
||||
blockNBT, err := ch.ApplySubChunkEntry(uint8(absY), &sub)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
if blockNBT != nil {
|
||||
s.blockNBT[subPos] = blockNBT
|
||||
}
|
||||
|
||||
chunk.LightArea([]*chunk.Chunk{ch}, 0, 0).Fill()
|
||||
}
|
||||
|
||||
for _, p := range s.server.Players() {
|
||||
p.Session().ViewSubChunks(world.SubChunkPos(pk.Position), offsets)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package seconduser
|
||||
|
||||
import "github.com/df-mc/dragonfly/server/session"
|
||||
|
||||
type fwdlistener struct {
|
||||
Conn chan session.Conn
|
||||
}
|
||||
|
||||
func (l *fwdlistener) Accept() (session.Conn, error) {
|
||||
return <-l.Conn, nil
|
||||
}
|
||||
|
||||
func (l *fwdlistener) Disconnect(conn session.Conn, reason string) error {
|
||||
return conn.Close()
|
||||
}
|
||||
|
||||
func (l *fwdlistener) Close() error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package seconduser
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
s *secondaryUser
|
||||
}
|
||||
|
||||
func (p *provider) Settings() *world.Settings {
|
||||
return &world.Settings{
|
||||
Mutex: sync.Mutex{},
|
||||
Name: "world",
|
||||
Spawn: cube.Pos{0, 0, 0},
|
||||
DefaultGameMode: world.GameModeCreative,
|
||||
Difficulty: world.DifficultyNormal,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *provider) SaveSettings(*world.Settings) {
|
||||
}
|
||||
|
||||
func (p *provider) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *provider) LoadPlayerSpawnPosition(uuid uuid.UUID) (pos cube.Pos, exists bool, err error) {
|
||||
return cube.Pos{0, 0, 0}, false, nil
|
||||
}
|
||||
|
||||
func (p *provider) SavePlayerSpawnPosition(uuid uuid.UUID, pos cube.Pos) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *provider) LoadChunk(position world.ChunkPos, dim world.Dimension) (c *chunk.Chunk, exists bool, err error) {
|
||||
c, ok := p.s.chunks[position]
|
||||
return c, ok, nil
|
||||
}
|
||||
|
||||
func (p *provider) SaveChunk(position world.ChunkPos, c *chunk.Chunk, dim world.Dimension) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *provider) LoadEntities(position world.ChunkPos, dim world.Dimension, reg world.EntityRegistry) ([]world.Entity, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *provider) SaveEntities(position world.ChunkPos, entities []world.Entity, dim world.Dimension) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *provider) LoadBlockNBT(position world.ChunkPos, dim world.Dimension) ([]map[string]any, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *provider) SaveBlockNBT(position world.ChunkPos, data []map[string]any, dim world.Dimension) error {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package seconduser
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/bedrock-tool/bedrocktool/utils"
|
||||
"github.com/df-mc/dragonfly/server"
|
||||
"github.com/df-mc/dragonfly/server/player"
|
||||
"github.com/df-mc/dragonfly/server/player/skin"
|
||||
"github.com/df-mc/dragonfly/server/session"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type secondaryUser struct {
|
||||
listener *fwdlistener
|
||||
server *server.Server
|
||||
|
||||
ispre118 bool
|
||||
hasCustomBlocks bool
|
||||
|
||||
chunks map[world.ChunkPos]*chunk.Chunk
|
||||
blockNBT map[protocol.SubChunkPos][]map[string]any
|
||||
dimension world.Dimension
|
||||
|
||||
mainPlayer *player.Player
|
||||
}
|
||||
|
||||
func NewSecondUser() *utils.ProxyHandler {
|
||||
s := &secondaryUser{
|
||||
listener: &fwdlistener{
|
||||
Conn: make(chan session.Conn),
|
||||
},
|
||||
|
||||
chunks: make(map[world.ChunkPos]*chunk.Chunk),
|
||||
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
||||
dimension: world.Overworld,
|
||||
}
|
||||
|
||||
s.server = server.Config{
|
||||
Listeners: []func(conf server.Config) (server.Listener, error){
|
||||
func(conf server.Config) (server.Listener, error) {
|
||||
return s.listener, nil
|
||||
},
|
||||
},
|
||||
Log: logrus.StandardLogger(),
|
||||
Name: "Secondary",
|
||||
Generator: func(dim world.Dimension) world.Generator { return &world.NopGenerator{} },
|
||||
WorldProvider: &provider{s: s},
|
||||
ReadOnlyWorld: true,
|
||||
}.New()
|
||||
|
||||
go s.loop()
|
||||
|
||||
return &utils.ProxyHandler{
|
||||
Name: "Secondary User",
|
||||
SecondaryClientCB: s.SecondaryClientCB,
|
||||
OnClientConnect: func(conn *minecraft.Conn) {
|
||||
id := conn.IdentityData()
|
||||
s.mainPlayer = player.New(id.DisplayName, skin.New(64, 64), mgl64.Vec3{0, 00})
|
||||
},
|
||||
PacketCB: func(pk packet.Packet, toServer bool, timeReceived time.Time) (packet.Packet, error) {
|
||||
|
||||
switch pk := pk.(type) {
|
||||
case *packet.LevelChunk:
|
||||
s.processLevelChunk(pk)
|
||||
case *packet.SubChunk:
|
||||
s.processSubChunk(pk)
|
||||
case *packet.ChangeDimension:
|
||||
s.processChangeDimension(pk)
|
||||
|
||||
case *packet.MovePlayer:
|
||||
v := mgl64.Vec3{float64(pk.Position.X()), float64(pk.Position.Y()), float64(pk.Position.Z())}
|
||||
s.mainPlayer.Teleport(v)
|
||||
case *packet.PlayerAuthInput:
|
||||
v := mgl64.Vec3{float64(pk.Position.X()), float64(pk.Position.Y()), float64(pk.Position.Z())}
|
||||
s.mainPlayer.Teleport(v)
|
||||
for _, p := range s.server.Players() {
|
||||
p.Teleport(s.mainPlayer.Position())
|
||||
}
|
||||
}
|
||||
|
||||
return pk, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *secondaryUser) SecondaryClientCB(conn *minecraft.Conn) {
|
||||
s.listener.Conn <- conn
|
||||
}
|
||||
|
||||
func (s *secondaryUser) loop() {
|
||||
s.server.Listen()
|
||||
for s.server.Accept(func(p *player.Player) {
|
||||
logrus.Infof("%s Joined", p.Name())
|
||||
p.Teleport(s.mainPlayer.Position())
|
||||
}) {
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@ func (s *SkinSaver) AddSkin(playerName string, playerID uuid.UUID, playerSkin *p
|
|||
}
|
||||
s.playerNames[playerID] = playerName
|
||||
|
||||
skin := &utils.Skin{playerSkin}
|
||||
skin := &utils.Skin{Skin: playerSkin}
|
||||
if s.OnlyIfHasGeometry && !skin.HaveGeometry() {
|
||||
return "", nil, false
|
||||
}
|
||||
|
|
|
@ -74,7 +74,6 @@ func (c *InteractiveCLI) Start(ctx context.Context, cancel context.CancelFunc) e
|
|||
flag.Parse()
|
||||
|
||||
InitDNS()
|
||||
InitExtraDebug(ctx)
|
||||
|
||||
subcommands.Execute(ctx)
|
||||
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/bedrock-tool/bedrocktool/locale"
|
||||
"github.com/bedrock-tool/bedrocktool/utils/crypt"
|
||||
"github.com/fatih/color"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
|
@ -182,52 +184,87 @@ func DumpStruct(data interface{}) {
|
|||
var ClientAddr net.Addr
|
||||
var pool = packet.NewPool()
|
||||
|
||||
func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||
var pk packet.Packet
|
||||
if pkFunc, ok := pool[header.PacketID]; ok {
|
||||
pk = pkFunc()
|
||||
} else {
|
||||
pk = &packet.Unknown{PacketID: header.PacketID, Payload: payload}
|
||||
}
|
||||
func NewDebugLogger(extraVerbose bool) *ProxyHandler {
|
||||
var logPlain, logCrypt, logCryptEnc io.WriteCloser
|
||||
var packetsLogF *bufio.Writer
|
||||
|
||||
defer func() {
|
||||
if recoveredErr := recover(); recoveredErr != nil {
|
||||
logrus.Errorf("%T: %s", pk, recoveredErr.(error))
|
||||
if extraVerbose {
|
||||
// open plain text log
|
||||
logPlain, err := os.Create("packets.log")
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
pk.Marshal(protocol.NewReader(bytes.NewBuffer(payload), 0))
|
||||
|
||||
if FLog != nil {
|
||||
dmpLock.Lock()
|
||||
FLog.Write([]byte(dmpStruct(0, pk, true, false) + "\n\n\n"))
|
||||
dmpLock.Unlock()
|
||||
}
|
||||
|
||||
pkName := reflect.TypeOf(pk).String()[1:]
|
||||
if slices.Contains(MutedPackets, pkName) {
|
||||
return
|
||||
}
|
||||
|
||||
switch pk := pk.(type) {
|
||||
case *packet.Disconnect:
|
||||
logrus.Infof(locale.Loc("disconnect", locale.Strmap{"Pk": pk}))
|
||||
}
|
||||
|
||||
dirS2C := color.GreenString("S") + "->" + color.CyanString("C")
|
||||
dirC2S := color.CyanString("C") + "->" + color.GreenString("S")
|
||||
var dir string = dirS2C
|
||||
|
||||
if ClientAddr != nil {
|
||||
if src == ClientAddr {
|
||||
dir = dirC2S
|
||||
}
|
||||
} else {
|
||||
srcAddr, _, _ := net.SplitHostPort(src.String())
|
||||
if IPPrivate(net.ParseIP(srcAddr)) {
|
||||
dir = dirS2C
|
||||
// open gpg log
|
||||
logCrypt, err := os.Create("packets.log.gpg")
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
} else {
|
||||
// encrypter for the log
|
||||
logCryptEnc, err = crypt.Encer("packets.log", logCrypt)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
packetsLogF = bufio.NewWriter(io.MultiWriter(logPlain, logCryptEnc))
|
||||
}
|
||||
|
||||
logrus.Debugf("%s 0x%02x, %s", dir, pk.ID(), pkName)
|
||||
return &ProxyHandler{
|
||||
Name: "Debug",
|
||||
PacketFunc: func(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||
var pk packet.Packet
|
||||
if pkFunc, ok := pool[header.PacketID]; ok {
|
||||
pk = pkFunc()
|
||||
} else {
|
||||
pk = &packet.Unknown{PacketID: header.PacketID, Payload: payload}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if recoveredErr := recover(); recoveredErr != nil {
|
||||
logrus.Errorf("%T: %s", pk, recoveredErr.(error))
|
||||
}
|
||||
}()
|
||||
pk.Marshal(protocol.NewReader(bytes.NewBuffer(payload), 0))
|
||||
|
||||
if extraVerbose {
|
||||
dmpLock.Lock()
|
||||
packetsLogF.Write([]byte(dmpStruct(0, pk, true, false) + "\n\n\n"))
|
||||
dmpLock.Unlock()
|
||||
}
|
||||
|
||||
pkName := reflect.TypeOf(pk).String()[1:]
|
||||
if !slices.Contains(MutedPackets, pkName) {
|
||||
dirS2C := color.GreenString("S") + "->" + color.CyanString("C")
|
||||
dirC2S := color.CyanString("C") + "->" + color.GreenString("S")
|
||||
var dir string = dirS2C
|
||||
|
||||
if ClientAddr != nil {
|
||||
if src == ClientAddr {
|
||||
dir = dirC2S
|
||||
}
|
||||
} else {
|
||||
srcAddr, _, _ := net.SplitHostPort(src.String())
|
||||
if IPPrivate(net.ParseIP(srcAddr)) {
|
||||
dir = dirS2C
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("%s 0x%02x, %s", dir, pk.ID(), pkName)
|
||||
}
|
||||
},
|
||||
OnEnd: func() {
|
||||
if packetsLogF != nil {
|
||||
packetsLogF.Flush()
|
||||
}
|
||||
if logPlain != nil {
|
||||
logPlain.Close()
|
||||
}
|
||||
if logCryptEnc != nil {
|
||||
logCryptEnc.Close()
|
||||
}
|
||||
if logCrypt != nil {
|
||||
logCrypt.Close()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,10 @@ type ProxyHandler struct {
|
|||
Name string
|
||||
ProxyRef func(*ProxyContext)
|
||||
//
|
||||
AddressAndName func(address, name string) error
|
||||
AddressAndName func(address, hostname string) error
|
||||
|
||||
// called to change game data
|
||||
GameDataModifier func(*minecraft.GameData)
|
||||
|
||||
// called for every packet
|
||||
PacketFunc func(header packet.Header, payload []byte, src, dst net.Addr)
|
||||
|
@ -85,9 +88,6 @@ type ProxyContext struct {
|
|||
CustomClientData *login.ClientData
|
||||
|
||||
handlers []*ProxyHandler
|
||||
|
||||
// called to change game data
|
||||
GameDataModifier func(*minecraft.GameData)
|
||||
}
|
||||
|
||||
func NewProxy() (*ProxyContext, error) {
|
||||
|
@ -284,6 +284,10 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
|||
}
|
||||
}
|
||||
|
||||
if Options.Debug || Options.ExtraDebug {
|
||||
p.AddHandler(NewDebugLogger(Options.ExtraDebug))
|
||||
}
|
||||
|
||||
if strings.HasPrefix(serverAddress, "PCAP!") {
|
||||
return createReplayConnection(ctx, serverAddress[5:], p)
|
||||
}
|
||||
|
@ -373,8 +377,10 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
|||
defer p.Server.Close()
|
||||
|
||||
gd := p.Server.GameData()
|
||||
if p.GameDataModifier != nil {
|
||||
p.GameDataModifier(&gd)
|
||||
for _, handler := range p.handlers {
|
||||
if handler.GameDataModifier != nil {
|
||||
handler.GameDataModifier(&gd)
|
||||
}
|
||||
}
|
||||
|
||||
// spawn and start the game
|
||||
|
@ -427,14 +433,16 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
|||
|
||||
if len(wantSecondary) > 0 {
|
||||
go func() {
|
||||
c, err := p.Listener.Accept()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
c, err := p.Listener.Accept()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, handler := range wantSecondary {
|
||||
go handler.SecondaryClientCB(c.(*minecraft.Conn))
|
||||
for _, handler := range wantSecondary {
|
||||
go handler.SecondaryClientCB(c.(*minecraft.Conn))
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
|
@ -141,10 +141,6 @@ func createReplayConnection(ctx context.Context, filename string, proxy *ProxyCo
|
|||
dst = client
|
||||
}
|
||||
|
||||
if Options.Debug {
|
||||
PacketLogger(hdr, f.Bytes(), src, dst)
|
||||
}
|
||||
|
||||
for _, handler := range proxy.handlers {
|
||||
if handler.PacketFunc != nil {
|
||||
handler.PacketFunc(hdr, f.Bytes(), src, dst)
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
|
@ -18,7 +16,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/bedrock-tool/bedrocktool/locale"
|
||||
"github.com/bedrock-tool/bedrocktool/utils/crypt"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -72,10 +69,6 @@ func connectServer(ctx context.Context, address string, ClientData *login.Client
|
|||
if header.PacketID == packet.IDRequestNetworkSettings {
|
||||
ClientAddr = src
|
||||
}
|
||||
|
||||
if Options.Debug {
|
||||
PacketLogger(header, payload, src, dst)
|
||||
}
|
||||
if packetFunc != nil {
|
||||
packetFunc(header, payload, src, dst)
|
||||
}
|
||||
|
@ -174,50 +167,3 @@ func CfbDecrypt(data []byte, key []byte) []byte {
|
|||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func InitExtraDebug(ctx context.Context) {
|
||||
if !Options.ExtraDebug {
|
||||
return
|
||||
}
|
||||
Options.Debug = true
|
||||
|
||||
var logPlain, logCryptEnc io.WriteCloser = nil, nil
|
||||
|
||||
// open plain text log
|
||||
logPlain, err := os.Create("packets.log")
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
// open gpg log
|
||||
logCrypt, err := os.Create("packets.log.gpg")
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
} else {
|
||||
// encrypter for the log
|
||||
logCryptEnc, err = crypt.Encer("packets.log", logCrypt)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
b := bufio.NewWriter(io.MultiWriter(logPlain, logCryptEnc))
|
||||
FLog = b
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
b.Flush()
|
||||
|
||||
if logPlain != nil {
|
||||
logPlain.Close()
|
||||
}
|
||||
if logCrypt != nil {
|
||||
logCrypt.Close()
|
||||
}
|
||||
if logCryptEnc != nil {
|
||||
logCryptEnc.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue