diff --git a/Readme.md b/Readme.md
index 2d6d1a2..13f0d29 100644
--- a/Readme.md
+++ b/Readme.md
@@ -2,18 +2,21 @@
## [releases](https://github.com/bedrock-tool/bedrocktool/releases)
-
-Available commands:
- capture capture packets
- realms-token get xbl3.0 token
- ~~packs downloads resourcepacks from a server~~
- skins-proxy skin stealer (proxy)
- skins skin stealer
- world Launch world downloading proxy (NOT WORKING YET)
-
+```
+Usage: bedrocktool
-usage:
-`./bedrocktool-.exe [-debug>`
+Subcommands:
+ capture capture packets in a pcap file
+ help describe subcommands and their syntax
+ inject inject files into a minecraft install (USE WITH CAUTION)
+ packs download resource packs from a server
+ realms-token print xbl3.0 token for realms api
+ skins download all skins from players on a server
+ skins-proxy download skins from players on a server with proxy
+ worlds download a world from a server
-example:
-`./bedrocktool-v1.24.3.exe skins-proxy play.minecraft.net [-debug]`
+
+Top-level flags (use "bedrocktool flags" for a full list):
+ -debug=false: debug mode
+ -dns=false: enable dns server for consoles
+```
\ No newline at end of file
diff --git a/capture.go b/capture.go
index 9a495ee..424286c 100644
--- a/capture.go
+++ b/capture.go
@@ -14,6 +14,7 @@ import (
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcapgo"
+ "github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
@@ -22,7 +23,7 @@ var SrcIp_client = net.IPv4(127, 0, 0, 1)
var SrcIp_server = net.IPv4(243, 0, 0, 2)
func init() {
- register_command("capture", "capture packets", packets_main)
+ register_command(&CaptureCMD{})
}
func dump_packet(from_client bool, w *pcapgo.Writer, pk packet.Packet) {
@@ -73,31 +74,40 @@ func dump_packet(from_client bool, w *pcapgo.Writer, pk packet.Packet) {
}
}
-func packets_main(ctx context.Context, args []string) error {
- var server string
- flag.StringVar(&server, "server", "", "target server")
- flag.CommandLine.Parse(args)
- if G_help {
- flag.Usage()
- return nil
- }
+type CaptureCMD struct {
+ server_address string
+}
- address, hostname, err := server_input(server)
+func (*CaptureCMD) Name() string { return "capture" }
+func (*CaptureCMD) Synopsis() string { return "capture packets in a pcap file" }
+
+func (p *CaptureCMD) SetFlags(f *flag.FlagSet) {
+ f.StringVar(&p.server_address, "address", "", "remote server address")
+}
+func (c *CaptureCMD) Usage() string {
+ return c.Name() + ": " + c.Synopsis() + "\n"
+}
+
+func (c *CaptureCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
+ address, hostname, err := server_input(c.server_address)
if err != nil {
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
}
listener, serverConn, clientConn, err := create_proxy(ctx, address)
if err != nil {
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
}
- f, err := os.Create(hostname + "-" + time.Now().Format("2006-01-02_15-04-05") + ".pcap")
+ fio, err := os.Create(hostname + "-" + time.Now().Format("2006-01-02_15-04-05") + ".pcap")
if err != nil {
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
}
- defer f.Close()
- w := pcapgo.NewWriter(f)
+ defer fio.Close()
+ w := pcapgo.NewWriter(fio)
w.WriteFileHeader(65536, layers.LinkTypeEthernet)
_wl := sync.Mutex{}
@@ -129,7 +139,7 @@ func packets_main(ctx context.Context, args []string) error {
pk, err := serverConn.ReadPacket()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read packet: %s\n", err)
- return nil
+ return 1
}
_wl.Lock()
@@ -139,7 +149,7 @@ func packets_main(ctx context.Context, args []string) error {
err = clientConn.WritePacket(pk)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write packet: %s\n", err)
- return nil
+ return 1
}
}
}
diff --git a/chunk.bin b/chunk.bin
new file mode 100644
index 0000000..be2cc50
Binary files /dev/null and b/chunk.bin differ
diff --git a/chunk_test.go b/chunk_test.go
new file mode 100644
index 0000000..a6e0bf1
--- /dev/null
+++ b/chunk_test.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "os"
+ "testing"
+
+ "github.com/df-mc/dragonfly/server/block/cube"
+ "github.com/df-mc/dragonfly/server/world/chunk"
+)
+
+func Benchmark_chunk_decode(b *testing.B) {
+ data, _ := os.ReadFile("chunk.bin")
+ for i := 0; i < b.N; i++ {
+ _, err := chunk.NetworkDecode(33, data, 6, cube.Range{-64, 319})
+ if err != nil {
+ b.Error(err)
+ }
+ }
+}
+
+func Benchmark_render_chunk(b *testing.B) {
+ data, _ := os.ReadFile("chunk.bin")
+ ch, _ := chunk.NetworkDecode(33, data, 6, cube.Range{-64, 319})
+
+ for i := 0; i < b.N; i++ {
+ Chunk2Img(ch)
+ }
+}
diff --git a/dns.go b/dns.go
new file mode 100644
index 0000000..6a1cec7
--- /dev/null
+++ b/dns.go
@@ -0,0 +1,95 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net"
+
+ "github.com/miekg/dns"
+)
+
+var override_dns = map[string]bool{
+ "geo.hivebedrock.network.": true,
+}
+
+func answerQuery(remote net.Addr, req *dns.Msg) (reply *dns.Msg) {
+ reply = new(dns.Msg)
+
+ answered := false
+ for _, q := range req.Question {
+ switch q.Qtype {
+ case dns.TypeA:
+ log.Printf("Query for %s\n", q.Name)
+
+ if override_dns[q.Name] {
+ host, _, _ := net.SplitHostPort(remote.String())
+ remote_ip := net.ParseIP(host)
+
+ addrs, _ := net.InterfaceAddrs()
+ var ip string
+ for _, addr := range addrs {
+ if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.Contains(remote_ip) {
+ ip = ipnet.IP.String()
+ }
+ }
+ }
+ if ip == "" {
+ log.Panicf("query from outside of own network??")
+ }
+
+ rr, err := dns.NewRR(fmt.Sprintf("%s A %s", q.Name, ip))
+ if err == nil {
+ reply.Answer = append(reply.Answer, rr)
+ answered = true
+ }
+ }
+ }
+ }
+
+ // forward to 1.1.1.1 if not intercepted
+ if !answered {
+ c, err := dns.DialWithTLS("tcp4", "1.1.1.1:853", nil)
+ if err != nil {
+ panic(err)
+ }
+ if err = c.WriteMsg(req); err != nil {
+ panic(err)
+ }
+ if reply, err = c.ReadMsg(); err != nil {
+ panic(err)
+ }
+ c.Close()
+ }
+
+ return reply
+}
+
+func dns_handler(w dns.ResponseWriter, req *dns.Msg) {
+ var reply *dns.Msg
+
+ switch req.Opcode {
+ case dns.OpcodeQuery:
+ reply = answerQuery(w.RemoteAddr(), req)
+ default:
+ reply = new(dns.Msg)
+ }
+
+ reply.SetReply(req)
+ w.WriteMsg(reply)
+}
+
+func init_dns() {
+ dns.HandleFunc(".", dns_handler)
+
+ server := &dns.Server{Addr: ":53", Net: "udp"}
+ go func() {
+ fmt.Printf("Starting dns at %s:53\n", GetLocalIP())
+ err := server.ListenAndServe()
+ defer server.Shutdown()
+ if err != nil {
+ log.Printf("Failed to start dns server: %s\n ", err.Error())
+ println("you may have to use bedrockconnect")
+ }
+ }()
+}
diff --git a/go.mod b/go.mod
index 64c468b..6df81f1 100644
--- a/go.mod
+++ b/go.mod
@@ -7,6 +7,9 @@ require (
github.com/df-mc/goleveldb v1.1.9
github.com/go-gl/mathgl v1.0.0
github.com/google/gopacket v1.1.19
+ github.com/google/subcommands v1.2.0
+ github.com/google/uuid v1.3.0
+ github.com/miekg/dns v1.1.50
github.com/sandertv/gophertunnel v1.24.0
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
@@ -26,16 +29,18 @@ require (
github.com/df-mc/atomic v1.10.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
- github.com/google/uuid v1.3.0 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
github.com/sandertv/go-raknet v1.11.1 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
+ golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/text v0.3.7 // indirect
+ golang.org/x/tools v0.1.10 // indirect
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
diff --git a/go.sum b/go.sum
index 2915457..b3d4c49 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,7 @@
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9 h1:/G0ghZwrhou0Wq21qc1vXXMm/t/aKWkALWwITptKbE0=
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9/go.mod h1:TOk10ahXejq9wkEaym3KPRNeuR/h5Jx+s8QRWIa2oTM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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=
@@ -18,32 +19,41 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
+github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
+github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
+github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
+github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/muhammadmuzzammil1998/jsonc v1.0.0 h1:8o5gBQn4ZA3NBA9DlTujCj2a4w0tqWrPVjDwhzkgTIs=
github.com/muhammadmuzzammil1998/jsonc v1.0.0/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
github.com/olebeck/dragonfly v0.8.2-1 h1:hC0iWH7WFOpsvR3XeTwJSRKtKO+GhEcMq+H+DHUwHWc=
github.com/olebeck/dragonfly v0.8.2-1/go.mod h1:xgpCDhHoP03RygPaTrzzDwsSTcEZhxNPMV3CAxETj+I=
-github.com/olebeck/dragonfly v0.8.2 h1:UIFDpktsif5pzQp0ewJIOtpzbNzuKHSMCPT69HHhKyo=
-github.com/olebeck/dragonfly v0.8.2/go.mod h1:xgpCDhHoP03RygPaTrzzDwsSTcEZhxNPMV3CAxETj+I=
github.com/olebeck/gophertunnel v1.24.4 h1:nX7Std61XpXW4VP7KKd2RvinRwx1nGB5l8QnbwrArLE=
github.com/olebeck/gophertunnel v1.24.4/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
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/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sandertv/go-raknet v1.11.1 h1:0auvhHoZNyC/Z1l5xqniE3JE+w3MGO3n3JXEGHzdlRE=
github.com/sandertv/go-raknet v1.11.1/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -57,30 +67,52 @@ golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 h1:dtndE8FcEta75/4kHF3AbpuWzV6f1LjnLrM4pe2SZrw=
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
+golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
@@ -88,9 +120,13 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
diff --git a/main.go b/main.go
index a90b7eb..96ed6d3 100644
--- a/main.go
+++ b/main.go
@@ -13,6 +13,7 @@ import (
"regexp"
"syscall"
+ "github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft/auth"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
@@ -25,7 +26,6 @@ const TOKEN_FILE = "token.json"
var G_src oauth2.TokenSource
var G_xbl_token *auth.XBLToken
var G_debug bool
-var G_help bool
var G_exit []func() = []func(){}
var pool = packet.NewPool()
@@ -85,22 +85,6 @@ func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
fmt.Printf("%s 0x%x, %s\n", dir, pk.ID(), pk_name)
}
-type CMD struct {
- Name string
- Desc string
- Main func(context.Context, []string) error
-}
-
-var cmds map[string]CMD = make(map[string]CMD)
-
-func register_command(name, desc string, main_func func(context.Context, []string) error) {
- cmds[name] = CMD{
- Name: name,
- Desc: desc,
- Main: main_func,
- }
-}
-
func exit() {
fmt.Printf("\nExiting\n")
for i := len(G_exit) - 1; i >= 0; i-- { // go through cleanup functions reversed
@@ -109,12 +93,50 @@ func exit() {
os.Exit(0)
}
-func main() {
- flag.BoolVar(&G_debug, "debug", false, "debug mode")
- flag.BoolVar(&G_help, "help", false, "show help")
+var valid_cmds = make(map[string]string, 0)
+func register_command(sub subcommands.Command) {
+ subcommands.Register(sub, "")
+ valid_cmds[sub.Name()] = sub.Synopsis()
+}
+
+func main() {
ctx, cancel := context.WithCancel(context.Background())
+ flag.BoolVar(&G_debug, "debug", false, "debug mode")
+ enable_dns := flag.Bool("dns", false, "enable dns server for consoles")
+ subcommands.Register(subcommands.HelpCommand(), "")
+ subcommands.ImportantFlag("debug")
+ subcommands.ImportantFlag("dns")
+
+ { // interactive input
+ if len(os.Args) < 2 {
+ select {
+ case <-ctx.Done():
+ return
+ default:
+ fmt.Println("Available commands:")
+ for name, desc := range valid_cmds {
+ fmt.Printf("\t%s\t%s\n", name, desc)
+ }
+ fmt.Printf("Use '%s ' to run a command\n", os.Args[0])
+
+ fmt.Printf("Input Command: ")
+ reader := bufio.NewReader(os.Stdin)
+ target, _ := reader.ReadString('\n')
+ r, _ := regexp.Compile(`[\n\r]`)
+ target = string(r.ReplaceAll([]byte(target), []byte("")))
+ os.Args = append(os.Args, target)
+ }
+ }
+ }
+
+ flag.Parse()
+
+ if *enable_dns {
+ init_dns()
+ }
+
// exit cleanup
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
@@ -124,58 +146,22 @@ func main() {
exit()
}()
- // authenticate
- token := get_token()
- G_src = auth.RefreshTokenSource(&token)
- {
- _token, err := G_src.Token()
- if err != nil {
- panic(err)
- }
- G_xbl_token, err = auth.RequestXBLToken(ctx, _token, "https://pocket.realms.minecraft.net/")
- if err != nil {
- panic(err)
- }
- }
-
- if len(os.Args) < 2 {
- select {
- case <-ctx.Done():
- return
- default:
- fmt.Println("Available commands:")
- for name, cmd := range cmds {
- fmt.Printf("\t%s\t%s\n", name, cmd.Desc)
+ { // authenticate
+ token := get_token()
+ G_src = auth.RefreshTokenSource(&token)
+ {
+ _token, err := G_src.Token()
+ if err != nil {
+ panic(err)
+ }
+ G_xbl_token, err = auth.RequestXBLToken(ctx, _token, "https://pocket.realms.minecraft.net/")
+ if err != nil {
+ panic(err)
}
- fmt.Printf("Use '%s ' to run a command\n", os.Args[0])
-
- fmt.Printf("Input Command: ")
- reader := bufio.NewReader(os.Stdin)
- target, _ := reader.ReadString('\n')
- r, _ := regexp.Compile(`[\n\r]`)
- target = string(r.ReplaceAll([]byte(target), []byte("")))
- os.Args = append(os.Args, target)
}
}
- cmd := cmds[os.Args[1]]
- if cmd.Main == nil {
- fmt.Fprintf(os.Stderr, "Unknown command: %s\n", os.Args[1])
- os.Exit(1)
- }
- if err := cmd.Main(ctx, os.Args[2:]); err != nil {
- fmt.Fprintf(os.Stderr, "Error: %s\n", err)
- os.Exit(1)
- }
-
+ ret := subcommands.Execute(ctx)
exit()
-}
-
-func token_main(ctx context.Context, args []string) error {
- fmt.Printf("%s\n", G_xbl_token.AuthorizationToken.Token)
- return nil
-}
-
-func init() {
- register_command("realms-token", "get xbl3.0 token for pocket.realms.minecraft.net", token_main)
+ os.Exit(int(ret))
}
diff --git a/realms.go b/realms.go
index b7a182d..be54718 100644
--- a/realms.go
+++ b/realms.go
@@ -1,11 +1,15 @@
package main
import (
+ "context"
"encoding/json"
+ "flag"
"fmt"
"io"
"net/http"
"strings"
+
+ "github.com/google/subcommands"
)
type Realm struct {
@@ -106,3 +110,22 @@ func list_realms() error {
}
return nil
}
+
+type TokenCMD struct{}
+
+func (*TokenCMD) Name() string { return "realms-token" }
+func (*TokenCMD) Synopsis() string { return "print xbl3.0 token for realms api" }
+
+func (c *TokenCMD) SetFlags(f *flag.FlagSet) {}
+func (c *TokenCMD) Usage() string {
+ return c.Name() + ": " + c.Synopsis() + "\n"
+}
+
+func (c *TokenCMD) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
+ fmt.Printf("%s\n", G_xbl_token.AuthorizationToken.Token)
+ return 0
+}
+
+func init() {
+ register_command(&TokenCMD{})
+}
diff --git a/resourcepack-ace.go b/resourcepack-ace.go
index 66f3378..fd1d03b 100644
Binary files a/resourcepack-ace.go and b/resourcepack-ace.go differ
diff --git a/skins-proxy.go b/skins-proxy.go
index d0ac9ac..97d4819 100644
--- a/skins-proxy.go
+++ b/skins-proxy.go
@@ -7,35 +7,37 @@ import (
"fmt"
"os"
+ "github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft"
)
-func init() {
- register_command("skins-proxy", "skin stealer (proxy)", skin_proxy_main)
+type SkinProxyCMD struct {
+ server_address string
+ filter string
}
-func skin_proxy_main(ctx context.Context, args []string) error {
- var server string
- if len(args) >= 1 {
- server = args[0]
- args = args[1:]
- }
+func (*SkinProxyCMD) Name() string { return "skins-proxy" }
+func (*SkinProxyCMD) Synopsis() string { return "download skins from players on a server with proxy" }
- flag.StringVar(&skin_filter_player, "player", "", "only download the skin of this player")
- flag.CommandLine.Parse(args)
- if G_help {
- flag.Usage()
- return nil
- }
+func (c *SkinProxyCMD) SetFlags(f *flag.FlagSet) {
+ f.StringVar(&c.server_address, "address", "", "remote server address")
+ f.StringVar(&c.filter, "filter", "", "player name filter prefix")
+}
+func (c *SkinProxyCMD) Usage() string {
+ return c.Name() + ": " + c.Synopsis() + "\n"
+}
- address, hostname, err := server_input(server)
+func (c *SkinProxyCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
+ address, hostname, err := server_input(c.server_address)
if err != nil {
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
}
listener, clientConn, serverConn, err := create_proxy(ctx, address)
if err != nil {
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
}
defer listener.Close()
@@ -85,9 +87,14 @@ func skin_proxy_main(ctx context.Context, args []string) error {
for {
select {
case err := <-errs:
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
case <-ctx.Done():
- return nil
+ return 0
}
}
}
+
+func init() {
+ register_command(&SkinProxyCMD{})
+}
diff --git a/skins.go b/skins.go
index 2fb689c..bce0244 100644
--- a/skins.go
+++ b/skins.go
@@ -14,6 +14,7 @@ import (
"regexp"
"strings"
+ "github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
@@ -101,10 +102,6 @@ func (skin *Skin) Write(output_path, name string) error {
return err
}
-func init() {
- register_command("skins", "skin stealer", skin_main)
-}
-
var name_regexp = regexp.MustCompile(`§.`)
func cleanup_name(name string) string {
@@ -169,36 +166,41 @@ func process_packet_skins(conn *minecraft.Conn, out_path string, pk packet.Packe
}
}
-func skin_main(ctx context.Context, args []string) error {
- var server string
+type SkinCMD struct {
+ server_address string
+ filter string
+}
- if len(args) >= 1 {
- server = args[0]
- args = args[1:]
- }
+func (*SkinCMD) Name() string { return "skins" }
+func (*SkinCMD) Synopsis() string { return "download all skins from players on a server" }
- flag.StringVar(&skin_filter_player, "player", "", "only download the skin of this player")
- flag.CommandLine.Parse(args)
- if G_help {
- flag.Usage()
- return nil
- }
+func (c *SkinCMD) SetFlags(f *flag.FlagSet) {
+ f.StringVar(&c.server_address, "address", "", "remote server address")
+ f.StringVar(&c.filter, "filter", "", "player name filter prefix")
+}
+func (c *SkinCMD) Usage() string {
+ return c.Name() + ": " + c.Synopsis() + "\n"
+}
- address, hostname, err := server_input(server)
+func (c *SkinCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
+ address, hostname, err := server_input(c.server_address)
if err != nil {
- return err
+ fmt.Fprint(os.Stderr, err)
+ return 1
}
serverConn, err := connect_server(ctx, address, nil)
if err != nil {
- return err
+ fmt.Fprint(os.Stderr, err)
+ return 1
}
defer serverConn.Close()
out_path := fmt.Sprintf("skins/%s", hostname)
if err := serverConn.DoSpawnContext(ctx); err != nil {
- return err
+ fmt.Fprint(os.Stderr, err)
+ return 1
}
println("Connected")
@@ -209,8 +211,12 @@ func skin_main(ctx context.Context, args []string) error {
for {
pk, err := serverConn.ReadPacket()
if err != nil {
- return err
+ return 1
}
process_packet_skins(nil, out_path, pk)
}
}
+
+func init() {
+ register_command(&SkinCMD{})
+}
diff --git a/utils.go b/utils.go
index 7b124dc..a1feaef 100644
--- a/utils.go
+++ b/utils.go
@@ -8,6 +8,7 @@ import (
"log"
"net"
"os"
+ "path"
"regexp"
"strings"
@@ -192,6 +193,7 @@ var PrivateIPNetworks = []net.IPNet{
},
}
+// check if ip is private
func IPPrivate(ip net.IP) bool {
for _, ipNet := range PrivateIPNetworks {
if ipNet.Contains(ip) {
@@ -200,3 +202,53 @@ func IPPrivate(ip net.IP) bool {
}
return false
}
+
+// GetLocalIP returns the non loopback local IP of the host
+func GetLocalIP() string {
+ addrs, err := net.InterfaceAddrs()
+ if err != nil {
+ return ""
+ }
+ for _, address := range addrs {
+ // check the address type and if it is not a loopback the display it
+ if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+ if ipnet.IP.To4() != nil {
+ return ipnet.IP.String()
+ }
+ }
+ }
+ return ""
+}
+
+// get longest line length
+func max_len(lines []string) int {
+ o := 0
+ for _, line := range lines {
+ if o < len(line) {
+ o = len(line)
+ }
+ }
+ return o
+}
+
+// make text centered
+func margin_lines(lines []string) string {
+ ret := ""
+ max := max_len(lines)
+ for _, line := range lines {
+ if len(line) != max {
+ ret += strings.Repeat(" ", max/2-len(line)/4)
+ }
+ ret += line + "\n"
+ }
+ return ret
+}
+
+// split path to filename and extension
+func splitext(filename string) (name, ext string) {
+ name, ext = path.Base(filename), path.Ext(filename)
+ if ext != "" {
+ name = strings.TrimSuffix(name, ext)
+ }
+ return
+}
diff --git a/world.go b/world.go
index 228674d..82a7f5f 100644
--- a/world.go
+++ b/world.go
@@ -13,15 +13,19 @@ import (
"os"
"path"
"path/filepath"
- "strconv"
+ "strings"
"time"
"github.com/df-mc/dragonfly/server/block/cube"
+ "github.com/df-mc/dragonfly/server/entity"
+ "github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/world"
"github.com/df-mc/dragonfly/server/world/chunk"
"github.com/df-mc/dragonfly/server/world/mcdb"
"github.com/df-mc/goleveldb/leveldb/opt"
"github.com/go-gl/mathgl/mgl32"
+ "github.com/go-gl/mathgl/mgl64"
+ "github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
@@ -40,6 +44,7 @@ type TPlayerPos struct {
type WorldState struct {
chunks map[protocol.ChunkPos]*chunk.Chunk
+ entities map[int64]world.SaveableEntity
Dim world.Dimension
WorldName string
ServerName string
@@ -63,60 +68,58 @@ func NewWorldState() *WorldState {
}
}
+var setname_command = protocol.Command{
+ Name: "setname",
+ Description: "set user defined name for this world",
+ Overloads: []protocol.CommandOverload{
+ {
+ Parameters: []protocol.CommandParameter{
+ {
+ Name: "name",
+ Type: protocol.CommandArgTypeFilepath,
+ Optional: false,
+ },
+ },
+ },
+ },
+}
+
var black_16x16 = image.NewRGBA(image.Rect(0, 0, 16, 16))
func init() {
draw.Draw(black_16x16, image.Rect(0, 0, 16, 16), image.Black, image.Point{}, draw.Src)
- register_command("world", "Launch world downloading proxy", world_main)
- register_command("test-chunk", "test chunk decode", test_chunk)
+ register_command(&WorldCMD{})
}
-func test_chunk(ctx context.Context, args []string) error {
- if len(args) == 0 {
- return fmt.Errorf("not enough args")
- }
- fname, air, count := args[0], args[1], args[2]
- _air, _ := strconv.Atoi(air)
- _count, _ := strconv.Atoi(count)
- data, err := os.ReadFile(fname)
- if err != nil {
- return err
- }
-
- ch, err := chunk.NetworkDecode(uint32(_air), data, _count, cube.Range{-64, 319})
- if err != nil {
- return err
- }
- ch.Range()
- return nil
+type WorldCMD struct {
+ server_address string
}
-func world_main(ctx context.Context, args []string) error {
- var server_address string
+func (*WorldCMD) Name() string { return "worlds" }
+func (*WorldCMD) Synopsis() string { return "download a world from a server" }
- if len(args) >= 1 {
- server_address = args[0]
- args = args[1:]
- }
+func (p *WorldCMD) SetFlags(f *flag.FlagSet) {
+ f.StringVar(&p.server_address, "address", "", "remote server address")
+}
+func (c *WorldCMD) Usage() string {
+ return c.Name() + ": " + c.Synopsis() + "\n"
+}
- flag.CommandLine.Parse(args)
- if G_help {
- flag.Usage()
- return nil
- }
-
- server_address, hostname, err := server_input(server_address)
+func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
+ server_address, hostname, err := server_input(c.server_address)
if err != nil {
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
}
listener, clientConn, serverConn, err := create_proxy(ctx, server_address)
if err != nil {
- return err
+ fmt.Fprintln(os.Stderr, err)
+ return 1
}
handleConn(ctx, listener, clientConn, serverConn, hostname)
- return nil
+ return 0
}
var dimension_ids = map[int32]world.Dimension{
@@ -201,6 +204,19 @@ func (w *WorldState) ProcessAnimate(pk *packet.Animate) {
}
}
+func (w *WorldState) ProcessAddItemActor(pk *packet.AddItemActor) {
+ it, ok := world.ItemByRuntimeID(pk.Item.StackNetworkID, int16(pk.Item.Stack.MetadataValue))
+ if !ok {
+ return
+ }
+ stack := item.NewStack(it, int(pk.Item.Stack.Count))
+ w.entities[pk.EntityUniqueID] = entity.NewItem(stack, mgl64.Vec3{
+ float64(pk.Position[0]),
+ float64(pk.Position[1]),
+ float64(pk.Position[2]),
+ })
+}
+
func (w *WorldState) ProcessChangeDimension(pk *packet.ChangeDimension) {
fmt.Printf("ChangeDimension %d\n", pk.Dimension)
if len(w.chunks) > 0 {
@@ -212,6 +228,23 @@ func (w *WorldState) ProcessChangeDimension(pk *packet.ChangeDimension) {
w.Dim = dimension_ids[pk.Dimension]
}
+func (w *WorldState) SendMessage(text string) {
+ w.ClientConn.WritePacket(&packet.Text{
+ TextType: packet.TextTypeSystem,
+ Message: "§8[§bBedrocktool§8]§r " + text,
+ })
+}
+
+func (w *WorldState) ProcessCommand(pk *packet.CommandRequest) bool {
+ cmd := strings.Split(pk.CommandLine, " ")
+ if cmd[0] == "/setname" && len(cmd) >= 2 {
+ w.WorldName = strings.Join(cmd[1:], " ")
+ w.SendMessage(fmt.Sprintf("worldName is now: %s", w.WorldName))
+ return true
+ }
+ return false
+}
+
func (w *WorldState) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
w.PlayerPos = TPlayerPos{
Position: Position,
@@ -223,13 +256,14 @@ func (w *WorldState) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float
func (w *WorldState) Reset() {
w.chunks = make(map[protocol.ChunkPos]*chunk.Chunk)
+ w.WorldName = "world"
w.ui.Reset()
}
// writes the world to a folder, resets all the chunks
func (w *WorldState) SaveAndReset() {
fmt.Println("Saving world")
- folder := path.Join("worlds", fmt.Sprintf("%s/world-%d", w.ServerName, w.worldCounter))
+ folder := path.Join("worlds", fmt.Sprintf("%s/%s-%d", w.ServerName, w.WorldName, w.worldCounter))
os.MkdirAll(folder, 0777)
provider, err := mcdb.New(folder, opt.DefaultCompression)
if err != nil {
@@ -239,6 +273,9 @@ func (w *WorldState) SaveAndReset() {
for cp, c := range w.chunks {
provider.SaveChunk((world.ChunkPos)(cp), c, w.Dim)
}
+
+ //provider.SaveEntities(w.entities)
+
s := provider.Settings()
s.Spawn = cube.Pos{
int(w.PlayerPos.Position[0]),
@@ -356,6 +393,8 @@ func handleConn(ctx context.Context, l *minecraft.Listener, cc, sc *minecraft.Co
w.ClientConn = cc
w.ServerConn = sc
+ w.SendMessage("use /setname \nto set the world name")
+
G_exit = append(G_exit, func() {
w.SaveAndReset()
})
@@ -387,6 +426,8 @@ func handleConn(ctx context.Context, l *minecraft.Listener, cc, sc *minecraft.Co
skip = true
case *packet.Animate:
w.ProcessAnimate(pk)
+ case *packet.CommandRequest:
+ skip = w.ProcessCommand(pk)
}
if !skip {
@@ -438,9 +479,13 @@ func handleConn(ctx context.Context, l *minecraft.Listener, cc, sc *minecraft.Co
case *packet.LevelChunk:
w.ProcessLevelChunk(pk)
w.ui.Send(w)
- send_popup(w.ClientConn, fmt.Sprintf("%d chunks loaded\n", len(w.chunks)))
+ send_popup(w.ClientConn, fmt.Sprintf("%d chunks loaded\nname: %s", len(w.chunks), w.WorldName))
case *packet.SubChunk:
w.ProcessSubChunk(pk)
+ case *packet.AddItemActor:
+ w.ProcessAddItemActor(pk)
+ case *packet.AvailableCommands:
+ pk.Commands = append(pk.Commands, setname_command)
}
if err := w.ClientConn.WritePacket(pk); err != nil {