replace cli interface, add dns and /setname command
This commit is contained in:
parent
12b7ff0822
commit
1c68978e50
29
Readme.md
29
Readme.md
|
@ -2,18 +2,21 @@
|
|||
|
||||
## [releases](https://github.com/bedrock-tool/bedrocktool/releases)
|
||||
|
||||
<pre>
|
||||
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)
|
||||
</pre>
|
||||
```
|
||||
Usage: bedrocktool <flags> <subcommand> <subcommand args>
|
||||
|
||||
usage:
|
||||
`./bedrocktool-<version>.exe <function> <address> [-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
|
||||
```
|
46
capture.go
46
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}()
|
||||
}
|
7
go.mod
7
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
|
||||
|
|
40
go.sum
40
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=
|
||||
|
|
124
main.go
124
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 <command>' 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 <command>' 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))
|
||||
}
|
||||
|
|
23
realms.go
23
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{})
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -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{})
|
||||
}
|
||||
|
|
48
skins.go
48
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{})
|
||||
}
|
||||
|
|
52
utils.go
52
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
|
||||
}
|
||||
|
|
123
world.go
123
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 <worldname>\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 {
|
||||
|
|
Loading…
Reference in New Issue