Compare commits
6 Commits
3cc13a7bbf
...
e13856a4ff
Author | SHA1 | Date |
---|---|---|
olebeck | e13856a4ff | |
olebeck | 2761cf094c | |
olebeck | 0eb3d09046 | |
olebeck | 4968181f0e | |
olebeck | bbf7cc1d75 | |
olebeck | b867221a66 |
6
go.mod
6
go.mod
|
@ -3,10 +3,10 @@ module github.com/bedrock-tool/bedrocktool
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
//replace github.com/sandertv/gophertunnel => ./gophertunnel
|
//replace github.com/sandertv/gophertunnel => ./gophertunnel
|
||||||
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.28.2-1
|
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.29.0-1
|
||||||
|
|
||||||
//replace github.com/df-mc/dragonfly => ./dragonfly
|
//replace github.com/df-mc/dragonfly => ./dragonfly
|
||||||
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.4-11
|
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.4-13
|
||||||
|
|
||||||
//replace gioui.org => ./gio
|
//replace gioui.org => ./gio
|
||||||
replace gioui.org => github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d
|
replace gioui.org => github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d
|
||||||
|
@ -28,7 +28,7 @@ require (
|
||||||
github.com/repeale/fp-go v0.11.1
|
github.com/repeale/fp-go v0.11.1
|
||||||
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49
|
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49
|
||||||
github.com/sandertv/go-raknet v1.12.0
|
github.com/sandertv/go-raknet v1.12.0
|
||||||
github.com/sandertv/gophertunnel v1.28.2
|
github.com/sandertv/gophertunnel v1.29.0
|
||||||
github.com/shirou/gopsutil/v3 v3.23.3
|
github.com/shirou/gopsutil/v3 v3.23.3
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.0
|
||||||
golang.design/x/lockfree v0.0.1
|
golang.design/x/lockfree v0.0.1
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -85,12 +85,12 @@ github.com/muhammadmuzzammil1998/jsonc v1.0.0 h1:8o5gBQn4ZA3NBA9DlTujCj2a4w0tqWr
|
||||||
github.com/muhammadmuzzammil1998/jsonc v1.0.0/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
|
github.com/muhammadmuzzammil1998/jsonc v1.0.0/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
|
github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
||||||
github.com/olebeck/dragonfly v0.9.4-11 h1:FkDKWUT1Kz6WRRxCLmCcFsZiocu9/htkyyEfTgKaVio=
|
github.com/olebeck/dragonfly v0.9.4-13 h1:JF72hfG3/BBCXU1GSBaEKKXQy/gt+0mEOua3RdKXdJ8=
|
||||||
github.com/olebeck/dragonfly v0.9.4-11/go.mod h1:1XIP+EcgRnxAEkFEbqZE3T4vXyMufzdpnigwczMBbyo=
|
github.com/olebeck/dragonfly v0.9.4-13/go.mod h1:ZNcbAATEeTNyN3Cumtwzox7STtFve469HHzL5c1K3nY=
|
||||||
github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d h1:D+Ryca52xv37/p0FsEWfGwAGUZ1vPWpvimA2eMfBijc=
|
github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d h1:D+Ryca52xv37/p0FsEWfGwAGUZ1vPWpvimA2eMfBijc=
|
||||||
github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d/go.mod h1:8CFQM/4LurRd9G3NUYdacFb9j2pK0LrAyVO2mAZo4mw=
|
github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d/go.mod h1:8CFQM/4LurRd9G3NUYdacFb9j2pK0LrAyVO2mAZo4mw=
|
||||||
github.com/olebeck/gophertunnel v1.28.2-1 h1:+3LaX37suEjMUnUTUKJMetoBqSg5PUkUBJc5dW02WI4=
|
github.com/olebeck/gophertunnel v1.29.0-1 h1:3x2cZoe8O54xVFgEZqTBJpFEXlzbjlLFoo/d9cWGv+g=
|
||||||
github.com/olebeck/gophertunnel v1.28.2-1/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
|
github.com/olebeck/gophertunnel v1.29.0-1/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
|
|
@ -2,7 +2,6 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
@ -12,7 +11,6 @@ import (
|
||||||
"github.com/bedrock-tool/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
"github.com/bedrock-tool/bedrocktool/utils/crypt"
|
"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/packet"
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
@ -79,20 +77,11 @@ func NewDebugLogger(extraVerbose bool) *utils.ProxyHandler {
|
||||||
proxy = pc
|
proxy = pc
|
||||||
},
|
},
|
||||||
PacketFunc: func(header packet.Header, payload []byte, src, dst net.Addr) {
|
PacketFunc: func(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||||
var pk packet.Packet
|
pk := utils.DecodePacket(header, payload)
|
||||||
if pkFunc, ok := pool[header.PacketID]; ok {
|
if pk == nil {
|
||||||
pk = pkFunc()
|
return
|
||||||
} 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 packetsLogF != nil {
|
if packetsLogF != nil {
|
||||||
dmpLock.Lock()
|
dmpLock.Lock()
|
||||||
packetsLogF.Write([]byte(utils.DumpStruct(0, pk, true, false) + "\n\n\n"))
|
packetsLogF.Write([]byte(utils.DumpStruct(0, pk, true, false) + "\n\n\n"))
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
"github.com/df-mc/dragonfly/server/block/cube"
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||||||
"github.com/df-mc/dragonfly/server/world"
|
"github.com/df-mc/dragonfly/server/world"
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,27 +37,12 @@ func (p *provider) SavePlayerSpawnPosition(uuid uuid.UUID, pos cube.Pos) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) LoadChunk(position world.ChunkPos, dim world.Dimension) (c *chunk.Chunk, exists bool, err error) {
|
func (p *provider) LoadColumn(pos world.ChunkPos, dim world.Dimension) (*world.Column, error) {
|
||||||
c, ok := p.s.chunks[position]
|
return &world.Column{
|
||||||
return c, ok, nil
|
Chunk: p.s.chunks[pos],
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) SaveChunk(position world.ChunkPos, c *chunk.Chunk, dim world.Dimension) error {
|
func (p *provider) StoreColumn(pos world.ChunkPos, dim world.Dimension, col *world.Column) 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package worlds
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
"github.com/bedrock-tool/bedrocktool/locale"
|
||||||
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||||||
"github.com/df-mc/dragonfly/server/world"
|
"github.com/df-mc/dragonfly/server/world"
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||||
"github.com/repeale/fp-go"
|
"github.com/repeale/fp-go"
|
||||||
|
@ -42,13 +43,13 @@ func (w *worldsHandler) processLevelChunk(pk *packet.LevelChunk) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, blockNBT := range blockNBTs {
|
for _, blockNBT := range blockNBTs {
|
||||||
x := blockNBT["x"].(int32)
|
x := int(blockNBT["x"].(int32))
|
||||||
y := blockNBT["y"].(int32)
|
y := int(blockNBT["y"].(int32))
|
||||||
z := blockNBT["z"].(int32)
|
z := int(blockNBT["z"].(int32))
|
||||||
w.worldState.blockNBTs[protocol.BlockPos{x, y, z}] = blockNBT
|
w.worldState.blockNBTs[cube.Pos{x, y, z}] = blockNBT
|
||||||
}
|
}
|
||||||
|
|
||||||
w.worldState.chunks[pk.Position] = ch
|
w.worldState.chunks[(world.ChunkPos)(pk.Position)] = ch
|
||||||
|
|
||||||
max := w.worldState.dimension.Range().Height() / 16
|
max := w.worldState.dimension.Range().Height() / 16
|
||||||
switch pk.SubChunkCount {
|
switch pk.SubChunkCount {
|
||||||
|
@ -76,20 +77,20 @@ func (w *worldsHandler) processLevelChunk(pk *packet.LevelChunk) {
|
||||||
return sub.Empty()
|
return sub.Empty()
|
||||||
})(ch.Sub())
|
})(ch.Sub())
|
||||||
if !empty {
|
if !empty {
|
||||||
w.mapUI.SetChunk(pk.Position, ch, true)
|
w.mapUI.SetChunk((world.ChunkPos)(pk.Position), ch, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldsHandler) processSubChunk(pk *packet.SubChunk) {
|
func (w *worldsHandler) processSubChunk(pk *packet.SubChunk) {
|
||||||
posToRedraw := make(map[protocol.ChunkPos]bool)
|
posToRedraw := make(map[world.ChunkPos]bool)
|
||||||
|
|
||||||
for _, sub := range pk.SubChunkEntries {
|
for _, sub := range pk.SubChunkEntries {
|
||||||
var (
|
var (
|
||||||
absX = pk.Position[0] + int32(sub.Offset[0])
|
absX = pk.Position[0] + int32(sub.Offset[0])
|
||||||
absY = pk.Position[1] + int32(sub.Offset[1])
|
absY = pk.Position[1] + int32(sub.Offset[1])
|
||||||
absZ = pk.Position[2] + int32(sub.Offset[2])
|
absZ = pk.Position[2] + int32(sub.Offset[2])
|
||||||
pos = protocol.ChunkPos{absX, absZ}
|
pos = world.ChunkPos{absX, absZ}
|
||||||
)
|
)
|
||||||
ch, ok := w.worldState.chunks[pos]
|
ch, ok := w.worldState.chunks[pos]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -101,10 +102,10 @@ func (w *worldsHandler) processSubChunk(pk *packet.SubChunk) {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
for _, blockNBT := range blockNBTs {
|
for _, blockNBT := range blockNBTs {
|
||||||
x := blockNBT["x"].(int32)
|
x := int(blockNBT["x"].(int32))
|
||||||
y := blockNBT["y"].(int32)
|
y := int(blockNBT["y"].(int32))
|
||||||
z := blockNBT["z"].(int32)
|
z := int(blockNBT["z"].(int32))
|
||||||
w.worldState.blockNBTs[protocol.BlockPos{x, y, z}] = blockNBT
|
w.worldState.blockNBTs[cube.Pos{x, y, z}] = blockNBT
|
||||||
}
|
}
|
||||||
|
|
||||||
posToRedraw[pos] = true
|
posToRedraw[pos] = true
|
||||||
|
@ -134,10 +135,11 @@ func (w *worldsHandler) ProcessChunkPackets(pk packet.Packet) packet.Packet {
|
||||||
case *packet.SubChunk:
|
case *packet.SubChunk:
|
||||||
w.processSubChunk(pk)
|
w.processSubChunk(pk)
|
||||||
case *packet.BlockActorData:
|
case *packet.BlockActorData:
|
||||||
w.worldState.blockNBTs[pk.Position] = pk.NBTData
|
p := pk.Position
|
||||||
|
w.worldState.blockNBTs[cube.Pos{int(p.X()), int(p.Y()), int(p.Z())}] = pk.NBTData
|
||||||
case *packet.UpdateBlock:
|
case *packet.UpdateBlock:
|
||||||
if w.settings.BlockUpdates {
|
if w.settings.BlockUpdates {
|
||||||
cp := protocol.ChunkPos{pk.Position.X() >> 4, pk.Position.Z() >> 4}
|
cp := world.ChunkPos{pk.Position.X() >> 4, pk.Position.Z() >> 4}
|
||||||
c, ok := w.worldState.chunks[cp]
|
c, ok := w.worldState.chunks[cp]
|
||||||
if ok {
|
if ok {
|
||||||
x, y, z := blockPosInChunk(pk.Position)
|
x, y, z := blockPosInChunk(pk.Position)
|
||||||
|
@ -147,7 +149,7 @@ func (w *worldsHandler) ProcessChunkPackets(pk packet.Packet) packet.Packet {
|
||||||
}
|
}
|
||||||
case *packet.UpdateSubChunkBlocks:
|
case *packet.UpdateSubChunkBlocks:
|
||||||
if w.settings.BlockUpdates {
|
if w.settings.BlockUpdates {
|
||||||
cp := protocol.ChunkPos{pk.Position.X(), pk.Position.Z()}
|
cp := world.ChunkPos{pk.Position.X(), pk.Position.Z()}
|
||||||
c, ok := w.worldState.chunks[cp]
|
c, ok := w.worldState.chunks[cp]
|
||||||
if ok {
|
if ok {
|
||||||
for _, bce := range pk.Blocks {
|
for _, bce := range pk.Blocks {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
"github.com/bedrock-tool/bedrocktool/locale"
|
||||||
"github.com/bedrock-tool/bedrocktool/utils/nbtconv"
|
"github.com/bedrock-tool/bedrocktool/utils/nbtconv"
|
||||||
"github.com/df-mc/dragonfly/server/block"
|
"github.com/df-mc/dragonfly/server/block"
|
||||||
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||||||
"github.com/df-mc/dragonfly/server/item"
|
"github.com/df-mc/dragonfly/server/item"
|
||||||
"github.com/df-mc/dragonfly/server/item/inventory"
|
"github.com/df-mc/dragonfly/server/item/inventory"
|
||||||
"github.com/df-mc/dragonfly/server/world"
|
"github.com/df-mc/dragonfly/server/world"
|
||||||
|
@ -92,7 +93,8 @@ func (w *worldsHandler) processItemPacketsServer(pk packet.Packet) packet.Packet
|
||||||
}
|
}
|
||||||
|
|
||||||
// put into subchunk
|
// put into subchunk
|
||||||
nbt, ok := w.worldState.blockNBTs[existing.OpenPacket.ContainerPosition]
|
p := existing.OpenPacket.ContainerPosition
|
||||||
|
nbt, ok := w.worldState.blockNBTs[cube.Pos{int(p.X()), int(p.Y()), int(p.Z())}]
|
||||||
if ok {
|
if ok {
|
||||||
nbt["Items"] = nbtconv.InvToNBT(inv)
|
nbt["Items"] = nbtconv.InvToNBT(inv)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/go-gl/mathgl/mgl32"
|
"github.com/go-gl/mathgl/mgl32"
|
||||||
"golang.design/x/lockfree"
|
"golang.design/x/lockfree"
|
||||||
|
|
||||||
|
"github.com/df-mc/dragonfly/server/world"
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||||
"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"
|
||||||
|
@ -262,8 +263,8 @@ func (m *MapUI) ToImage() *image.RGBA {
|
||||||
return img
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MapUI) SetChunk(pos protocol.ChunkPos, ch *chunk.Chunk, complete bool) {
|
func (m *MapUI) SetChunk(pos world.ChunkPos, ch *chunk.Chunk, complete bool) {
|
||||||
m.renderQueue.Enqueue(&RenderElem{pos, ch})
|
m.renderQueue.Enqueue(&RenderElem{(protocol.ChunkPos)(pos), ch})
|
||||||
m.SchedRedraw()
|
m.SchedRedraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"image/png"
|
"image/png"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
|
@ -54,8 +55,8 @@ type WorldSettings struct {
|
||||||
|
|
||||||
type worldState struct {
|
type worldState struct {
|
||||||
dimension world.Dimension
|
dimension world.Dimension
|
||||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
chunks map[world.ChunkPos]*chunk.Chunk
|
||||||
blockNBTs map[protocol.BlockPos]map[string]any
|
blockNBTs map[cube.Pos]map[string]any
|
||||||
entities map[uint64]*entityState
|
entities map[uint64]*entityState
|
||||||
openItemContainers map[byte]*itemContainer
|
openItemContainers map[byte]*itemContainer
|
||||||
Name string
|
Name string
|
||||||
|
@ -218,8 +219,8 @@ func (w *worldsHandler) currentName() string {
|
||||||
func (w *worldsHandler) Reset() {
|
func (w *worldsHandler) Reset() {
|
||||||
w.worldState = worldState{
|
w.worldState = worldState{
|
||||||
dimension: w.worldState.dimension,
|
dimension: w.worldState.dimension,
|
||||||
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
chunks: make(map[world.ChunkPos]*chunk.Chunk),
|
||||||
blockNBTs: make(map[protocol.BlockPos]map[string]any),
|
blockNBTs: make(map[cube.Pos]map[string]any),
|
||||||
entities: make(map[uint64]*entityState),
|
entities: make(map[uint64]*entityState),
|
||||||
openItemContainers: make(map[byte]*itemContainer),
|
openItemContainers: make(map[byte]*itemContainer),
|
||||||
Name: w.currentName(),
|
Name: w.currentName(),
|
||||||
|
@ -228,11 +229,11 @@ func (w *worldsHandler) Reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldState) cullChunks() {
|
func (w *worldState) cullChunks() {
|
||||||
keys := make([]protocol.ChunkPos, 0, len(w.chunks))
|
keys := make([]world.ChunkPos, 0, len(w.chunks))
|
||||||
for cp := range w.chunks {
|
for cp := range w.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 world.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.chunks[cp].Sub())
|
})(w.chunks[cp].Sub())
|
||||||
|
@ -241,6 +242,35 @@ func (w *worldState) cullChunks() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type dummyBlock struct {
|
||||||
|
id string
|
||||||
|
nbt map[string]any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyBlock) EncodeBlock() (string, map[string]any) {
|
||||||
|
return d.id, d.nbt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyBlock) Hash() uint64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyBlock) Model() world.BlockModel {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyBlock) Color() color.RGBA {
|
||||||
|
return color.RGBA{0, 0, 0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyBlock) DecodeNBT(data map[string]any) any {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dummyBlock) EncodeNBT() map[string]any {
|
||||||
|
return d.nbt
|
||||||
|
}
|
||||||
|
|
||||||
func (w *worldState) Save(folder string) (*mcdb.DB, error) {
|
func (w *worldState) Save(folder string) (*mcdb.DB, error) {
|
||||||
provider, err := mcdb.Config{
|
provider, err := mcdb.Config{
|
||||||
Log: logrus.StandardLogger(),
|
Log: logrus.StandardLogger(),
|
||||||
|
@ -250,32 +280,32 @@ func (w *worldState) Save(folder string) (*mcdb.DB, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// save chunk data
|
chunkBlockNBT := make(map[world.ChunkPos]map[cube.Pos]world.Block)
|
||||||
for cp, c := range w.chunks {
|
|
||||||
provider.SaveChunk((world.ChunkPos)(cp), c, w.dimension)
|
|
||||||
}
|
|
||||||
|
|
||||||
// save block nbt data
|
|
||||||
chunkBlockNBT := make(map[world.ChunkPos][]map[string]any)
|
|
||||||
for bp, blockNBT := range w.blockNBTs { // 3d to 2d
|
for bp, blockNBT := range w.blockNBTs { // 3d to 2d
|
||||||
cp := world.ChunkPos{bp.X() >> 4, bp.Z() >> 4}
|
cp := world.ChunkPos{int32(bp.X()) >> 4, int32(bp.Z()) >> 4}
|
||||||
chunkBlockNBT[cp] = append(chunkBlockNBT[cp], blockNBT)
|
m, ok := chunkBlockNBT[cp]
|
||||||
}
|
if !ok {
|
||||||
for cp, blockNBT := range chunkBlockNBT {
|
m = make(map[cube.Pos]world.Block)
|
||||||
err = provider.SaveBlockNBT(cp, blockNBT, w.dimension)
|
chunkBlockNBT[cp] = m
|
||||||
if err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
}
|
}
|
||||||
|
id := blockNBT["id"].(string)
|
||||||
|
m[bp] = &dummyBlock{id, blockNBT}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save entities
|
|
||||||
chunkEntities := make(map[world.ChunkPos][]world.Entity)
|
chunkEntities := make(map[world.ChunkPos][]world.Entity)
|
||||||
for _, es := range w.entities {
|
for _, es := range w.entities {
|
||||||
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
|
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
|
||||||
chunkEntities[cp] = append(chunkEntities[cp], es.ToServerEntity())
|
chunkEntities[cp] = append(chunkEntities[cp], es.ToServerEntity())
|
||||||
}
|
}
|
||||||
for cp, v := range chunkEntities {
|
|
||||||
err = provider.SaveEntities(cp, v, w.dimension)
|
// save chunk data
|
||||||
|
for cp, c := range w.chunks {
|
||||||
|
column := &world.Column{
|
||||||
|
Chunk: c,
|
||||||
|
BlockEntities: chunkBlockNBT[cp],
|
||||||
|
Entities: chunkEntities[cp],
|
||||||
|
}
|
||||||
|
err = provider.StoreColumn(cp, w.dimension, column)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -301,6 +331,9 @@ func (w *worldsHandler) SaveAndReset() {
|
||||||
img = w.mapUI.ToImage()
|
img = w.mapUI.ToImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
folder := fmt.Sprintf("worlds/%s/%s", w.serverState.Name, worldStateCopy.Name)
|
||||||
|
filename := folder + ".mcworld"
|
||||||
|
|
||||||
w.serverState.worldCounter += 1
|
w.serverState.worldCounter += 1
|
||||||
w.Reset()
|
w.Reset()
|
||||||
w.wg.Add(1)
|
w.wg.Add(1)
|
||||||
|
@ -308,12 +341,14 @@ func (w *worldsHandler) SaveAndReset() {
|
||||||
defer w.wg.Done()
|
defer w.wg.Done()
|
||||||
logrus.Infof(locale.Loc("saving_world", locale.Strmap{"Name": worldStateCopy.Name, "Count": len(worldStateCopy.chunks)}))
|
logrus.Infof(locale.Loc("saving_world", locale.Strmap{"Name": worldStateCopy.Name, "Count": len(worldStateCopy.chunks)}))
|
||||||
w.gui.Message(messages.SavingWorld{
|
w.gui.Message(messages.SavingWorld{
|
||||||
Name: w.worldState.Name,
|
World: &messages.SavedWorld{
|
||||||
Chunks: len(w.worldState.chunks),
|
Name: worldStateCopy.Name,
|
||||||
|
Path: filename,
|
||||||
|
Chunks: len(worldStateCopy.chunks),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// open world
|
// open world
|
||||||
folder := fmt.Sprintf("worlds/%s/%s", w.serverState.Name, worldStateCopy.Name)
|
|
||||||
os.RemoveAll(folder)
|
os.RemoveAll(folder)
|
||||||
os.MkdirAll(folder, 0o777)
|
os.MkdirAll(folder, 0o777)
|
||||||
provider, err := worldStateCopy.Save(folder)
|
provider, err := worldStateCopy.Save(folder)
|
||||||
|
@ -439,7 +474,6 @@ func (w *worldsHandler) SaveAndReset() {
|
||||||
w.AddPacks(folder)
|
w.AddPacks(folder)
|
||||||
|
|
||||||
// zip it
|
// zip it
|
||||||
filename := folder + ".mcworld"
|
|
||||||
err = utils.ZipFolder(filename, folder)
|
err = utils.ZipFolder(filename, folder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
|
@ -533,6 +567,9 @@ func (w *worldsHandler) AddPacks(folder string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worldsHandler) OnConnect(err error) bool {
|
func (w *worldsHandler) OnConnect(err error) bool {
|
||||||
|
w.gui.Message(messages.SetWorldName{
|
||||||
|
WorldName: w.worldState.Name,
|
||||||
|
})
|
||||||
w.gui.Message(messages.SetUIState(messages.UIStateMain))
|
w.gui.Message(messages.SetUIState(messages.UIStateMain))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
|
|
Binary file not shown.
|
@ -1,8 +1,10 @@
|
||||||
package packs
|
package packs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
|
@ -26,19 +28,25 @@ type (
|
||||||
type Page struct {
|
type Page struct {
|
||||||
*pages.Router
|
*pages.Router
|
||||||
|
|
||||||
State messages.UIState
|
State messages.UIState
|
||||||
packsList widget.List
|
packsList widget.List
|
||||||
l sync.Mutex
|
packShowButtons map[string]*widget.Clickable
|
||||||
Packs []*packEntry
|
l sync.Mutex
|
||||||
|
Packs map[string]*packEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
type packEntry struct {
|
type packEntry struct {
|
||||||
|
IsFinished bool
|
||||||
|
UUID string
|
||||||
|
|
||||||
HasIcon bool
|
HasIcon bool
|
||||||
Icon paint.ImageOp
|
Icon paint.ImageOp
|
||||||
Size string
|
|
||||||
Name string
|
Size uint64
|
||||||
Path string
|
Loaded uint64
|
||||||
Err error
|
Name string
|
||||||
|
Path string
|
||||||
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(router *pages.Router) *Page {
|
func New(router *pages.Router) *Page {
|
||||||
|
@ -49,6 +57,8 @@ func New(router *pages.Router) *Page {
|
||||||
Axis: layout.Vertical,
|
Axis: layout.Vertical,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Packs: make(map[string]*packEntry),
|
||||||
|
packShowButtons: make(map[string]*widget.Clickable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,48 +78,99 @@ func (p *Page) NavItem() component.NavItem {
|
||||||
//Icon: icon.OtherIcon,
|
//Icon: icon.OtherIcon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func drawPackIcon(ops *op.Ops, imageOp paint.ImageOp, bounds image.Point) {
|
func drawPackIcon(gtx C, hasImage bool, imageOp paint.ImageOp, bounds image.Point) D {
|
||||||
imageOp.Add(ops)
|
return layout.Inset{
|
||||||
|
Top: unit.Dp(5),
|
||||||
|
Bottom: unit.Dp(5),
|
||||||
|
Right: unit.Dp(5),
|
||||||
|
Left: unit.Dp(5),
|
||||||
|
}.Layout(gtx, func(gtx C) D {
|
||||||
|
if hasImage {
|
||||||
|
imageOp.Add(gtx.Ops)
|
||||||
|
s := imageOp.Size()
|
||||||
|
p := f32.Pt(float32(s.X), float32(s.Y))
|
||||||
|
p.X = 1 / (p.X / float32(bounds.X))
|
||||||
|
p.Y = 1 / (p.Y / float32(bounds.Y))
|
||||||
|
defer op.Affine(f32.Affine2D{}.Scale(f32.Pt(0, 0), p)).Push(gtx.Ops).Pop()
|
||||||
|
paint.PaintOp{}.Add(gtx.Ops)
|
||||||
|
}
|
||||||
|
return D{Size: bounds}
|
||||||
|
})
|
||||||
|
|
||||||
s := imageOp.Size()
|
|
||||||
p := f32.Pt(float32(s.X), float32(s.Y))
|
|
||||||
p.X = 1 / (p.X / float32(bounds.X))
|
|
||||||
p.Y = 1 / (p.Y / float32(bounds.Y))
|
|
||||||
defer op.Affine(f32.Affine2D{}.Scale(f32.Pt(0, 0), p)).Push(ops).Pop()
|
|
||||||
|
|
||||||
paint.PaintOp{}.Add(ops)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawPackEntry(gtx C, th *material.Theme, entry *packEntry) D {
|
func MulAlpha(c color.NRGBA, alpha uint8) color.NRGBA {
|
||||||
return layout.UniformInset(5).Layout(gtx, func(gtx C) D {
|
c.A = uint8(uint32(c.A) * uint32(alpha) / 0xFF)
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return c
|
||||||
layout.Rigid(func(gtx C) D {
|
}
|
||||||
s := image.Pt(50, 50)
|
|
||||||
if entry.HasIcon {
|
func drawPackEntry(gtx C, th *material.Theme, entry *packEntry, button *widget.Clickable) D {
|
||||||
drawPackIcon(gtx.Ops, entry.Icon, s)
|
var size = ""
|
||||||
}
|
var colorSize = th.Palette.Fg
|
||||||
return D{Size: s.Add(image.Pt(10, 10))}
|
if entry.IsFinished {
|
||||||
}),
|
size = utils.SizeofFmt(float32(entry.Size))
|
||||||
layout.Flexed(1, func(gtx C) D {
|
} else {
|
||||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
size = fmt.Sprintf("%s / %s %.02f%%",
|
||||||
layout.Rigid(material.Label(th, th.TextSize, entry.Name).Layout),
|
utils.SizeofFmt(float32(entry.Loaded)),
|
||||||
layout.Rigid(material.Label(th, th.TextSize, entry.Size).Layout),
|
utils.SizeofFmt(float32(entry.Size)),
|
||||||
layout.Rigid(func(gtx C) D {
|
float32(entry.Loaded)/float32(entry.Size)*100,
|
||||||
if entry.Err != nil {
|
|
||||||
return material.LabelStyle{
|
|
||||||
Color: color.NRGBA{0xbb, 0x00, 0x00, 0xff},
|
|
||||||
Text: entry.Err.Error(),
|
|
||||||
}.Layout(gtx)
|
|
||||||
}
|
|
||||||
return D{}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
colorSize = color.NRGBA{0x00, 0xc9, 0xc9, 0xff}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout.UniformInset(5).Layout(gtx, func(gtx C) D {
|
||||||
|
fn := func(gtx C) D {
|
||||||
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
|
layout.Rigid(func(gtx C) D {
|
||||||
|
return drawPackIcon(gtx, entry.HasIcon, entry.Icon, image.Pt(50, 50))
|
||||||
|
}),
|
||||||
|
layout.Flexed(1, func(gtx C) D {
|
||||||
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||||
|
layout.Rigid(material.Label(th, th.TextSize, entry.Name).Layout),
|
||||||
|
layout.Rigid(material.LabelStyle{
|
||||||
|
Text: size,
|
||||||
|
Color: colorSize,
|
||||||
|
SelectionColor: MulAlpha(th.Palette.ContrastBg, 0x60),
|
||||||
|
TextSize: th.TextSize,
|
||||||
|
Shaper: th.Shaper,
|
||||||
|
}.Layout),
|
||||||
|
layout.Rigid(func(gtx C) D {
|
||||||
|
if entry.Err != nil {
|
||||||
|
return material.LabelStyle{
|
||||||
|
Color: color.NRGBA{0xbb, 0x00, 0x00, 0xff},
|
||||||
|
Text: entry.Err.Error(),
|
||||||
|
}.Layout(gtx)
|
||||||
|
}
|
||||||
|
return D{}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Path != "" {
|
||||||
|
return material.ButtonLayoutStyle{
|
||||||
|
Background: MulAlpha(th.Palette.Bg, 0x60),
|
||||||
|
Button: button,
|
||||||
|
CornerRadius: 3,
|
||||||
|
}.Layout(gtx, fn)
|
||||||
|
} else {
|
||||||
|
return fn(gtx)
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Page) layoutFinished(gtx C, th *material.Theme) D {
|
func (p *Page) layoutFinished(gtx C, th *material.Theme) D {
|
||||||
|
for uuid, button := range p.packShowButtons {
|
||||||
|
if button.Clicked() {
|
||||||
|
pack := p.Packs[uuid]
|
||||||
|
if pack.IsFinished {
|
||||||
|
utils.ShowFile(pack.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return layout.Center.Layout(gtx, func(gtx C) D {
|
return layout.Center.Layout(gtx, func(gtx C) D {
|
||||||
return layout.Flex{
|
return layout.Flex{
|
||||||
Axis: layout.Vertical,
|
Axis: layout.Vertical,
|
||||||
|
@ -118,9 +179,17 @@ func (p *Page) layoutFinished(gtx C, th *material.Theme) D {
|
||||||
layout.Flexed(1, func(gtx C) D {
|
layout.Flexed(1, func(gtx C) D {
|
||||||
p.l.Lock()
|
p.l.Lock()
|
||||||
defer p.l.Unlock()
|
defer p.l.Unlock()
|
||||||
return material.List(th, &p.packsList).Layout(gtx, len(p.Packs), func(gtx C, index int) D {
|
|
||||||
entry := p.Packs[len(p.Packs)-index-1]
|
keys := make([]string, 0, len(p.Packs))
|
||||||
return drawPackEntry(gtx, th, entry)
|
for k := range p.Packs {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
return material.List(th, &p.packsList).Layout(gtx, len(keys), func(gtx C, index int) D {
|
||||||
|
entry := p.Packs[keys[index]]
|
||||||
|
button := p.packShowButtons[keys[index]]
|
||||||
|
return drawPackEntry(gtx, th, entry, button)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -137,7 +206,9 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
|
||||||
|
|
||||||
return margin.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
return margin.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
switch p.State {
|
switch p.State {
|
||||||
case messages.UIStateFinished:
|
case messages.UIStateConnecting:
|
||||||
|
return layout.Center.Layout(gtx, material.Label(th, 100, "Connecting").Layout)
|
||||||
|
case messages.UIStateMain:
|
||||||
return p.layoutFinished(gtx, th)
|
return p.layoutFinished(gtx, th)
|
||||||
}
|
}
|
||||||
return layout.Dimensions{}
|
return layout.Dimensions{}
|
||||||
|
@ -155,19 +226,46 @@ func (p *Page) Handler(data interface{}) messages.MessageResponse {
|
||||||
p.State = m
|
p.State = m
|
||||||
p.Router.Invalidate()
|
p.Router.Invalidate()
|
||||||
r.Ok = true
|
r.Ok = true
|
||||||
case messages.FinishedDownloadingPacks:
|
|
||||||
p.State = messages.UIStateFinished
|
case messages.InitialPacksInfo:
|
||||||
|
p.State = messages.UIStateMain
|
||||||
|
p.l.Lock()
|
||||||
for _, dp := range m.Packs {
|
for _, dp := range m.Packs {
|
||||||
e := &packEntry{
|
e := &packEntry{
|
||||||
Name: dp.Name,
|
IsFinished: false,
|
||||||
Size: utils.SizeofFmt(float32(dp.Size)),
|
UUID: dp.UUID,
|
||||||
|
Name: dp.SubPackName + " v" + dp.Version,
|
||||||
|
Size: dp.Size,
|
||||||
}
|
}
|
||||||
|
p.Packs[e.UUID] = e
|
||||||
|
p.packShowButtons[e.UUID] = &widget.Clickable{}
|
||||||
|
}
|
||||||
|
p.l.Unlock()
|
||||||
|
p.Router.Invalidate()
|
||||||
|
|
||||||
|
case messages.PackDownloadProgress:
|
||||||
|
p.l.Lock()
|
||||||
|
e := p.Packs[m.UUID]
|
||||||
|
e.Loaded += m.LoadedAdd
|
||||||
|
if e.Loaded == e.Size {
|
||||||
|
e.IsFinished = true
|
||||||
|
}
|
||||||
|
p.l.Unlock()
|
||||||
|
p.Router.Invalidate()
|
||||||
|
|
||||||
|
case messages.FinishedDownloadingPacks:
|
||||||
|
p.l.Lock()
|
||||||
|
for _, dp := range m.Packs {
|
||||||
|
e := p.Packs[dp.UUID]
|
||||||
if dp.Icon != nil {
|
if dp.Icon != nil {
|
||||||
e.Icon = paint.NewImageOpFilter(dp.Icon, paint.FilterNearest)
|
e.Icon = paint.NewImageOpFilter(dp.Icon, paint.FilterNearest)
|
||||||
e.HasIcon = true
|
e.HasIcon = true
|
||||||
}
|
}
|
||||||
p.Packs = append(p.Packs, e)
|
e.Err = dp.Err
|
||||||
|
e.IsFinished = true
|
||||||
|
e.Path = dp.Path
|
||||||
}
|
}
|
||||||
|
p.l.Unlock()
|
||||||
p.Router.Invalidate()
|
p.Router.Invalidate()
|
||||||
r.Ok = true
|
r.Ok = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package worlds
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
|
@ -29,7 +28,7 @@ type Page struct {
|
||||||
worldName string
|
worldName string
|
||||||
|
|
||||||
worldsList widget.List
|
worldsList widget.List
|
||||||
worlds []messages.SavingWorld
|
worlds []*messages.SavedWorld
|
||||||
l sync.Mutex
|
l sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +61,19 @@ func (p *Page) NavItem() component.NavItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func displayWorldEntry(gtx C, th *material.Theme, entry *messages.SavedWorld) D {
|
||||||
|
return layout.UniformInset(5).Layout(gtx, func(gtx C) D {
|
||||||
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
|
layout.Rigid(func(gtx C) D {
|
||||||
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||||
|
layout.Rigid(material.Label(th, th.TextSize, entry.Name).Layout),
|
||||||
|
layout.Rigid(material.Label(th, th.TextSize, fmt.Sprintf("%d Chunks", entry.Chunks)).Layout),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Page) Layout(gtx C, th *material.Theme) D {
|
func (p *Page) Layout(gtx C, th *material.Theme) D {
|
||||||
margin := layout.Inset{
|
margin := layout.Inset{
|
||||||
Top: unit.Dp(25),
|
Top: unit.Dp(25),
|
||||||
|
@ -70,46 +82,42 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
|
||||||
Left: unit.Dp(35),
|
Left: unit.Dp(35),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.State {
|
margin.Layout(gtx, func(gtx C) D {
|
||||||
case messages.UIStateConnect:
|
switch p.State {
|
||||||
// display login page
|
case messages.UIStateConnect:
|
||||||
return margin.Layout(gtx, material.Label(th, 100, "connect Client").Layout)
|
// display login page
|
||||||
case messages.UIStateConnecting:
|
return layout.Center.Layout(gtx, material.Label(th, 100, "connect Client").Layout)
|
||||||
// display connecting to server
|
case messages.UIStateConnecting:
|
||||||
return margin.Layout(gtx, material.Label(th, 100, "Connecting").Layout)
|
return layout.Center.Layout(gtx, material.Label(th, 100, "Connecting").Layout)
|
||||||
case messages.UIStateMain:
|
case messages.UIStateMain:
|
||||||
// show the main ui
|
// show the main ui
|
||||||
return layout.Flex{
|
return layout.Flex{
|
||||||
Axis: layout.Vertical,
|
Axis: layout.Vertical,
|
||||||
}.Layout(gtx,
|
}.Layout(gtx,
|
||||||
layout.Flexed(1, func(gtx C) D {
|
//layout.Rigid(material.Label(th, th.TextSize, p.worldName).Layout),
|
||||||
return layout.Center.Layout(gtx, p.worldMap.Layout)
|
layout.Flexed(1, func(gtx C) D {
|
||||||
}),
|
return layout.Center.Layout(gtx, p.worldMap.Layout)
|
||||||
)
|
}),
|
||||||
case messages.UIStateFinished:
|
)
|
||||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
case messages.UIStateFinished:
|
||||||
layout.Rigid(func(gtx C) D {
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||||
return layout.UniformInset(20).
|
layout.Rigid(func(gtx C) D {
|
||||||
Layout(gtx, material.Label(th, 20, "Worlds Saved").Layout)
|
return layout.UniformInset(15).
|
||||||
}),
|
Layout(gtx, material.Label(th, 20, "Worlds Saved").Layout)
|
||||||
layout.Flexed(1, func(gtx C) D {
|
}),
|
||||||
p.l.Lock()
|
layout.Flexed(1, func(gtx C) D {
|
||||||
defer p.l.Unlock()
|
p.l.Lock()
|
||||||
return material.List(th, &p.worldsList).Layout(gtx, len(p.worlds), func(gtx C, index int) D {
|
defer p.l.Unlock()
|
||||||
entry := p.worlds[len(p.worlds)-index-1]
|
return material.List(th, &p.worldsList).Layout(gtx, len(p.worlds), func(gtx C, index int) D {
|
||||||
return layout.UniformInset(25).Layout(gtx, func(gtx C) D {
|
entry := p.worlds[len(p.worlds)-index-1]
|
||||||
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
return displayWorldEntry(gtx, th, entry)
|
||||||
layout.Rigid(material.Label(th, th.TextSize, entry.Name).Layout),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
return layout.Dimensions{Size: image.Pt(20, 20)}
|
|
||||||
}),
|
|
||||||
layout.Rigid(material.Label(th, th.TextSize, fmt.Sprintf("%d chunks", entry.Chunks)).Layout),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
}),
|
||||||
}),
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
return D{}
|
||||||
|
})
|
||||||
|
|
||||||
return layout.Dimensions{}
|
return layout.Dimensions{}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +148,7 @@ func (u *Page) Handler(data any) messages.MessageResponse {
|
||||||
r.Ok = true
|
r.Ok = true
|
||||||
case messages.SavingWorld:
|
case messages.SavingWorld:
|
||||||
u.l.Lock()
|
u.l.Lock()
|
||||||
u.worlds = append(u.worlds, m)
|
u.worlds = append(u.worlds, m.World)
|
||||||
u.l.Unlock()
|
u.l.Unlock()
|
||||||
u.Router.Invalidate()
|
u.Router.Invalidate()
|
||||||
r.Ok = true
|
r.Ok = true
|
||||||
|
|
|
@ -63,13 +63,29 @@ type NewSkin struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SavingWorld struct {
|
type SavingWorld struct {
|
||||||
|
World *SavedWorld
|
||||||
|
}
|
||||||
|
|
||||||
|
type SavedWorld struct {
|
||||||
Name string
|
Name string
|
||||||
|
Path string
|
||||||
Chunks int
|
Chunks int
|
||||||
|
Image image.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
type CanShowImages struct{}
|
type CanShowImages struct{}
|
||||||
|
|
||||||
|
type InitialPacksInfo struct {
|
||||||
|
Packs []protocol.TexturePackInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type PackDownloadProgress struct {
|
||||||
|
UUID string
|
||||||
|
LoadedAdd uint64
|
||||||
|
}
|
||||||
|
|
||||||
type DownloadedPack struct {
|
type DownloadedPack struct {
|
||||||
|
UUID string
|
||||||
Name string
|
Name string
|
||||||
Path string
|
Path string
|
||||||
Size int
|
Size int
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -70,6 +71,8 @@ type ProxyHandler struct {
|
||||||
OnClientConnect func(conn minecraft.IConn)
|
OnClientConnect func(conn minecraft.IConn)
|
||||||
SecondaryClientCB func(conn minecraft.IConn)
|
SecondaryClientCB func(conn minecraft.IConn)
|
||||||
|
|
||||||
|
// called after server connected & downloaded resource packs
|
||||||
|
OnServerConnect func() (cancel bool)
|
||||||
// called after game started
|
// called after game started
|
||||||
ConnectCB func(err error) bool
|
ConnectCB func(err error) bool
|
||||||
|
|
||||||
|
@ -351,11 +354,6 @@ func (p *ProxyContext) connectClient(ctx context.Context, serverAddress string,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyContext) connectServer(ctx context.Context, serverAddress string, cdp *login.ClientData, packetFunc PacketFunc) (err error) {
|
|
||||||
p.Server, err = connectServer(ctx, serverAddress, cdp, p.AlwaysGetPacks, packetFunc)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err error) {
|
func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err error) {
|
||||||
if Options.Debug || Options.ExtraDebug {
|
if Options.Debug || Options.ExtraDebug {
|
||||||
p.AddHandler(NewDebugLogger(Options.ExtraDebug))
|
p.AddHandler(NewDebugLogger(Options.ExtraDebug))
|
||||||
|
@ -436,7 +434,7 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = p.connectServer(ctx, serverAddress, cdp, packetFunc)
|
p.Server, err = connectServer(ctx, serverAddress, cdp, p.AlwaysGetPacks, packetFunc)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
for _, handler := range p.handlers {
|
for _, handler := range p.handlers {
|
||||||
|
@ -457,6 +455,16 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
||||||
}
|
}
|
||||||
defer p.Server.Close()
|
defer p.Server.Close()
|
||||||
|
|
||||||
|
for _, handler := range p.handlers {
|
||||||
|
if handler.OnServerConnect == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cancel := handler.OnServerConnect()
|
||||||
|
if cancel {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gd := p.Server.GameData()
|
gd := p.Server.GameData()
|
||||||
for _, handler := range p.handlers {
|
for _, handler := range p.handlers {
|
||||||
if handler.GameDataModifier != nil {
|
if handler.GameDataModifier != nil {
|
||||||
|
@ -475,7 +483,8 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !handler.ConnectCB(nil) {
|
if !handler.ConnectCB(nil) {
|
||||||
return errors.New("Cancelled")
|
logrus.Info("Disconnecting")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,3 +534,22 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pool = packet.NewPool()
|
||||||
|
|
||||||
|
func DecodePacket(header packet.Header, payload []byte) packet.Packet {
|
||||||
|
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))
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
|
@ -183,7 +183,8 @@ func SizeofFmt(num float32) string {
|
||||||
func ShowFile(path string) {
|
func ShowFile(path string) {
|
||||||
path, _ = filepath.Abs(path)
|
path, _ = filepath.Abs(path)
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
exec.Command(`explorer`, `/select,`, path)
|
cmd := exec.Command(`explorer`, "/select,", path)
|
||||||
|
cmd.Start()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
|
|
Loading…
Reference in New Issue