performance optimizations
This commit is contained in:
parent
d3a8219d99
commit
1e990d7fcb
|
@ -41,6 +41,15 @@ func (c *CLI) Start(ctx context.Context, cancel context.CancelFunc) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
/*
|
||||
cf, _ := os.Create("cpu.pprof")
|
||||
err := pprof.StartCPUProfile(cf)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
*/
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logrus.Errorf(locale.Loc("fatal_error", nil))
|
||||
|
|
5
go.mod
5
go.mod
|
@ -6,7 +6,7 @@ go 1.20
|
|||
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.28.1-1
|
||||
|
||||
//replace github.com/df-mc/dragonfly => ./dragonfly
|
||||
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.3-10
|
||||
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.4-3
|
||||
|
||||
//replace gioui.org => ./gio
|
||||
replace gioui.org => github.com/olebeck/gio v0.0.0-20230321105529-d424f1a59af9
|
||||
|
@ -15,7 +15,7 @@ require (
|
|||
gioui.org v0.0.0-20230323230841-d7b1c7c33b33
|
||||
gioui.org/x v0.0.0-20230313161557-05b40af72ed0
|
||||
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
|
||||
github.com/df-mc/dragonfly v0.9.3
|
||||
github.com/df-mc/dragonfly v0.9.4
|
||||
github.com/df-mc/goleveldb v1.1.9
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/flytam/filenamify v1.1.2
|
||||
|
@ -48,6 +48,7 @@ require (
|
|||
github.com/changkun/lockfree v0.0.1 // indirect
|
||||
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect
|
||||
github.com/df-mc/atomic v1.10.0 // indirect
|
||||
github.com/df-mc/worldupgrader v1.0.3 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-text/typesetting v0.0.0-20221214153724-0399769901d5 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
|
|
6
go.sum
6
go.sum
|
@ -30,6 +30,8 @@ github.com/df-mc/atomic v1.10.0 h1:0ZuxBKwR/hxcFGorKiHIp+hY7hgY+XBTzhCYD2NqSEg=
|
|||
github.com/df-mc/atomic v1.10.0/go.mod h1:Gw9rf+rPIbydMjA329Jn4yjd/O2c/qusw3iNp4tFGSc=
|
||||
github.com/df-mc/goleveldb v1.1.9 h1:ihdosZyy5jkQKrxucTQmN90jq/2lUwQnJZjIYIC/9YU=
|
||||
github.com/df-mc/goleveldb v1.1.9/go.mod h1:+NHCup03Sci5q84APIA21z3iPZCuk6m6ABtg4nANCSk=
|
||||
github.com/df-mc/worldupgrader v1.0.3 h1:3nbthy6vfSNQZdqHBR+E5Fh3mCeWmCwLtqrYDiPUG5I=
|
||||
github.com/df-mc/worldupgrader v1.0.3/go.mod h1:6ybkJ/BV9b0XkcPzcLmvgT9Nv/xgBXdDQTmRhu7b8zQ=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/flytam/filenamify v1.1.2 h1:dGlfWU4zrhDlsmvob4IFcfgjG5vIjfo4UwLyec6Wx94=
|
||||
|
@ -83,6 +85,10 @@ github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYo
|
|||
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
||||
github.com/olebeck/dragonfly v0.9.3-10 h1:USruaK+8c3gsX9CtDzInLbwsdoZxcYjmnC8t/H4/Zjw=
|
||||
github.com/olebeck/dragonfly v0.9.3-10/go.mod h1:nnnmYWgSTNQb9x33nBthqN/2vyHlUaijfo+e2y3W5j4=
|
||||
github.com/olebeck/dragonfly v0.9.4-1 h1:AvP0JALUJqkDBTCT/7tOrIndKIrIol1rX6XFcbOwpLI=
|
||||
github.com/olebeck/dragonfly v0.9.4-1/go.mod h1:Iu46xugbkTQ9CcUj+zPC4VvKP94CmxxLGtW8pHgAPr4=
|
||||
github.com/olebeck/dragonfly v0.9.4-2 h1:e1bzsTxcPMaUUs2B6wnCbc1FE96XcdBbL7mp1LE92NI=
|
||||
github.com/olebeck/dragonfly v0.9.4-2/go.mod h1:k8OQvjmfj+JbrwQf1qHfMETlFHOp0WJLjILN+QVqh+c=
|
||||
github.com/olebeck/gio v0.0.0-20230321105529-d424f1a59af9 h1:TqDsMHwjW5ZYfh+RE8ussT62m0qXqo+QjzSXb7BCVA4=
|
||||
github.com/olebeck/gio v0.0.0-20230321105529-d424f1a59af9/go.mod h1:+W1Kpf96YcfissZocFqIp6O42FDTuphkObbEybp+Ffc=
|
||||
github.com/olebeck/gophertunnel v1.28.1-1 h1:bw2jeMz94YHF5qQYhq1Yq/6fALkklGu7k26YbPI4DSs=
|
||||
|
|
|
@ -3,7 +3,6 @@ package subcommands
|
|||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"strings"
|
||||
|
||||
"github.com/bedrock-tool/bedrocktool/locale"
|
||||
"github.com/bedrock-tool/bedrocktool/utils"
|
||||
|
@ -11,14 +10,12 @@ import (
|
|||
|
||||
type DebugProxyCMD struct {
|
||||
ServerAddress string
|
||||
Filter string
|
||||
}
|
||||
|
||||
func (*DebugProxyCMD) Name() string { return "debug-proxy" }
|
||||
func (*DebugProxyCMD) Synopsis() string { return locale.Loc("debug_proxy_synopsis", nil) }
|
||||
func (c *DebugProxyCMD) SetFlags(f *flag.FlagSet) {
|
||||
f.StringVar(&c.ServerAddress, "address", "", locale.Loc("remote_address", nil))
|
||||
f.StringVar(&c.Filter, "filter", "", locale.Loc("packet_filter", nil))
|
||||
}
|
||||
|
||||
func (c *DebugProxyCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||
|
@ -29,27 +26,11 @@ func (c *DebugProxyCMD) Execute(ctx context.Context, ui utils.UI) error {
|
|||
|
||||
utils.Options.Debug = true
|
||||
|
||||
filters := strings.Split(c.Filter, ",")
|
||||
if len(filters) > 0 {
|
||||
for _, v := range filters {
|
||||
if len(v) == 0 {
|
||||
continue
|
||||
}
|
||||
if string(v[0]) == "*" {
|
||||
v = v[1:]
|
||||
}
|
||||
v = strings.TrimPrefix(v, "packet.")
|
||||
v = "packet." + v
|
||||
utils.ExtraVerbose = append(utils.ExtraVerbose, v)
|
||||
}
|
||||
}
|
||||
|
||||
proxy, err := utils.NewProxy()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = proxy.Run(ctx, address)
|
||||
return err
|
||||
return proxy.Run(ctx, address)
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
Binary file not shown.
|
@ -9,21 +9,21 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (w *WorldState) processChangeDimension(pk *packet.ChangeDimension) {
|
||||
if len(w.chunks) > 0 {
|
||||
func (w *worldsServer) processChangeDimension(pk *packet.ChangeDimension) {
|
||||
if len(w.worldState.chunks) > 0 {
|
||||
w.SaveAndReset()
|
||||
} else {
|
||||
logrus.Info(locale.Loc("not_saving_empty", nil))
|
||||
w.Reset()
|
||||
w.Reset(w.CurrentName())
|
||||
}
|
||||
dimensionID := pk.Dimension
|
||||
if w.ispre118 {
|
||||
if w.serverState.ispre118 {
|
||||
dimensionID += 10
|
||||
}
|
||||
w.Dim = dimensionIDMap[uint8(dimensionID)]
|
||||
w.worldState.Dim = dimensionIDMap[uint8(dimensionID)]
|
||||
}
|
||||
|
||||
func (w *WorldState) processLevelChunk(pk *packet.LevelChunk) {
|
||||
func (w *worldsServer) processLevelChunk(pk *packet.LevelChunk) {
|
||||
// ignore empty chunks THANKS WEIRD SERVER SOFTWARE DEVS
|
||||
if len(pk.RawPayload) == 0 {
|
||||
logrus.Info(locale.Loc("empty_chunk", nil))
|
||||
|
@ -40,32 +40,35 @@ func (w *WorldState) processLevelChunk(pk *packet.LevelChunk) {
|
|||
subChunkCount = int(pk.SubChunkCount)
|
||||
}
|
||||
|
||||
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, w.Dim.Range(), w.ispre118, w.bp.HasBlocks())
|
||||
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, w.worldState.Dim.Range(), w.serverState.ispre118, w.bp.HasBlocks())
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
if blockNBTs != nil {
|
||||
w.blockNBT[protocol.SubChunkPos{
|
||||
w.worldState.blockNBT[protocol.SubChunkPos{
|
||||
pk.Position.X(), 0, pk.Position.Z(),
|
||||
}] = blockNBTs
|
||||
}
|
||||
w.chunks[pk.Position] = ch
|
||||
w.worldState.chunks[pk.Position] = ch
|
||||
|
||||
max := w.Dim.Range().Height() / 16
|
||||
max := w.worldState.Dim.Range().Height() / 16
|
||||
switch pk.SubChunkCount {
|
||||
case protocol.SubChunkRequestModeLimited:
|
||||
max = int(pk.HighestSubChunk)
|
||||
fallthrough
|
||||
case protocol.SubChunkRequestModeLimitless:
|
||||
var offsetTable []protocol.SubChunkOffset
|
||||
r := w.Dim.Range()
|
||||
r := w.worldState.Dim.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
|
||||
|
||||
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
|
||||
Dimension: int32(w.Dim.EncodeDimension()),
|
||||
Dimension: int32(dimId),
|
||||
Position: protocol.SubChunkPos{
|
||||
pk.Position.X(), 0, pk.Position.Z(),
|
||||
},
|
||||
|
@ -86,7 +89,7 @@ func (w *WorldState) processLevelChunk(pk *packet.LevelChunk) {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *WorldState) processSubChunk(pk *packet.SubChunk) {
|
||||
func (w *worldsServer) processSubChunk(pk *packet.SubChunk) {
|
||||
posToRedraw := make(map[protocol.ChunkPos]bool)
|
||||
|
||||
for _, sub := range pk.SubChunkEntries {
|
||||
|
@ -97,7 +100,7 @@ func (w *WorldState) processSubChunk(pk *packet.SubChunk) {
|
|||
subPos = protocol.SubChunkPos{absX, absY, absZ}
|
||||
pos = protocol.ChunkPos{absX, absZ}
|
||||
)
|
||||
ch, ok := w.chunks[pos]
|
||||
ch, ok := w.worldState.chunks[pos]
|
||||
if !ok {
|
||||
logrus.Error(locale.Loc("subchunk_before_chunk", nil))
|
||||
continue
|
||||
|
@ -107,7 +110,7 @@ func (w *WorldState) processSubChunk(pk *packet.SubChunk) {
|
|||
logrus.Error(err)
|
||||
}
|
||||
if blockNBT != nil {
|
||||
w.blockNBT[subPos] = blockNBT
|
||||
w.worldState.blockNBT[subPos] = blockNBT
|
||||
}
|
||||
|
||||
posToRedraw[pos] = true
|
||||
|
@ -115,7 +118,7 @@ func (w *WorldState) processSubChunk(pk *packet.SubChunk) {
|
|||
|
||||
// redraw the chunks
|
||||
for pos := range posToRedraw {
|
||||
w.mapUI.SetChunk(pos, w.chunks[pos], true)
|
||||
w.mapUI.SetChunk(pos, w.worldState.chunks[pos], true)
|
||||
}
|
||||
w.mapUI.SchedRedraw()
|
||||
}
|
||||
|
@ -124,22 +127,22 @@ func blockPosInChunk(pos protocol.BlockPos) (uint8, int16, uint8) {
|
|||
return uint8(pos.X() & 0x0f), int16(pos.Y() & 0x0f), uint8(pos.Z() & 0x0f)
|
||||
}
|
||||
|
||||
func (w *WorldState) ProcessChunkPackets(pk packet.Packet) packet.Packet {
|
||||
func (w *worldsServer) 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.chunks), "Name": w.WorldName}, len(w.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:
|
||||
if w.blockUpdates {
|
||||
if w.settings.blockUpdates {
|
||||
sp := protocol.SubChunkPos{pk.Position.X() << 4, 0, pk.Position.Z() << 4}
|
||||
b, ok := w.blockNBT[sp]
|
||||
b, ok := w.worldState.blockNBT[sp]
|
||||
if !ok {
|
||||
w.blockNBT[sp] = []map[string]any{pk.NBTData}
|
||||
w.worldState.blockNBT[sp] = []map[string]any{pk.NBTData}
|
||||
} else {
|
||||
for i, v := range b {
|
||||
x, y, z := v["x"].(int32), v["y"].(int32), v["z"].(int32)
|
||||
|
@ -151,19 +154,19 @@ func (w *WorldState) ProcessChunkPackets(pk packet.Packet) packet.Packet {
|
|||
}
|
||||
}
|
||||
case *packet.UpdateBlock:
|
||||
if w.blockUpdates {
|
||||
if w.settings.blockUpdates {
|
||||
cp := protocol.ChunkPos{pk.Position.X() >> 4, pk.Position.Z() >> 4}
|
||||
c, ok := w.chunks[cp]
|
||||
c, ok := w.worldState.chunks[cp]
|
||||
if ok {
|
||||
x, y, z := blockPosInChunk(pk.Position)
|
||||
c.SetBlock(x, y, z, uint8(pk.Layer), pk.NewBlockRuntimeID)
|
||||
w.mapUI.SetChunk(cp, w.chunks[cp], true)
|
||||
w.mapUI.SetChunk(cp, w.worldState.chunks[cp], true)
|
||||
}
|
||||
}
|
||||
case *packet.UpdateSubChunkBlocks:
|
||||
if w.blockUpdates {
|
||||
if w.settings.blockUpdates {
|
||||
cp := protocol.ChunkPos{pk.Position.X(), pk.Position.Z()}
|
||||
c, ok := w.chunks[cp]
|
||||
c, ok := w.worldState.chunks[cp]
|
||||
if ok {
|
||||
for _, bce := range pk.Blocks {
|
||||
x, y, z := blockPosInChunk(bce.BlockPos)
|
||||
|
@ -173,7 +176,7 @@ func (w *WorldState) ProcessChunkPackets(pk packet.Packet) packet.Packet {
|
|||
c.SetBlock(x, y, z, 0, bce.BlockRuntimeID)
|
||||
}
|
||||
}
|
||||
w.mapUI.SetChunk(cp, w.chunks[cp], true)
|
||||
w.mapUI.SetChunk(cp, w.worldState.chunks[cp], true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 432 B |
|
@ -3,6 +3,7 @@ package world_test
|
|||
import (
|
||||
"image/png"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"testing"
|
||||
|
||||
"github.com/bedrock-tool/bedrocktool/subcommands/world"
|
||||
|
@ -21,19 +22,32 @@ func Test(t *testing.T) {
|
|||
|
||||
func Benchmark_chunk_decode(b *testing.B) {
|
||||
data, _ := os.ReadFile("chunk.bin")
|
||||
|
||||
cf, _ := os.Create("cpu.pprof")
|
||||
err := pprof.StartCPUProfile(cf)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, err := chunk.NetworkDecode(33, data, 6, cube.Range{0, 255}, true, false)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
func Benchmark_render_chunk(b *testing.B) {
|
||||
data, _ := os.ReadFile("chunk.bin")
|
||||
ch, _, _ := chunk.NetworkDecode(33, data, 6, cube.Range{0, 255}, true, false)
|
||||
|
||||
cf, _ := os.Create("cpu.pprof")
|
||||
err := pprof.StartCPUProfile(cf)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
world.Chunk2Img(ch, true)
|
||||
}
|
||||
pprof.StopCPUProfile()
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@ func (e serverEntity) Type() world.EntityType {
|
|||
return e.EntityType
|
||||
}
|
||||
|
||||
func (w *WorldState) processAddActor(pk *packet.AddActor) {
|
||||
e, ok := w.entities[pk.EntityRuntimeID]
|
||||
func (w *worldsServer) processAddActor(pk *packet.AddActor) {
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if !ok {
|
||||
e = &entityState{
|
||||
RuntimeID: pk.EntityRuntimeID,
|
||||
|
@ -71,7 +71,7 @@ func (w *WorldState) processAddActor(pk *packet.AddActor) {
|
|||
Inventory: make(map[byte]map[byte]protocol.ItemInstance),
|
||||
Metadata: make(map[uint32]any),
|
||||
}
|
||||
w.entities[pk.EntityRuntimeID] = e
|
||||
w.worldState.entities[pk.EntityRuntimeID] = e
|
||||
|
||||
w.bp.AddEntity(behaviourpack.EntityIn{
|
||||
Identifier: pk.EntityType,
|
||||
|
@ -211,25 +211,25 @@ func (s *entityState) ToServerEntity() serverEntity {
|
|||
return e
|
||||
}
|
||||
|
||||
func (w *WorldState) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
||||
func (w *worldsServer) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.AddActor:
|
||||
w.processAddActor(pk)
|
||||
case *packet.RemoveActor:
|
||||
case *packet.SetActorData:
|
||||
e, ok := w.entities[pk.EntityRuntimeID]
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if ok {
|
||||
for k, v := range pk.EntityMetadata {
|
||||
e.Metadata[k] = v
|
||||
}
|
||||
}
|
||||
case *packet.SetActorMotion:
|
||||
e, ok := w.entities[pk.EntityRuntimeID]
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if ok {
|
||||
e.Velocity = pk.Velocity
|
||||
}
|
||||
case *packet.MoveActorDelta:
|
||||
e, ok := w.entities[pk.EntityRuntimeID]
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if ok {
|
||||
if pk.Flags&packet.MoveActorDeltaFlagHasX != 0 {
|
||||
e.Position[0] = pk.Position[0]
|
||||
|
@ -251,14 +251,14 @@ func (w *WorldState) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
|||
//}
|
||||
}
|
||||
case *packet.MoveActorAbsolute:
|
||||
e, ok := w.entities[pk.EntityRuntimeID]
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if ok {
|
||||
e.Position = pk.Position
|
||||
e.Pitch = pk.Rotation.X()
|
||||
e.Yaw = pk.Rotation.Y()
|
||||
}
|
||||
case *packet.MobEquipment:
|
||||
e, ok := w.entities[pk.EntityRuntimeID]
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if ok {
|
||||
w, ok := e.Inventory[pk.WindowID]
|
||||
if !ok {
|
||||
|
@ -268,7 +268,7 @@ func (w *WorldState) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
|||
w[pk.HotBarSlot] = pk.NewItem
|
||||
}
|
||||
case *packet.MobArmourEquipment:
|
||||
e, ok := w.entities[pk.EntityRuntimeID]
|
||||
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
||||
if ok {
|
||||
e.Helmet = &pk.Helmet
|
||||
e.Chestplate = &pk.Chestplate
|
||||
|
|
|
@ -17,25 +17,25 @@ type itemContainer struct {
|
|||
Content *packet.InventoryContent
|
||||
}
|
||||
|
||||
func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
||||
func (w *worldsServer) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.ContainerOpen:
|
||||
// add to open containers
|
||||
existing, ok := w.openItemContainers[pk.WindowID]
|
||||
existing, ok := w.worldState.openItemContainers[pk.WindowID]
|
||||
if !ok {
|
||||
existing = &itemContainer{}
|
||||
}
|
||||
w.openItemContainers[pk.WindowID] = &itemContainer{
|
||||
w.worldState.openItemContainers[pk.WindowID] = &itemContainer{
|
||||
OpenPacket: pk,
|
||||
Content: existing.Content,
|
||||
}
|
||||
|
||||
case *packet.InventoryContent:
|
||||
if pk.WindowID == 0x0 { // inventory
|
||||
w.playerInventory = pk.Content
|
||||
w.serverState.playerInventory = pk.Content
|
||||
} else {
|
||||
// save content
|
||||
existing, ok := w.openItemContainers[byte(pk.WindowID)]
|
||||
existing, ok := w.worldState.openItemContainers[byte(pk.WindowID)]
|
||||
if ok {
|
||||
existing.Content = pk
|
||||
}
|
||||
|
@ -43,10 +43,10 @@ func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
|||
|
||||
case *packet.InventorySlot:
|
||||
if pk.WindowID == 0x0 {
|
||||
w.playerInventory[pk.Slot] = pk.NewItem
|
||||
w.serverState.playerInventory[pk.Slot] = pk.NewItem
|
||||
} else {
|
||||
// save content
|
||||
existing, ok := w.openItemContainers[byte(pk.WindowID)]
|
||||
existing, ok := w.worldState.openItemContainers[byte(pk.WindowID)]
|
||||
if ok {
|
||||
existing.Content.Content[pk.Slot] = pk.NewItem
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
|||
|
||||
case *packet.ContainerClose:
|
||||
// find container info
|
||||
existing, ok := w.openItemContainers[byte(pk.WindowID)]
|
||||
existing, ok := w.worldState.openItemContainers[byte(pk.WindowID)]
|
||||
|
||||
switch pk.WindowID {
|
||||
case protocol.WindowIDArmour: // todo handle
|
||||
|
@ -88,11 +88,11 @@ func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
|||
}
|
||||
|
||||
// put into subchunk
|
||||
nbts := w.blockNBT[cp]
|
||||
nbts := w.worldState.blockNBT[cp]
|
||||
for i, v := range nbts {
|
||||
NBTPos := protocol.BlockPos{v["x"].(int32), v["y"].(int32), v["z"].(int32)}
|
||||
if NBTPos == pos {
|
||||
w.blockNBT[cp][i]["Items"] = nbtconv.InvToNBT(inv)
|
||||
w.worldState.blockNBT[cp][i]["Items"] = nbtconv.InvToNBT(inv)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
|||
w.proxy.SendMessage(locale.Loc("saved_block_inv", nil))
|
||||
|
||||
// remove it again
|
||||
delete(w.openItemContainers, byte(pk.WindowID))
|
||||
delete(w.worldState.openItemContainers, byte(pk.WindowID))
|
||||
}
|
||||
|
||||
case *packet.ItemComponent:
|
||||
|
@ -113,7 +113,7 @@ func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
|||
return pk
|
||||
}
|
||||
|
||||
func (w *WorldState) processItemPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
|
||||
func (w *worldsServer) processItemPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
|
||||
switch pk := pk.(type) {
|
||||
case *packet.ItemStackRequest:
|
||||
var requests []protocol.ItemStackRequest
|
||||
|
@ -184,15 +184,15 @@ func stackToItem(it protocol.ItemStack) item.Stack {
|
|||
return nbtconv.ReadItem(it.NBTData, &s)
|
||||
}
|
||||
|
||||
func (w *WorldState) playerData() (ret map[string]any) {
|
||||
func (w *worldsServer) playerData() (ret map[string]any) {
|
||||
ret = map[string]any{
|
||||
"format_version": "1.12.0",
|
||||
"identifier": "minecraft:player",
|
||||
}
|
||||
|
||||
if len(w.playerInventory) > 0 {
|
||||
inv := inventory.New(len(w.playerInventory), nil)
|
||||
for i, ii := range w.playerInventory {
|
||||
if len(w.serverState.playerInventory) > 0 {
|
||||
inv := inventory.New(len(w.serverState.playerInventory), nil)
|
||||
for i, ii := range w.serverState.playerInventory {
|
||||
inv.SetItem(i, stackToItem(ii.Stack))
|
||||
}
|
||||
ret["Inventory"] = nbtconv.InvToNBT(inv)
|
||||
|
@ -373,8 +373,8 @@ func (w *WorldState) playerData() (ret map[string]any) {
|
|||
}
|
||||
|
||||
ret["Rotation"] = []float32{
|
||||
w.PlayerPos.Pitch,
|
||||
w.PlayerPos.Yaw,
|
||||
w.serverState.PlayerPos.Pitch,
|
||||
w.serverState.PlayerPos.Yaw,
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
@ -79,10 +79,10 @@ type MapUI struct {
|
|||
l sync.RWMutex
|
||||
|
||||
ticker *time.Ticker
|
||||
w *WorldState
|
||||
w *worldsServer
|
||||
}
|
||||
|
||||
func NewMapUI(w *WorldState) *MapUI {
|
||||
func NewMapUI(w *worldsServer) *MapUI {
|
||||
m := &MapUI{
|
||||
img: image.NewRGBA(image.Rect(0, 0, 128, 128)),
|
||||
zoomLevel: 16,
|
||||
|
@ -198,8 +198,8 @@ func (m *MapUI) Redraw() {
|
|||
m.l.Unlock()
|
||||
|
||||
middle := protocol.ChunkPos{
|
||||
int32(m.w.PlayerPos.Position.X()),
|
||||
int32(m.w.PlayerPos.Position.Z()),
|
||||
int32(m.w.serverState.PlayerPos.Position.X()),
|
||||
int32(m.w.serverState.PlayerPos.Position.Z()),
|
||||
}
|
||||
|
||||
chunksPerLine := float64(128 / m.zoomLevel)
|
||||
|
@ -227,7 +227,7 @@ func (m *MapUI) Redraw() {
|
|||
min, max := m.GetBounds()
|
||||
m.w.gui.Message(messages.UpdateMap, messages.UpdateMapPayload{
|
||||
ChunkCount: len(m.renderedChunks),
|
||||
Rotation: m.w.PlayerPos.Yaw,
|
||||
Rotation: m.w.serverState.PlayerPos.Yaw,
|
||||
UpdatedTiles: updatedChunks,
|
||||
Tiles: m.renderedChunks,
|
||||
BoundsMin: min,
|
||||
|
@ -265,14 +265,14 @@ func (m *MapUI) SetChunk(pos protocol.ChunkPos, ch *chunk.Chunk, complete bool)
|
|||
m.SchedRedraw()
|
||||
}
|
||||
|
||||
func (w *WorldState) ProcessAnimate(pk *packet.Animate) {
|
||||
func (w *worldsServer) 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 *WorldState) processMapPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
|
||||
func (w *worldsServer) 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)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package world
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
|
@ -41,53 +40,69 @@ type TPlayerPos struct {
|
|||
|
||||
// the state used for drawing and saving
|
||||
|
||||
type WorldState struct {
|
||||
type worldSettings struct {
|
||||
// settings
|
||||
voidGen bool
|
||||
withPacks bool
|
||||
saveImage bool
|
||||
blockUpdates bool
|
||||
}
|
||||
|
||||
type worldState struct {
|
||||
Dim world.Dimension
|
||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||
blockNBT map[protocol.SubChunkPos][]map[string]any
|
||||
entities map[uint64]*entityState
|
||||
openItemContainers map[byte]*itemContainer
|
||||
Name string
|
||||
}
|
||||
|
||||
type serverState struct {
|
||||
ChunkRadius int
|
||||
ispre118 bool
|
||||
worldCounter int
|
||||
|
||||
playerInventory []protocol.ItemInstance
|
||||
PlayerPos TPlayerPos
|
||||
|
||||
Name string
|
||||
}
|
||||
|
||||
type worldsServer struct {
|
||||
ctx context.Context
|
||||
proxy *utils.ProxyContext
|
||||
mapUI *MapUI
|
||||
gui utils.UI
|
||||
bp *behaviourpack.BehaviourPack
|
||||
|
||||
// save state
|
||||
ChunkRadius int
|
||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||
blockNBT map[protocol.SubChunkPos][]map[string]any
|
||||
openItemContainers map[byte]*itemContainer
|
||||
playerInventory []protocol.ItemInstance
|
||||
entities map[uint64]*entityState
|
||||
Dim world.Dimension
|
||||
PlayerPos TPlayerPos
|
||||
worldCounter int
|
||||
WorldName string
|
||||
ServerName string
|
||||
ispre118 bool
|
||||
|
||||
// settings
|
||||
voidGen bool
|
||||
withPacks bool
|
||||
saveImage bool
|
||||
experimentInventory bool
|
||||
blockUpdates bool
|
||||
worldState worldState
|
||||
serverState serverState
|
||||
settings worldSettings
|
||||
}
|
||||
|
||||
func NewWorldState(ctx context.Context, proxy *utils.ProxyContext, ServerName string, ui utils.UI) *WorldState {
|
||||
w := &WorldState{
|
||||
ctx: ctx,
|
||||
proxy: proxy,
|
||||
mapUI: nil,
|
||||
gui: ui,
|
||||
bp: behaviourpack.New(ServerName),
|
||||
ServerName: ServerName,
|
||||
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),
|
||||
|
||||
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
||||
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
||||
openItemContainers: make(map[byte]*itemContainer),
|
||||
entities: make(map[uint64]*entityState),
|
||||
Dim: nil,
|
||||
WorldName: "world",
|
||||
PlayerPos: TPlayerPos{},
|
||||
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, messages.InitPayload{
|
||||
Handler: w.uiMessage,
|
||||
|
@ -118,11 +133,10 @@ func init() {
|
|||
}
|
||||
|
||||
type WorldCMD struct {
|
||||
ServerAddress string
|
||||
Packs bool
|
||||
EnableVoid bool
|
||||
SaveImage bool
|
||||
ExperimentInventory bool
|
||||
ServerAddress string
|
||||
Packs bool
|
||||
EnableVoid bool
|
||||
SaveImage bool
|
||||
}
|
||||
|
||||
func (*WorldCMD) Name() string { return "worlds" }
|
||||
|
@ -133,7 +147,6 @@ func (c *WorldCMD) SetFlags(f *flag.FlagSet) {
|
|||
f.BoolVar(&c.Packs, "packs", false, locale.Loc("save_packs_with_world", nil))
|
||||
f.BoolVar(&c.EnableVoid, "void", true, locale.Loc("enable_void", nil))
|
||||
f.BoolVar(&c.SaveImage, "image", false, locale.Loc("save_image", nil))
|
||||
f.BoolVar(&c.ExperimentInventory, "inv", false, locale.Loc("test_block_inv", nil))
|
||||
}
|
||||
|
||||
func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||
|
@ -147,11 +160,12 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
|||
return err
|
||||
}
|
||||
|
||||
w := NewWorldState(ctx, proxy, hostname, ui)
|
||||
w.voidGen = c.EnableVoid
|
||||
w.withPacks = c.Packs
|
||||
w.saveImage = c.SaveImage
|
||||
w.experimentInventory = c.ExperimentInventory
|
||||
w := NewWorldsServer(ctx, proxy, hostname, ui)
|
||||
w.settings = worldSettings{
|
||||
voidGen: c.EnableVoid,
|
||||
withPacks: c.Packs,
|
||||
saveImage: c.SaveImage,
|
||||
}
|
||||
|
||||
proxy.AlwaysGetPacks = true
|
||||
proxy.GameDataModifier = func(gd *minecraft.GameData) {
|
||||
|
@ -172,7 +186,7 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
|||
// from server
|
||||
switch pk := pk.(type) {
|
||||
case *packet.ChunkRadiusUpdated:
|
||||
w.ChunkRadius = int(pk.ChunkRadius)
|
||||
w.serverState.ChunkRadius = int(pk.ChunkRadius)
|
||||
pk.ChunkRadius = 80
|
||||
}
|
||||
pk = w.processItemPacketsServer(pk)
|
||||
|
@ -196,7 +210,7 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *WorldState) uiMessage(name string, data interface{}) messages.MessageResponse {
|
||||
func (w *worldsServer) uiMessage(name string, data interface{}) messages.MessageResponse {
|
||||
r := messages.MessageResponse{
|
||||
Ok: false,
|
||||
Data: nil,
|
||||
|
@ -212,24 +226,25 @@ func (w *WorldState) uiMessage(name string, data interface{}) messages.MessageRe
|
|||
return r
|
||||
}
|
||||
|
||||
func (w *WorldState) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
|
||||
last := w.PlayerPos
|
||||
w.PlayerPos = TPlayerPos{
|
||||
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(w.PlayerPos.Position.X()) || int(last.Position.Z()) != int(w.PlayerPos.Position.Z()) {
|
||||
if int(last.Position.X()) != int(current.Position.X()) || int(last.Position.Z()) != int(current.Position.Z()) {
|
||||
w.mapUI.SchedRedraw()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WorldState) setVoidGen(val bool, fromUI bool) bool {
|
||||
w.voidGen = val
|
||||
func (w *worldsServer) setVoidGen(val bool, fromUI bool) bool {
|
||||
w.settings.voidGen = val
|
||||
var s string
|
||||
if w.voidGen {
|
||||
if w.settings.voidGen {
|
||||
s = locale.Loc("void_generator_true", nil)
|
||||
} else {
|
||||
s = locale.Loc("void_generator_false", nil)
|
||||
|
@ -238,68 +253,79 @@ func (w *WorldState) setVoidGen(val bool, fromUI bool) bool {
|
|||
|
||||
if !fromUI {
|
||||
w.gui.Message(messages.SetVoidGen, messages.SetVoidGenPayload{
|
||||
Value: w.voidGen,
|
||||
Value: w.settings.voidGen,
|
||||
})
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *WorldState) setWorldName(val string, fromUI bool) bool {
|
||||
w.WorldName = val
|
||||
w.proxy.SendMessage(locale.Loc("worldname_set", locale.Strmap{"Name": w.WorldName}))
|
||||
func (w *worldsServer) setWorldName(val string, fromUI bool) bool {
|
||||
w.worldState.Name = val
|
||||
w.proxy.SendMessage(locale.Loc("worldname_set", locale.Strmap{"Name": w.worldState.Name}))
|
||||
|
||||
if !fromUI {
|
||||
w.gui.Message(messages.SetWorldName, messages.SetWorldNamePayload{
|
||||
WorldName: w.WorldName,
|
||||
WorldName: w.worldState.Name,
|
||||
})
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *WorldState) Reset() {
|
||||
w.chunks = make(map[protocol.ChunkPos]*chunk.Chunk)
|
||||
w.entities = make(map[uint64]*entityState)
|
||||
w.blockNBT = make(map[protocol.SubChunkPos][]map[string]any)
|
||||
w.openItemContainers = make(map[byte]*itemContainer)
|
||||
w.WorldName = fmt.Sprintf("world-%d", w.worldCounter)
|
||||
func (w *worldsServer) CurrentName() string {
|
||||
worldName := "world"
|
||||
if w.serverState.worldCounter > 1 {
|
||||
worldName = fmt.Sprintf("world-%d", w.serverState.worldCounter)
|
||||
}
|
||||
return worldName
|
||||
}
|
||||
|
||||
func (w *worldsServer) Reset(newName string) {
|
||||
w.worldState = worldState{
|
||||
Dim: nil,
|
||||
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
||||
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
||||
entities: make(map[uint64]*entityState),
|
||||
openItemContainers: make(map[byte]*itemContainer),
|
||||
Name: newName,
|
||||
}
|
||||
w.mapUI.Reset()
|
||||
}
|
||||
|
||||
// SaveAndReset writes the world to a folder, resets all the chunks
|
||||
func (w *WorldState) SaveAndReset() {
|
||||
func (w *worldsServer) SaveAndReset() {
|
||||
|
||||
// cull empty chunks
|
||||
keys := make([]protocol.ChunkPos, 0, len(w.chunks))
|
||||
for cp := range w.chunks {
|
||||
keys := make([]protocol.ChunkPos, 0, len(w.worldState.chunks))
|
||||
for cp := range w.worldState.chunks {
|
||||
keys = append(keys, cp)
|
||||
}
|
||||
for _, cp := range keys {
|
||||
has_any := false
|
||||
for _, sc := range w.chunks[cp].Sub() {
|
||||
for _, sc := range w.worldState.chunks[cp].Sub() {
|
||||
has_any = !sc.Empty()
|
||||
if has_any {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !has_any {
|
||||
delete(w.chunks, cp)
|
||||
delete(w.worldState.chunks, cp)
|
||||
}
|
||||
}
|
||||
if len(w.chunks) == 0 {
|
||||
w.Reset()
|
||||
if len(w.worldState.chunks) == 0 {
|
||||
w.Reset(w.CurrentName())
|
||||
return
|
||||
}
|
||||
|
||||
logrus.Infof(locale.Loc("saving_world", locale.Strmap{"Name": w.WorldName, "Count": len(w.chunks)}))
|
||||
logrus.Infof(locale.Loc("saving_world", locale.Strmap{"Name": w.worldState.Name, "Count": len(w.worldState.chunks)}))
|
||||
w.gui.Message(messages.SavingWorld, messages.SavingWorldPayload{
|
||||
Name: w.WorldName,
|
||||
Chunks: len(w.chunks),
|
||||
Name: w.worldState.Name,
|
||||
Chunks: len(w.worldState.chunks),
|
||||
})
|
||||
|
||||
// open world
|
||||
folder := path.Join("worlds", fmt.Sprintf("%s/%s", w.ServerName, w.WorldName))
|
||||
folder := path.Join("worlds", fmt.Sprintf("%s/%s", w.serverState.Name, w.worldState.Name))
|
||||
os.RemoveAll(folder)
|
||||
os.MkdirAll(folder, 0o777)
|
||||
|
||||
|
@ -309,18 +335,18 @@ func (w *WorldState) SaveAndReset() {
|
|||
}
|
||||
|
||||
// save chunk data
|
||||
for cp, c := range w.chunks {
|
||||
provider.SaveChunk((world.ChunkPos)(cp), c, w.Dim)
|
||||
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.blockNBT { // 3d to 2d
|
||||
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.Dim)
|
||||
err = provider.SaveBlockNBT(cp, v, w.worldState.Dim)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
@ -328,30 +354,30 @@ func (w *WorldState) SaveAndReset() {
|
|||
|
||||
// save entities
|
||||
chunkEntities := make(map[world.ChunkPos][]world.Entity)
|
||||
for _, es := range w.entities {
|
||||
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.Dim)
|
||||
err = provider.SaveEntities(cp, v, w.worldState.Dim)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
playerPos := w.proxy.Server.GameData().PlayerPosition
|
||||
spawnPos := cube.Pos{int(playerPos.X()), int(playerPos.Y()), int(playerPos.Z())}
|
||||
|
||||
err = provider.SaveLocalPlayerData(w.playerData())
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
playerPos := w.proxy.Server.GameData().PlayerPosition
|
||||
spawnPos := cube.Pos{int(playerPos.X()), int(playerPos.Y()), int(playerPos.Z())}
|
||||
|
||||
// write metadata
|
||||
s := provider.Settings()
|
||||
s.Spawn = spawnPos
|
||||
s.Name = w.WorldName
|
||||
s.Name = w.worldState.Name
|
||||
|
||||
// set gamerules
|
||||
ld := provider.LevelDat()
|
||||
|
@ -427,7 +453,7 @@ func (w *WorldState) SaveAndReset() {
|
|||
ld.RandomSeed = int64(gd.WorldSeed)
|
||||
|
||||
// void world
|
||||
if w.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.Generator = 2
|
||||
}
|
||||
|
@ -446,7 +472,7 @@ func (w *WorldState) SaveAndReset() {
|
|||
logrus.Error(err)
|
||||
}
|
||||
|
||||
w.worldCounter += 1
|
||||
w.serverState.worldCounter += 1
|
||||
|
||||
type dep struct {
|
||||
PackID string `json:"pack_id"`
|
||||
|
@ -467,7 +493,7 @@ func (w *WorldState) SaveAndReset() {
|
|||
|
||||
// save behaviourpack
|
||||
if w.bp.HasContent() {
|
||||
name := strings.ReplaceAll(w.ServerName, "./", "")
|
||||
name := strings.ReplaceAll(w.serverState.Name, "./", "")
|
||||
name = strings.ReplaceAll(name, "/", "-")
|
||||
packFolder := path.Join(folder, "behavior_packs", name)
|
||||
os.MkdirAll(packFolder, 0o755)
|
||||
|
@ -484,16 +510,16 @@ func (w *WorldState) SaveAndReset() {
|
|||
}})
|
||||
|
||||
// force resource packs for worlds with custom blocks
|
||||
w.withPacks = true
|
||||
w.settings.withPacks = true
|
||||
}
|
||||
|
||||
// add resource packs
|
||||
if w.withPacks {
|
||||
if w.settings.withPacks {
|
||||
packs, err := utils.GetPacks(w.proxy.Server)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
} else {
|
||||
//var rdeps []dep
|
||||
var rdeps []dep
|
||||
for k, p := range packs {
|
||||
if p.Encrypted() && !p.CanDecrypt() {
|
||||
logrus.Warnf("Cant add %s, it is encrypted", p.Name())
|
||||
|
@ -502,17 +528,14 @@ func (w *WorldState) SaveAndReset() {
|
|||
logrus.Infof(locale.Loc("adding_pack", locale.Strmap{"Name": k}))
|
||||
packFolder := path.Join(folder, "resource_packs", p.Name())
|
||||
os.MkdirAll(packFolder, 0o755)
|
||||
data := make([]byte, p.Len())
|
||||
p.ReadAt(data, 0)
|
||||
utils.UnpackZip(bytes.NewReader(data), int64(len(data)), packFolder)
|
||||
utils.UnpackZip(p, int64(p.Len()), packFolder)
|
||||
|
||||
/*
|
||||
rdeps = append(rdeps, dep{
|
||||
PackID: p.Manifest().Header.UUID,
|
||||
Version: p.Manifest().Header.Version,
|
||||
})
|
||||
*/
|
||||
rdeps = append(rdeps, dep{
|
||||
PackID: p.Manifest().Header.UUID,
|
||||
Version: p.Manifest().Header.Version,
|
||||
})
|
||||
}
|
||||
_ = rdeps
|
||||
/*
|
||||
if len(rdeps) > 0 {
|
||||
addPacksJSON("world_resource_packs.json", rdeps)
|
||||
|
@ -521,7 +544,7 @@ func (w *WorldState) SaveAndReset() {
|
|||
}
|
||||
}
|
||||
|
||||
if w.saveImage {
|
||||
if w.settings.saveImage {
|
||||
f, _ := os.Create(folder + ".png")
|
||||
png.Encode(f, w.mapUI.ToImage())
|
||||
f.Close()
|
||||
|
@ -532,25 +555,27 @@ func (w *WorldState) SaveAndReset() {
|
|||
// zip it
|
||||
filename := folder + ".mcworld"
|
||||
if err := utils.ZipFolder(filename, folder); err != nil {
|
||||
fmt.Println(err)
|
||||
logrus.Error(err)
|
||||
}
|
||||
logrus.Info(locale.Loc("saved", locale.Strmap{"Name": filename}))
|
||||
//os.RemoveAll(folder)
|
||||
w.Reset()
|
||||
w.Reset(w.CurrentName())
|
||||
w.gui.Message(messages.SetUIState, messages.UIStateMain)
|
||||
}
|
||||
|
||||
func (w *WorldState) OnConnect(err error) bool {
|
||||
func (w *worldsServer) OnConnect(err error) bool {
|
||||
w.gui.Message(messages.SetUIState, messages.UIStateMain)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
gd := w.proxy.Server.GameData()
|
||||
w.ChunkRadius = int(gd.ChunkRadius)
|
||||
w.serverState.ChunkRadius = int(gd.ChunkRadius)
|
||||
w.proxy.ClientWritePacket(&packet.ChunkRadiusUpdated{
|
||||
ChunkRadius: 80,
|
||||
})
|
||||
|
||||
world.InsertCustomItems(gd.Items)
|
||||
|
||||
for _, ie := range gd.Items {
|
||||
w.bp.AddItem(ie)
|
||||
}
|
||||
|
@ -576,18 +601,18 @@ func (w *WorldState) OnConnect(err error) bool {
|
|||
if len(gv) > 1 {
|
||||
var ver int
|
||||
ver, err = strconv.Atoi(gv[1])
|
||||
w.ispre118 = ver < 18
|
||||
w.serverState.ispre118 = ver < 18
|
||||
}
|
||||
if err != nil || len(gv) <= 1 {
|
||||
logrus.Info(locale.Loc("guessing_version", nil))
|
||||
}
|
||||
|
||||
dimensionID := gd.Dimension
|
||||
if w.ispre118 {
|
||||
if w.serverState.ispre118 {
|
||||
logrus.Info(locale.Loc("using_under_118", nil))
|
||||
dimensionID += 10
|
||||
}
|
||||
w.Dim = dimensionIDMap[uint8(dimensionID)]
|
||||
w.worldState.Dim = dimensionIDMap[uint8(dimensionID)]
|
||||
}
|
||||
|
||||
w.proxy.SendMessage(locale.Loc("use_setname", nil))
|
||||
|
@ -611,7 +636,7 @@ func (w *WorldState) OnConnect(err error) bool {
|
|||
|
||||
w.proxy.AddCommand(utils.IngameCommand{
|
||||
Exec: func(cmdline []string) bool {
|
||||
return w.setVoidGen(!w.voidGen, false)
|
||||
return w.setVoidGen(!w.settings.voidGen, false)
|
||||
},
|
||||
Cmd: protocol.Command{
|
||||
Name: "void",
|
||||
|
@ -620,9 +645,5 @@ func (w *WorldState) OnConnect(err error) bool {
|
|||
})
|
||||
|
||||
w.mapUI.Start()
|
||||
|
||||
w.proxy.ClientWritePacket(&packet.ChunkRadiusUpdated{
|
||||
ChunkRadius: 80,
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package utils
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
|
@ -18,8 +17,6 @@ import (
|
|||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
var pool = packet.NewPool()
|
||||
|
||||
var MutedPackets = []string{
|
||||
"packet.UpdateBlock",
|
||||
"packet.MoveActorAbsolute",
|
||||
|
@ -49,9 +46,8 @@ var MutedPackets = []string{
|
|||
}
|
||||
|
||||
var (
|
||||
ExtraVerbose []string
|
||||
FLog io.Writer
|
||||
dmpLock sync.Mutex
|
||||
FLog io.Writer
|
||||
dmpLock sync.Mutex
|
||||
)
|
||||
|
||||
func dmpStruct(level int, inputStruct any, withType bool, isInList bool) (s string) {
|
||||
|
@ -63,11 +59,14 @@ func dmpStruct(level int, inputStruct any, withType bool, isInList bool) (s stri
|
|||
|
||||
ii := reflect.Indirect(reflect.ValueOf(inputStruct))
|
||||
typeName := reflect.TypeOf(inputStruct).String()
|
||||
if typeName == "[]interface {}" {
|
||||
typeName = "[]any"
|
||||
}
|
||||
typeString := ""
|
||||
if withType {
|
||||
if slices.Contains([]string{"bool", "string"}, typeName) {
|
||||
} else {
|
||||
typeString = typeName + " "
|
||||
typeString = typeName
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +83,8 @@ func dmpStruct(level int, inputStruct any, withType bool, isInList bool) (s stri
|
|||
return
|
||||
}
|
||||
|
||||
if ii.Kind() == reflect.Struct {
|
||||
switch ii.Kind() {
|
||||
case reflect.Struct:
|
||||
if ii.NumField() == 0 {
|
||||
s += typeName + "{}"
|
||||
} else {
|
||||
|
@ -93,30 +93,24 @@ func dmpStruct(level int, inputStruct any, withType bool, isInList bool) (s stri
|
|||
fieldType := ii.Type().Field(i)
|
||||
|
||||
if fieldType.IsExported() {
|
||||
field := ii.Field(i).Interface()
|
||||
d := dmpStruct(level+1, field, true, false)
|
||||
s += tBase + fmt.Sprintf("\t%s = %s\n", fieldType.Name, d)
|
||||
s += fmt.Sprintf("%s\t%s: %s,\n", tBase, fieldType.Name, dmpStruct(level+1, ii.Field(i).Interface(), true, false))
|
||||
} else {
|
||||
s += tBase + " " + fieldType.Name + " (unexported)"
|
||||
}
|
||||
}
|
||||
s += tBase + "}"
|
||||
}
|
||||
} else if ii.Kind() == reflect.Slice {
|
||||
var t reflect.Type
|
||||
is_elem_struct := false
|
||||
if ii.Len() > 0 {
|
||||
e := ii.Index(0)
|
||||
t = reflect.TypeOf(e.Interface())
|
||||
is_elem_struct = t.Kind() == reflect.Struct
|
||||
}
|
||||
case reflect.Slice:
|
||||
s += typeName + "{"
|
||||
|
||||
if ii.Len() > 1000 {
|
||||
s += "[<slice too long>]"
|
||||
s += "<slice too long>"
|
||||
} else if ii.Len() == 0 {
|
||||
s += fmt.Sprintf("[0%s", typeName[1:])
|
||||
} else {
|
||||
s += fmt.Sprintf("[%d%s{", ii.Len(), typeString[1:])
|
||||
e := ii.Index(0)
|
||||
t := reflect.TypeOf(e.Interface())
|
||||
is_elem_struct := t.Kind() == reflect.Struct
|
||||
|
||||
if is_elem_struct {
|
||||
s += "\n"
|
||||
}
|
||||
|
@ -124,32 +118,55 @@ func dmpStruct(level int, inputStruct any, withType bool, isInList bool) (s stri
|
|||
if is_elem_struct {
|
||||
s += tBase + "\t"
|
||||
}
|
||||
s += dmpStruct(level+1, ii.Index(i).Interface(), false, true)
|
||||
s += dmpStruct(level+1, ii.Index(i).Interface(), false, true) + ","
|
||||
if is_elem_struct {
|
||||
s += "\n"
|
||||
} else {
|
||||
s += " "
|
||||
if i != ii.Len()-1 {
|
||||
s += " "
|
||||
}
|
||||
}
|
||||
}
|
||||
if is_elem_struct {
|
||||
s += tBase
|
||||
}
|
||||
s += "]"
|
||||
}
|
||||
} else if ii.Kind() == reflect.Map {
|
||||
j, err := json.MarshalIndent(ii.Interface(), tBase, "\t")
|
||||
if err != nil {
|
||||
s += err.Error()
|
||||
s += "}"
|
||||
case reflect.Map:
|
||||
it := reflect.TypeOf(inputStruct)
|
||||
valType := it.Elem().String()
|
||||
if valType == "interface {}" {
|
||||
valType = "any"
|
||||
}
|
||||
s += string(j)
|
||||
} else {
|
||||
keyType := it.Key().String()
|
||||
|
||||
s += fmt.Sprintf("map[%s]%s{", keyType, valType)
|
||||
if ii.Len() > 0 {
|
||||
s += "\n"
|
||||
}
|
||||
|
||||
iter := ii.MapRange()
|
||||
for iter.Next() {
|
||||
k := iter.Key()
|
||||
v := iter.Value()
|
||||
s += fmt.Sprintf("%s\t%#v: %s,\n", tBase, k.Interface(), dmpStruct(level+1, v.Interface(), true, false))
|
||||
}
|
||||
|
||||
if ii.Len() > 0 {
|
||||
s += tBase
|
||||
}
|
||||
s += "}"
|
||||
default:
|
||||
is_array := ii.Kind() == reflect.Array
|
||||
if !isInList && !is_array {
|
||||
s += typeString
|
||||
add_type := !isInList && !is_array && len(typeString) > 0
|
||||
if add_type {
|
||||
s += typeString + "("
|
||||
}
|
||||
s += fmt.Sprintf("%#v", ii.Interface())
|
||||
if add_type {
|
||||
s += ")"
|
||||
}
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -163,17 +180,18 @@ func DumpStruct(data interface{}) {
|
|||
}
|
||||
|
||||
var ClientAddr net.Addr
|
||||
var pool = packet.NewPool()
|
||||
|
||||
func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||
if header.PacketID == packet.IDRequestNetworkSettings {
|
||||
ClientAddr = src
|
||||
}
|
||||
|
||||
var pk packet.Packet
|
||||
if pkFunc, ok := pool[header.PacketID]; ok {
|
||||
pk = pkFunc()
|
||||
} else {
|
||||
pk = &packet.Unknown{PacketID: header.PacketID}
|
||||
}
|
||||
|
||||
if pk.ID() == packet.IDRequestNetworkSettings {
|
||||
ClientAddr = src
|
||||
pk = &packet.Unknown{PacketID: header.PacketID, Payload: payload}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
|
@ -186,9 +204,8 @@ func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
|||
|
||||
if FLog != nil {
|
||||
dmpLock.Lock()
|
||||
defer dmpLock.Unlock()
|
||||
FLog.Write([]byte(dmpStruct(0, pk, true, false)))
|
||||
FLog.Write([]byte("\n\n\n"))
|
||||
FLog.Write([]byte(dmpStruct(0, pk, true, false) + "\n\n\n"))
|
||||
dmpLock.Unlock()
|
||||
}
|
||||
|
||||
pkName := reflect.TypeOf(pk).String()[1:]
|
||||
|
@ -217,8 +234,4 @@ func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
|||
}
|
||||
|
||||
logrus.Debugf("%s 0x%02x, %s", dir, pk.ID(), pkName)
|
||||
|
||||
if slices.Contains(ExtraVerbose, pkName) {
|
||||
logrus.Debugf("%+v", pk)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/aes"
|
||||
|
@ -207,11 +208,6 @@ func InitExtraDebug(ctx context.Context) {
|
|||
logPlain, err := os.Create("packets.log")
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
} else {
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
logPlain.Close()
|
||||
}()
|
||||
}
|
||||
|
||||
// open gpg log
|
||||
|
@ -219,24 +215,30 @@ func InitExtraDebug(ctx context.Context) {
|
|||
if err != nil {
|
||||
logrus.Error(err)
|
||||
} else {
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
logCrypt.Close()
|
||||
}()
|
||||
// encrypter for the log
|
||||
logCryptEnc, err = crypt.Encer("packets.log", logCrypt)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
} else {
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
logCryptEnc.Close()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
FLog = io.MultiWriter(logPlain, logCryptEnc)
|
||||
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()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package utils
|
|||
|
||||
import (
|
||||
"archive/zip"
|
||||
"compress/flate"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
@ -36,6 +37,12 @@ func ZipFolder(filename, folder string) error {
|
|||
logrus.Fatal(err)
|
||||
}
|
||||
zw := zip.NewWriter(f)
|
||||
|
||||
// Register a custom Deflate compressor.
|
||||
zw.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
|
||||
return flate.NewWriter(out, flate.NoCompression)
|
||||
})
|
||||
|
||||
err = filepath.WalkDir(folder, func(path string, d fs.DirEntry, err error) error {
|
||||
if !d.Type().IsDir() {
|
||||
rel := path[len(folder)+1:]
|
||||
|
|
Loading…
Reference in New Issue