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=
|
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 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
|
||||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
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 h1:qlGjFzXukp9IgVQl32cz4PosbiFEnwXa2EpDbwddHS8=
|
||||||
github.com/TeaEntityLab/fpGo/v2 v2.3.2/go.mod h1:b06fRNLSnNiUwfSskBC3f3cocA4mAC2iySdtaP/T9uA=
|
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=
|
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/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 h1:/G0ghZwrhou0Wq21qc1vXXMm/t/aKWkALWwITptKbE0=
|
||||||
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9/go.mod h1:TOk10ahXejq9wkEaym3KPRNeuR/h5Jx+s8QRWIa2oTM=
|
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 h1:5WefVJLglY4IHRqOQmh6Ao6wkJYaJkarshKU8VUtId4=
|
||||||
github.com/changkun/lockfree v0.0.1/go.mod h1:3bKiaXn/iNzIPlSvSOMSVbRQUQtAp8qUAyBUtzU11s4=
|
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=
|
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/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 h1:Q/e+gNyyHaxKAyfdbBqvip3DxhVWH453R+kthvSr9Mk=
|
||||||
github.com/repeale/fp-go v0.11.1/go.mod h1:4KrwQJB1VRY+06CA+jTc4baZetr6o2PeuqnKr5ybQUc=
|
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 h1:LuxslTBxJrrNeKfqoywIERWWhH43TgiVAiPEVlhgNBA=
|
||||||
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49/go.mod h1:fY313ZGG810aWruFYcyq3coFpHDrWJVoMfSRI81y1r4=
|
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=
|
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/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 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
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.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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (w *worldsServer) processChangeDimension(pk *packet.ChangeDimension) {
|
func (w *worldsHandler) processChangeDimension(pk *packet.ChangeDimension) {
|
||||||
if len(w.worldState.chunks) > 0 {
|
if len(w.worldState.chunks) > 0 {
|
||||||
w.SaveAndReset()
|
w.SaveAndReset()
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,13 +18,14 @@ func (w *worldsServer) processChangeDimension(pk *packet.ChangeDimension) {
|
||||||
w.Reset(w.CurrentName())
|
w.Reset(w.CurrentName())
|
||||||
}
|
}
|
||||||
dimensionID := pk.Dimension
|
dimensionID := pk.Dimension
|
||||||
if w.serverState.ispre118 {
|
if w.serverState.ispre118 && dimensionID == 0 {
|
||||||
dimensionID += 10
|
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
|
// ignore empty chunks THANKS WEIRD SERVER SOFTWARE DEVS
|
||||||
if len(pk.RawPayload) == 0 {
|
if len(pk.RawPayload) == 0 {
|
||||||
logrus.Info(locale.Loc("empty_chunk", nil))
|
logrus.Info(locale.Loc("empty_chunk", nil))
|
||||||
|
@ -41,7 +42,7 @@ func (w *worldsServer) processLevelChunk(pk *packet.LevelChunk) {
|
||||||
subChunkCount = int(pk.SubChunkCount)
|
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 {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -53,21 +54,19 @@ func (w *worldsServer) processLevelChunk(pk *packet.LevelChunk) {
|
||||||
}
|
}
|
||||||
w.worldState.chunks[pk.Position] = ch
|
w.worldState.chunks[pk.Position] = ch
|
||||||
|
|
||||||
max := w.worldState.Dim.Range().Height() / 16
|
max := w.worldState.dimension.Range().Height() / 16
|
||||||
switch pk.SubChunkCount {
|
switch pk.SubChunkCount {
|
||||||
case protocol.SubChunkRequestModeLimited:
|
case protocol.SubChunkRequestModeLimited:
|
||||||
max = int(pk.HighestSubChunk)
|
max = int(pk.HighestSubChunk)
|
||||||
fallthrough
|
fallthrough
|
||||||
case protocol.SubChunkRequestModeLimitless:
|
case protocol.SubChunkRequestModeLimitless:
|
||||||
var offsetTable []protocol.SubChunkOffset
|
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++ {
|
for y := int8(r.Min() / 16); y < int8(r.Max()); y++ {
|
||||||
offsetTable = append(offsetTable, protocol.SubChunkOffset{0, y, 0})
|
offsetTable = append(offsetTable, protocol.SubChunkOffset{0, y, 0})
|
||||||
}
|
}
|
||||||
|
|
||||||
dimId, ok := world.DimensionID(w.worldState.Dim)
|
dimId, _ := world.DimensionID(w.worldState.dimension)
|
||||||
_ = ok
|
|
||||||
|
|
||||||
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
|
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
|
||||||
Dimension: int32(dimId),
|
Dimension: int32(dimId),
|
||||||
Position: protocol.SubChunkPos{
|
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)
|
posToRedraw := make(map[protocol.ChunkPos]bool)
|
||||||
|
|
||||||
for _, sub := range pk.SubChunkEntries {
|
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)
|
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) {
|
switch pk := pk.(type) {
|
||||||
case *packet.ChangeDimension:
|
case *packet.ChangeDimension:
|
||||||
w.processChangeDimension(pk)
|
w.processChangeDimension(pk)
|
||||||
case *packet.LevelChunk:
|
case *packet.LevelChunk:
|
||||||
w.processLevelChunk(pk)
|
w.processLevelChunk(pk)
|
||||||
|
w.proxy.SendPopup(locale.Locm("popup_chunk_count", locale.Strmap{
|
||||||
w.proxy.SendPopup(locale.Locm("popup_chunk_count", locale.Strmap{"Count": len(w.worldState.chunks), "Name": w.worldState.Name}, len(w.worldState.chunks)))
|
"Count": len(w.worldState.chunks),
|
||||||
|
"Name": w.worldState.Name,
|
||||||
|
}, len(w.worldState.chunks)))
|
||||||
case *packet.SubChunk:
|
case *packet.SubChunk:
|
||||||
w.processSubChunk(pk)
|
w.processSubChunk(pk)
|
||||||
case *packet.BlockActorData:
|
case *packet.BlockActorData:
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (e serverEntity) Type() world.EntityType {
|
||||||
return e.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]
|
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||||
if !ok {
|
if !ok {
|
||||||
e = &entityState{
|
e = &entityState{
|
||||||
|
@ -141,47 +141,49 @@ func entityMetadataToNBT(metadata protocol.EntityMetadata, nbt map[string]any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagNoAI) {
|
if _, ok := metadata[protocol.EntityDataKeyFlags]; ok {
|
||||||
nbt["IsAutonomous"] = false
|
if metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagNoAI) {
|
||||||
}
|
nbt["IsAutonomous"] = false
|
||||||
for k, v := range flagNames {
|
}
|
||||||
nbt[v] = metadata.Flag(protocol.EntityDataKeyFlags, k)
|
for k, v := range flagNames {
|
||||||
}
|
nbt[v] = metadata.Flag(protocol.EntityDataKeyFlags, k)
|
||||||
|
}
|
||||||
|
|
||||||
AlwaysShowName := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagAlwaysShowName)
|
AlwaysShowName := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagAlwaysShowName)
|
||||||
if AlwaysShowName {
|
if AlwaysShowName {
|
||||||
nbt["CustomNameVisible"] = true
|
nbt["CustomNameVisible"] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
type effect struct {
|
type effect struct {
|
||||||
Id byte
|
Id byte
|
||||||
Amplifier byte
|
Amplifier byte
|
||||||
Duration int32
|
Duration int32
|
||||||
DurationEasy int32
|
DurationEasy int32
|
||||||
DurationNormal int32
|
DurationNormal int32
|
||||||
DurationHard int32
|
DurationHard int32
|
||||||
Ambient bool
|
Ambient bool
|
||||||
ShowParticles bool
|
ShowParticles bool
|
||||||
DisplayOnScreenTextureAnimation bool
|
DisplayOnScreenTextureAnimation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
activeEffects := []effect{}
|
activeEffects := []effect{}
|
||||||
addEffect := func(id int, showParticles bool) {
|
addEffect := func(id int, showParticles bool) {
|
||||||
activeEffects = append(activeEffects, effect{
|
activeEffects = append(activeEffects, effect{
|
||||||
Id: byte(id),
|
Id: byte(id),
|
||||||
Amplifier: 1,
|
Amplifier: 1,
|
||||||
Duration: 10000000,
|
Duration: 10000000,
|
||||||
ShowParticles: false,
|
ShowParticles: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
invisible := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagInvisible)
|
invisible := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagInvisible)
|
||||||
if invisible {
|
if invisible {
|
||||||
addEffect(packet.EffectInvisibility, false)
|
addEffect(packet.EffectInvisibility, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(activeEffects) > 0 {
|
if len(activeEffects) > 0 {
|
||||||
nbt["ActiveEffects"] = activeEffects
|
nbt["ActiveEffects"] = activeEffects
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +216,7 @@ func (s *entityState) ToServerEntity() serverEntity {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldsServer) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
func (w *worldsHandler) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
||||||
switch pk := pk.(type) {
|
switch pk := pk.(type) {
|
||||||
case *packet.AddActor:
|
case *packet.AddActor:
|
||||||
w.processAddActor(pk)
|
w.processAddActor(pk)
|
||||||
|
|
|
@ -17,7 +17,7 @@ type itemContainer struct {
|
||||||
Content *packet.InventoryContent
|
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) {
|
switch pk := pk.(type) {
|
||||||
case *packet.ContainerOpen:
|
case *packet.ContainerOpen:
|
||||||
// add to open containers
|
// add to open containers
|
||||||
|
@ -116,7 +116,7 @@ func (w *worldsServer) processItemPacketsServer(pk packet.Packet) packet.Packet
|
||||||
return pk
|
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) {
|
switch pk := pk.(type) {
|
||||||
case *packet.ItemStackRequest:
|
case *packet.ItemStackRequest:
|
||||||
var requests []protocol.ItemStackRequest
|
var requests []protocol.ItemStackRequest
|
||||||
|
@ -187,7 +187,7 @@ func stackToItem(it protocol.ItemStack) item.Stack {
|
||||||
return nbtconv.ReadItem(it.NBTData, &s)
|
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{
|
ret = map[string]any{
|
||||||
"format_version": "1.12.0",
|
"format_version": "1.12.0",
|
||||||
"identifier": "minecraft:player",
|
"identifier": "minecraft:player",
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
"github.com/bedrock-tool/bedrocktool/locale"
|
||||||
"github.com/bedrock-tool/bedrocktool/ui/messages"
|
"github.com/bedrock-tool/bedrocktool/ui/messages"
|
||||||
"github.com/bedrock-tool/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
"github.com/go-gl/mathgl/mgl32"
|
||||||
"golang.design/x/lockfree"
|
"golang.design/x/lockfree"
|
||||||
|
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||||
|
@ -79,10 +80,10 @@ type MapUI struct {
|
||||||
l sync.RWMutex
|
l sync.RWMutex
|
||||||
|
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
w *worldsServer
|
w *worldsHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMapUI(w *worldsServer) *MapUI {
|
func NewMapUI(w *worldsHandler) *MapUI {
|
||||||
m := &MapUI{
|
m := &MapUI{
|
||||||
img: image.NewRGBA(image.Rect(0, 0, 128, 128)),
|
img: image.NewRGBA(image.Rect(0, 0, 128, 128)),
|
||||||
zoomLevel: 16,
|
zoomLevel: 16,
|
||||||
|
@ -265,14 +266,29 @@ func (m *MapUI) SetChunk(pos protocol.ChunkPos, ch *chunk.Chunk, complete bool)
|
||||||
m.SchedRedraw()
|
m.SchedRedraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldsServer) ProcessAnimate(pk *packet.Animate) {
|
func (w *worldsHandler) ProcessAnimate(pk *packet.Animate) {
|
||||||
if pk.ActionType == packet.AnimateActionSwingArm {
|
if pk.ActionType == packet.AnimateActionSwingArm {
|
||||||
w.mapUI.ChangeZoom()
|
w.mapUI.ChangeZoom()
|
||||||
w.proxy.SendPopup(locale.Loc("zoom_level", locale.Strmap{"Level": w.mapUI.zoomLevel}))
|
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) {
|
switch pk := pk.(type) {
|
||||||
case *packet.MovePlayer:
|
case *packet.MovePlayer:
|
||||||
w.SetPlayerPos(pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
|
w.SetPlayerPos(pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
|
||||||
|
|
|
@ -41,7 +41,7 @@ type TPlayerPos struct {
|
||||||
|
|
||||||
// the state used for drawing and saving
|
// the state used for drawing and saving
|
||||||
|
|
||||||
type worldSettings struct {
|
type WorldSettings struct {
|
||||||
// settings
|
// settings
|
||||||
voidGen bool
|
voidGen bool
|
||||||
withPacks bool
|
withPacks bool
|
||||||
|
@ -50,7 +50,7 @@ type worldSettings struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type worldState struct {
|
type worldState struct {
|
||||||
Dim world.Dimension
|
dimension world.Dimension
|
||||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||||
blockNBT map[protocol.SubChunkPos][]map[string]any
|
blockNBT map[protocol.SubChunkPos][]map[string]any
|
||||||
entities map[uint64]*entityState
|
entities map[uint64]*entityState
|
||||||
|
@ -69,7 +69,7 @@ type serverState struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type worldsServer struct {
|
type worldsHandler struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
proxy *utils.ProxyContext
|
proxy *utils.ProxyContext
|
||||||
mapUI *MapUI
|
mapUI *MapUI
|
||||||
|
@ -78,53 +78,10 @@ type worldsServer struct {
|
||||||
|
|
||||||
worldState worldState
|
worldState worldState
|
||||||
serverState serverState
|
serverState serverState
|
||||||
settings worldSettings
|
settings WorldSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorldsServer(ctx context.Context, proxy *utils.ProxyContext, ServerName string, ui utils.UI) *worldsServer {
|
var black16x16 = image.NewRGBA(image.Rect(0, 0, 16, 16))
|
||||||
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))
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for i := 3; i < len(black16x16.Pix); i += 4 {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w := NewWorldsServer(ctx, proxy, hostname, ui)
|
proxy.AlwaysGetPacks = true
|
||||||
w.settings = worldSettings{
|
proxy.AddHandler(NewWorldsHandler(ctx, ui, WorldSettings{
|
||||||
voidGen: c.EnableVoid,
|
voidGen: c.EnableVoid,
|
||||||
withPacks: c.Packs,
|
withPacks: c.Packs,
|
||||||
saveImage: c.SaveImage,
|
saveImage: c.SaveImage,
|
||||||
}
|
}))
|
||||||
|
|
||||||
proxy.AlwaysGetPacks = true
|
ui.Message(messages.SetUIState(messages.UIStateConnect))
|
||||||
proxy.GameDataModifier = func(gd *minecraft.GameData) {
|
err = proxy.Run(ctx, serverAddress, hostname)
|
||||||
gd.ClientSideGeneration = false
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
ui.Message(messages.SetUIState(messages.UIStateFinished))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
proxy.AddHandler(&utils.ProxyHandler{
|
func NewWorldsHandler(ctx context.Context, ui utils.UI, settings WorldSettings) *utils.ProxyHandler {
|
||||||
Name: "Worlds",
|
w := &worldsHandler{
|
||||||
ConnectCB: w.OnConnect,
|
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) {
|
OnClientConnect: func(conn *minecraft.Conn) {
|
||||||
w.gui.Message(messages.SetUIState(messages.UIStateConnecting))
|
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) {
|
PacketCB: func(pk packet.Packet, toServer bool, timeReceived time.Time) (packet.Packet, error) {
|
||||||
forward := true
|
forward := true
|
||||||
|
|
||||||
|
@ -203,34 +223,13 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||||
}
|
}
|
||||||
return pk, nil
|
return pk, nil
|
||||||
},
|
},
|
||||||
})
|
OnEnd: func() {
|
||||||
|
w.SaveAndReset()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldsServer) setVoidGen(val bool, fromUI bool) bool {
|
func (w *worldsHandler) setVoidGen(val bool, fromUI bool) bool {
|
||||||
w.settings.voidGen = val
|
w.settings.voidGen = val
|
||||||
var s = locale.Loc("void_generator_false", nil)
|
var s = locale.Loc("void_generator_false", nil)
|
||||||
if w.settings.voidGen {
|
if w.settings.voidGen {
|
||||||
|
@ -247,7 +246,7 @@ func (w *worldsServer) setVoidGen(val bool, fromUI bool) bool {
|
||||||
return true
|
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.worldState.Name = val
|
||||||
w.proxy.SendMessage(locale.Loc("worldname_set", locale.Strmap{"Name": w.worldState.Name}))
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldsServer) CurrentName() string {
|
func (w *worldsHandler) CurrentName() string {
|
||||||
worldName := "world"
|
worldName := "world"
|
||||||
if w.serverState.worldCounter > 1 {
|
if w.serverState.worldCounter > 1 {
|
||||||
worldName = fmt.Sprintf("world-%d", w.serverState.worldCounter)
|
worldName = fmt.Sprintf("world-%d", w.serverState.worldCounter)
|
||||||
|
@ -268,9 +267,9 @@ func (w *worldsServer) CurrentName() string {
|
||||||
return worldName
|
return worldName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldsServer) Reset(newName string) {
|
func (w *worldsHandler) Reset(newName string) {
|
||||||
w.worldState = worldState{
|
w.worldState = worldState{
|
||||||
Dim: nil,
|
dimension: nil,
|
||||||
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
||||||
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
||||||
entities: make(map[uint64]*entityState),
|
entities: make(map[uint64]*entityState),
|
||||||
|
@ -280,23 +279,63 @@ func (w *worldsServer) Reset(newName string) {
|
||||||
w.mapUI.Reset()
|
w.mapUI.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveAndReset writes the world to a folder, resets all the chunks
|
func (w *worldState) cullChunks() {
|
||||||
func (w *worldsServer) SaveAndReset() {
|
keys := make([]protocol.ChunkPos, 0, len(w.chunks))
|
||||||
|
for cp := range w.chunks {
|
||||||
// cull empty chunks
|
|
||||||
keys := make([]protocol.ChunkPos, 0, len(w.worldState.chunks))
|
|
||||||
for cp := range w.worldState.chunks {
|
|
||||||
keys = append(keys, cp)
|
keys = append(keys, cp)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cp := range fp.Filter(func(cp protocol.ChunkPos) bool {
|
for _, cp := range fp.Filter(func(cp protocol.ChunkPos) bool {
|
||||||
return !fp.Some(func(sc *chunk.SubChunk) bool {
|
return !fp.Some(func(sc *chunk.SubChunk) bool {
|
||||||
return !sc.Empty()
|
return !sc.Empty()
|
||||||
})(w.worldState.chunks[cp].Sub())
|
})(w.chunks[cp].Sub())
|
||||||
})(keys) {
|
})(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 {
|
if len(w.worldState.chunks) == 0 {
|
||||||
w.Reset(w.CurrentName())
|
w.Reset(w.CurrentName())
|
||||||
return
|
return
|
||||||
|
@ -312,42 +351,10 @@ func (w *worldsServer) SaveAndReset() {
|
||||||
folder := path.Join("worlds", fmt.Sprintf("%s/%s", w.serverState.Name, w.worldState.Name))
|
folder := path.Join("worlds", fmt.Sprintf("%s/%s", w.serverState.Name, w.worldState.Name))
|
||||||
os.RemoveAll(folder)
|
os.RemoveAll(folder)
|
||||||
os.MkdirAll(folder, 0o777)
|
os.MkdirAll(folder, 0o777)
|
||||||
|
provider, err := w.worldState.Save(folder)
|
||||||
provider, err := mcdb.New(logrus.StandardLogger(), folder, opt.DefaultCompression)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Error(err)
|
||||||
}
|
return
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = provider.SaveLocalPlayerData(w.playerData())
|
err = provider.SaveLocalPlayerData(w.playerData())
|
||||||
|
@ -366,6 +373,7 @@ func (w *worldsServer) SaveAndReset() {
|
||||||
// set gamerules
|
// set gamerules
|
||||||
ld := provider.LevelDat()
|
ld := provider.LevelDat()
|
||||||
gd := w.proxy.Server.GameData()
|
gd := w.proxy.Server.GameData()
|
||||||
|
ld.RandomSeed = int64(gd.WorldSeed)
|
||||||
for _, gr := range gd.GameRules {
|
for _, gr := range gd.GameRules {
|
||||||
switch gr.Name {
|
switch gr.Name {
|
||||||
case "commandblockoutput":
|
case "commandblockoutput":
|
||||||
|
@ -434,8 +442,6 @@ func (w *worldsServer) SaveAndReset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ld.RandomSeed = int64(gd.WorldSeed)
|
|
||||||
|
|
||||||
// void world
|
// void world
|
||||||
if w.settings.voidGen {
|
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}`
|
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))
|
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))
|
w.gui.Message(messages.SetUIState(messages.UIStateMain))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -592,40 +597,14 @@ func (w *worldsServer) OnConnect(err error) bool {
|
||||||
dimensionID := gd.Dimension
|
dimensionID := gd.Dimension
|
||||||
if w.serverState.ispre118 {
|
if w.serverState.ispre118 {
|
||||||
logrus.Info(locale.Loc("using_under_118", nil))
|
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.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()
|
w.mapUI.Start()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,6 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
|
||||||
go func() {
|
go func() {
|
||||||
defer p.Router.Wg.Done()
|
defer p.Router.Wg.Done()
|
||||||
utils.InitDNS()
|
utils.InitDNS()
|
||||||
utils.InitExtraDebug(p.Router.Ctx)
|
|
||||||
|
|
||||||
err := cmd.Execute(p.Router.Ctx, utils.CurrentUI)
|
err := cmd.Execute(p.Router.Ctx, utils.CurrentUI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -28,12 +28,12 @@ func dumpPacket(f io.WriteCloser, toServer bool, payload []byte) {
|
||||||
f.Write([]byte{0xBB, 0xBB, 0xBB, 0xBB})
|
f.Write([]byte{0xBB, 0xBB, 0xBB, 0xBB})
|
||||||
}
|
}
|
||||||
|
|
||||||
type PacketCapturer struct {
|
type packetCapturer struct {
|
||||||
proxy *utils.ProxyContext
|
proxy *utils.ProxyContext
|
||||||
fio *os.File
|
fio *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PacketCapturer) AddressAndName(address, hostname string) error {
|
func (p *packetCapturer) AddressAndName(address, hostname string) error {
|
||||||
os.Mkdir("captures", 0o775)
|
os.Mkdir("captures", 0o775)
|
||||||
fio, err := os.Create(fmt.Sprintf("captures/%s-%s.pcap2", hostname, time.Now().Format("2006-01-02_15-04-05")))
|
fio, err := os.Create(fmt.Sprintf("captures/%s-%s.pcap2", hostname, time.Now().Format("2006-01-02_15-04-05")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -44,7 +44,7 @@ func (p *PacketCapturer) AddressAndName(address, hostname string) error {
|
||||||
return nil
|
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()
|
IsfromClient := utils.ClientAddr.String() == src.String()
|
||||||
|
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
|
@ -54,14 +54,14 @@ func (p *PacketCapturer) PacketFunc(header packet.Header, payload []byte, src, d
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketCapturer() *utils.ProxyHandler {
|
func NewPacketCapturer() *utils.ProxyHandler {
|
||||||
p := &PacketCapturer{}
|
p := &packetCapturer{}
|
||||||
return &utils.ProxyHandler{
|
return &utils.ProxyHandler{
|
||||||
Name: "Packet Capturer",
|
Name: "Packet Capturer",
|
||||||
ProxyRef: func(pc *utils.ProxyContext) {
|
ProxyRef: func(pc *utils.ProxyContext) {
|
||||||
p.proxy = pc
|
p.proxy = pc
|
||||||
},
|
},
|
||||||
PacketFunc: p.PacketFunc,
|
|
||||||
AddressAndName: p.AddressAndName,
|
AddressAndName: p.AddressAndName,
|
||||||
|
PacketFunc: p.PacketFunc,
|
||||||
OnEnd: func() {
|
OnEnd: func() {
|
||||||
p.fio.Close()
|
p.fio.Close()
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,22 +10,12 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChatLogger struct {
|
type chatLogger struct {
|
||||||
Verbose bool
|
Verbose bool
|
||||||
fio *os.File
|
fio *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatLogger) AddressAndName(address, hostname string) error {
|
func (c *chatLogger) PacketCB(pk packet.Packet, toServer bool, t time.Time) (packet.Packet, 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) {
|
|
||||||
if text, ok := pk.(*packet.Text); ok {
|
if text, ok := pk.(*packet.Text); ok {
|
||||||
logLine := text.Message
|
logLine := text.Message
|
||||||
if c.Verbose {
|
if c.Verbose {
|
||||||
|
@ -42,13 +32,21 @@ func (c *ChatLogger) PacketCB(pk packet.Packet, toServer bool, t time.Time) (pac
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChatLogger() *utils.ProxyHandler {
|
func NewChatLogger() *utils.ProxyHandler {
|
||||||
p := &ChatLogger{}
|
c := &chatLogger{}
|
||||||
return &utils.ProxyHandler{
|
return &utils.ProxyHandler{
|
||||||
Name: "Packet Capturer",
|
Name: "Packet Capturer",
|
||||||
PacketCB: p.PacketCB,
|
PacketCB: c.PacketCB,
|
||||||
AddressAndName: p.AddressAndName,
|
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() {
|
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
|
s.playerNames[playerID] = playerName
|
||||||
|
|
||||||
skin := &utils.Skin{playerSkin}
|
skin := &utils.Skin{Skin: playerSkin}
|
||||||
if s.OnlyIfHasGeometry && !skin.HaveGeometry() {
|
if s.OnlyIfHasGeometry && !skin.HaveGeometry() {
|
||||||
return "", nil, false
|
return "", nil, false
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,6 @@ func (c *InteractiveCLI) Start(ctx context.Context, cancel context.CancelFunc) e
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
InitDNS()
|
InitDNS()
|
||||||
InitExtraDebug(ctx)
|
|
||||||
|
|
||||||
subcommands.Execute(ctx)
|
subcommands.Execute(ctx)
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
"github.com/bedrock-tool/bedrocktool/utils/crypt"
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
|
@ -182,52 +184,87 @@ func DumpStruct(data interface{}) {
|
||||||
var ClientAddr net.Addr
|
var ClientAddr net.Addr
|
||||||
var pool = packet.NewPool()
|
var pool = packet.NewPool()
|
||||||
|
|
||||||
func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
func NewDebugLogger(extraVerbose bool) *ProxyHandler {
|
||||||
var pk packet.Packet
|
var logPlain, logCrypt, logCryptEnc io.WriteCloser
|
||||||
if pkFunc, ok := pool[header.PacketID]; ok {
|
var packetsLogF *bufio.Writer
|
||||||
pk = pkFunc()
|
|
||||||
} else {
|
|
||||||
pk = &packet.Unknown{PacketID: header.PacketID, Payload: payload}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
if extraVerbose {
|
||||||
if recoveredErr := recover(); recoveredErr != nil {
|
// open plain text log
|
||||||
logrus.Errorf("%T: %s", pk, recoveredErr.(error))
|
logPlain, err := os.Create("packets.log")
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
|
||||||
pk.Marshal(protocol.NewReader(bytes.NewBuffer(payload), 0))
|
// open gpg log
|
||||||
|
logCrypt, err := os.Create("packets.log.gpg")
|
||||||
if FLog != nil {
|
if err != nil {
|
||||||
dmpLock.Lock()
|
logrus.Error(err)
|
||||||
FLog.Write([]byte(dmpStruct(0, pk, true, false) + "\n\n\n"))
|
} else {
|
||||||
dmpLock.Unlock()
|
// encrypter for the log
|
||||||
}
|
logCryptEnc, err = crypt.Encer("packets.log", logCrypt)
|
||||||
|
if err != nil {
|
||||||
pkName := reflect.TypeOf(pk).String()[1:]
|
logrus.Error(err)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
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
|
Name string
|
||||||
ProxyRef func(*ProxyContext)
|
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
|
// called for every packet
|
||||||
PacketFunc func(header packet.Header, payload []byte, src, dst net.Addr)
|
PacketFunc func(header packet.Header, payload []byte, src, dst net.Addr)
|
||||||
|
@ -85,9 +88,6 @@ type ProxyContext struct {
|
||||||
CustomClientData *login.ClientData
|
CustomClientData *login.ClientData
|
||||||
|
|
||||||
handlers []*ProxyHandler
|
handlers []*ProxyHandler
|
||||||
|
|
||||||
// called to change game data
|
|
||||||
GameDataModifier func(*minecraft.GameData)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxy() (*ProxyContext, error) {
|
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!") {
|
if strings.HasPrefix(serverAddress, "PCAP!") {
|
||||||
return createReplayConnection(ctx, serverAddress[5:], p)
|
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()
|
defer p.Server.Close()
|
||||||
|
|
||||||
gd := p.Server.GameData()
|
gd := p.Server.GameData()
|
||||||
if p.GameDataModifier != nil {
|
for _, handler := range p.handlers {
|
||||||
p.GameDataModifier(&gd)
|
if handler.GameDataModifier != nil {
|
||||||
|
handler.GameDataModifier(&gd)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// spawn and start the game
|
// spawn and start the game
|
||||||
|
@ -427,14 +433,16 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
||||||
|
|
||||||
if len(wantSecondary) > 0 {
|
if len(wantSecondary) > 0 {
|
||||||
go func() {
|
go func() {
|
||||||
c, err := p.Listener.Accept()
|
for {
|
||||||
if err != nil {
|
c, err := p.Listener.Accept()
|
||||||
logrus.Error(err)
|
if err != nil {
|
||||||
return
|
logrus.Error(err)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, handler := range wantSecondary {
|
for _, handler := range wantSecondary {
|
||||||
go handler.SecondaryClientCB(c.(*minecraft.Conn))
|
go handler.SecondaryClientCB(c.(*minecraft.Conn))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,10 +141,6 @@ func createReplayConnection(ctx context.Context, filename string, proxy *ProxyCo
|
||||||
dst = client
|
dst = client
|
||||||
}
|
}
|
||||||
|
|
||||||
if Options.Debug {
|
|
||||||
PacketLogger(hdr, f.Bytes(), src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, handler := range proxy.handlers {
|
for _, handler := range proxy.handlers {
|
||||||
if handler.PacketFunc != nil {
|
if handler.PacketFunc != nil {
|
||||||
handler.PacketFunc(hdr, f.Bytes(), src, dst)
|
handler.PacketFunc(hdr, f.Bytes(), src, dst)
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -18,7 +16,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
"github.com/bedrock-tool/bedrocktool/locale"
|
||||||
"github.com/bedrock-tool/bedrocktool/utils/crypt"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/sandertv/gophertunnel/minecraft"
|
"github.com/sandertv/gophertunnel/minecraft"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -72,10 +69,6 @@ func connectServer(ctx context.Context, address string, ClientData *login.Client
|
||||||
if header.PacketID == packet.IDRequestNetworkSettings {
|
if header.PacketID == packet.IDRequestNetworkSettings {
|
||||||
ClientAddr = src
|
ClientAddr = src
|
||||||
}
|
}
|
||||||
|
|
||||||
if Options.Debug {
|
|
||||||
PacketLogger(header, payload, src, dst)
|
|
||||||
}
|
|
||||||
if packetFunc != nil {
|
if packetFunc != nil {
|
||||||
packetFunc(header, payload, src, dst)
|
packetFunc(header, payload, src, dst)
|
||||||
}
|
}
|
||||||
|
@ -174,50 +167,3 @@ func CfbDecrypt(data []byte, key []byte) []byte {
|
||||||
}
|
}
|
||||||
return data
|
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