mirror of
https://github.com/CosmicStar98/bedrocktool.git
synced 2024-06-09 10:39:45 +00:00
add replay proxy
This commit is contained in:
parent
4a9451b7f0
commit
d770b979f1
12
capture.go
12
capture.go
|
@ -43,12 +43,16 @@ func dump_packet(from_client bool, w *pcapgo.Writer, pk packet.Packet) {
|
||||||
dst_ip = SrcIp_client
|
dst_ip = SrcIp_client
|
||||||
}
|
}
|
||||||
|
|
||||||
var packet_data []byte
|
packet_data := bytes.NewBuffer(nil)
|
||||||
{
|
{
|
||||||
_pw := bytes.NewBuffer(nil)
|
_pw := bytes.NewBuffer(nil)
|
||||||
pw := protocol.NewWriter(_pw, 0x0)
|
pw := protocol.NewWriter(_pw, 0x0)
|
||||||
pk.Marshal(pw)
|
pk.Marshal(pw)
|
||||||
packet_data = _pw.Bytes()
|
h := packet.Header{
|
||||||
|
PacketID: pk.ID(),
|
||||||
|
}
|
||||||
|
h.Write(packet_data)
|
||||||
|
packet_data.Write(_pw.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize_buf := gopacket.NewSerializeBuffer()
|
serialize_buf := gopacket.NewSerializeBuffer()
|
||||||
|
@ -58,9 +62,9 @@ func dump_packet(from_client bool, w *pcapgo.Writer, pk packet.Packet) {
|
||||||
&layers.IPv4{
|
&layers.IPv4{
|
||||||
SrcIP: src_ip,
|
SrcIP: src_ip,
|
||||||
DstIP: dst_ip,
|
DstIP: dst_ip,
|
||||||
Length: uint16(len(packet_data)),
|
Length: uint16(packet_data.Len()),
|
||||||
},
|
},
|
||||||
gopacket.Payload(packet_data),
|
gopacket.Payload(packet_data.Bytes()),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -21,7 +21,7 @@ require (
|
||||||
|
|
||||||
//replace github.com/df-mc/dragonfly => ./dragonfly
|
//replace github.com/df-mc/dragonfly => ./dragonfly
|
||||||
|
|
||||||
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.24.8-3
|
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.24.8-4
|
||||||
|
|
||||||
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.8.3-0.20220902161600-2f9b3652bbb7
|
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.8.3-0.20220902161600-2f9b3652bbb7
|
||||||
|
|
||||||
|
|
17
map_item.go
17
map_item.go
|
@ -181,13 +181,16 @@ func (m *MapUI) Send(w *WorldState) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
m.send_lock.Unlock()
|
m.send_lock.Unlock()
|
||||||
return w.proxy.client.WritePacket(&packet.ClientBoundMapItemData{
|
if w.proxy.client != nil {
|
||||||
MapID: VIEW_MAP_ID,
|
return w.proxy.client.WritePacket(&packet.ClientBoundMapItemData{
|
||||||
Width: 128,
|
MapID: VIEW_MAP_ID,
|
||||||
Height: 128,
|
Width: 128,
|
||||||
Pixels: img2rgba(m.img),
|
Height: 128,
|
||||||
UpdateFlags: 2,
|
Pixels: img2rgba(m.img),
|
||||||
})
|
UpdateFlags: 2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MapUI) SetChunk(pos protocol.ChunkPos, ch *chunk.Chunk) {
|
func (m *MapUI) SetChunk(pos protocol.ChunkPos, ch *chunk.Chunk) {
|
||||||
|
|
28
proxy.go
28
proxy.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/sandertv/gophertunnel/minecraft"
|
"github.com/sandertv/gophertunnel/minecraft"
|
||||||
|
@ -35,11 +36,30 @@ type ProxyContext struct {
|
||||||
client *minecraft.Conn
|
client *minecraft.Conn
|
||||||
listener *minecraft.Listener
|
listener *minecraft.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
PacketCallback func(pk packet.Packet, proxy *ProxyContext, toServer bool) (packet.Packet, error)
|
PacketCallback func(pk packet.Packet, proxy *ProxyContext, toServer bool) (packet.Packet, error)
|
||||||
ConnectCallback func(proxy *ProxyContext)
|
ConnectCallback func(proxy *ProxyContext)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (p *ProxyContext) sendMessage(text string) {
|
||||||
|
if p.client != nil {
|
||||||
|
p.client.WritePacket(&packet.Text{
|
||||||
|
TextType: packet.TextTypeSystem,
|
||||||
|
Message: "§8[§bBedrocktool§8]§r " + text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProxyContext) sendPopup(text string) {
|
||||||
|
if p.client != nil {
|
||||||
|
p.client.WritePacket(&packet.Text{
|
||||||
|
TextType: packet.TextTypePopup,
|
||||||
|
Message: text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func proxyLoop(ctx context.Context, proxy *ProxyContext, toServer bool, packetCBs []PacketCallback) error {
|
func proxyLoop(ctx context.Context, proxy *ProxyContext, toServer bool, packetCBs []PacketCallback) error {
|
||||||
var c1, c2 *minecraft.Conn
|
var c1, c2 *minecraft.Conn
|
||||||
if toServer {
|
if toServer {
|
||||||
|
@ -79,11 +99,9 @@ func proxyLoop(ctx context.Context, proxy *ProxyContext, toServer bool, packetCB
|
||||||
}
|
}
|
||||||
|
|
||||||
func create_proxy(ctx context.Context, log *logrus.Logger, server_address string, onConnect ConnectCallback, packetCB PacketCallback) (err error) {
|
func create_proxy(ctx context.Context, log *logrus.Logger, server_address string, onConnect ConnectCallback, packetCB PacketCallback) (err error) {
|
||||||
/*
|
if strings.HasSuffix(server_address, ".pcap") {
|
||||||
if strings.HasSuffix(server_address, ".pcap") {
|
return create_replay_connection(ctx, log, server_address, onConnect, packetCB)
|
||||||
return create_replay_connection(server_address)
|
}
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
GetTokenSource() // ask for login before listening
|
GetTokenSource() // ask for login before listening
|
||||||
|
|
||||||
|
|
100
replay.go
Normal file
100
replay.go
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
"github.com/google/gopacket/pcapgo"
|
||||||
|
"github.com/sandertv/gophertunnel/minecraft"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetUnexportedField(field reflect.Value, value interface{}) {
|
||||||
|
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
|
||||||
|
Elem().
|
||||||
|
Set(reflect.ValueOf(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
type PayloadDecoder struct {
|
||||||
|
Payload []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d PayloadDecoder) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func create_replay_connection(ctx context.Context, log *logrus.Logger, filename string, onConnect ConnectCallback, packetCB PacketCallback) error {
|
||||||
|
fmt.Printf("Reading replay %s\n", filename)
|
||||||
|
|
||||||
|
f, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reader, err := pcapgo.NewReader(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
SetUnexportedField(reflect.ValueOf(reader).Elem().Field(5), uint32(0xFFFFFFFF))
|
||||||
|
|
||||||
|
dummy_conn := minecraft.NewConn()
|
||||||
|
dummy_conn.SetGameData(minecraft.GameData{
|
||||||
|
BaseGameVersion: "1.17.40", // SPECIFIC TO THE SERVER; TODO
|
||||||
|
})
|
||||||
|
|
||||||
|
proxy := ProxyContext{}
|
||||||
|
proxy.server = dummy_conn
|
||||||
|
|
||||||
|
if onConnect != nil {
|
||||||
|
onConnect(&proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FOR OLD BROKEN CAPTURES
|
||||||
|
fake_head := packet.Header{
|
||||||
|
PacketID: packet.IDLevelChunk,
|
||||||
|
}
|
||||||
|
fake_header_w := bytes.NewBuffer(nil)
|
||||||
|
fake_head.Write(fake_header_w)
|
||||||
|
fake_header := fake_header_w.Bytes()
|
||||||
|
*/
|
||||||
|
|
||||||
|
start := time.Time{}
|
||||||
|
for {
|
||||||
|
data, ci, err := reader.ReadPacketData()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if start.Unix() == 0 {
|
||||||
|
start = ci.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := data[0x14:]
|
||||||
|
if len(payload) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// payload = append(fake_header, payload...)
|
||||||
|
|
||||||
|
pk_data, err := minecraft.ParseData(payload, dummy_conn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pks, err := pk_data.Decode(dummy_conn)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pk := range pks {
|
||||||
|
if data[0x10] == 127 { // to client
|
||||||
|
packetCB(pk, &proxy, false)
|
||||||
|
} else {
|
||||||
|
packetCB(pk, &proxy, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
skins.go
15
skins.go
|
@ -129,7 +129,7 @@ func (skin *Skin) Write(output_path, name string) error {
|
||||||
|
|
||||||
have_geometry, have_cape, have_animations, have_tint := len(skin.SkinGeometry) > 0, len(skin.CapeData) > 0, len(skin.Animations) > 0, len(skin.PieceTintColours) > 0
|
have_geometry, have_cape, have_animations, have_tint := len(skin.SkinGeometry) > 0, len(skin.CapeData) > 0, len(skin.Animations) > 0, len(skin.PieceTintColours) > 0
|
||||||
|
|
||||||
os.MkdirAll(skin_dir, 0755)
|
os.MkdirAll(skin_dir, 0o755)
|
||||||
if have_geometry {
|
if have_geometry {
|
||||||
if err := skin.WriteGeometry(path.Join(skin_dir, "geometry.json")); err != nil {
|
if err := skin.WriteGeometry(path.Join(skin_dir, "geometry.json")); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -188,9 +188,11 @@ func write_skin(output_path, name string, skin protocol.Skin, filter string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var skin_players = make(map[string]string)
|
var (
|
||||||
var skin_player_counts = make(map[string]int)
|
skin_players = make(map[string]string)
|
||||||
var processed_skins = make(map[string]bool)
|
skin_player_counts = make(map[string]int)
|
||||||
|
processed_skins = make(map[string]bool)
|
||||||
|
)
|
||||||
|
|
||||||
func process_packet_skins(conn *minecraft.Conn, out_path string, pk packet.Packet, filter string) {
|
func process_packet_skins(conn *minecraft.Conn, out_path string, pk packet.Packet, filter string) {
|
||||||
switch _pk := pk.(type) {
|
switch _pk := pk.(type) {
|
||||||
|
@ -218,7 +220,7 @@ func process_packet_skins(conn *minecraft.Conn, out_path string, pk packet.Packe
|
||||||
skin_players[player.UUID.String()] = name
|
skin_players[player.UUID.String()] = name
|
||||||
processed_skins[name] = true
|
processed_skins[name] = true
|
||||||
if conn != nil {
|
if conn != nil {
|
||||||
send_popup(conn, fmt.Sprintf("%s Skin was Saved", name))
|
(&ProxyContext{client: conn}).sendPopup(fmt.Sprintf("%s Skin was Saved", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,6 +238,7 @@ func (c *SkinCMD) SetFlags(f *flag.FlagSet) {
|
||||||
f.StringVar(&c.server_address, "address", "", "remote server address")
|
f.StringVar(&c.server_address, "address", "", "remote server address")
|
||||||
f.StringVar(&c.filter, "filter", "", "player name filter prefix")
|
f.StringVar(&c.filter, "filter", "", "player name filter prefix")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SkinCMD) Usage() string {
|
func (c *SkinCMD) Usage() string {
|
||||||
return c.Name() + ": " + c.Synopsis() + "\n"
|
return c.Name() + ": " + c.Synopsis() + "\n"
|
||||||
}
|
}
|
||||||
|
@ -264,7 +267,7 @@ func (c *SkinCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}
|
||||||
println("Connected")
|
println("Connected")
|
||||||
println("Press ctrl+c to exit")
|
println("Press ctrl+c to exit")
|
||||||
|
|
||||||
os.MkdirAll(out_path, 0755)
|
os.MkdirAll(out_path, 0o755)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
pk, err := serverConn.ReadPacket()
|
pk, err := serverConn.ReadPacket()
|
||||||
|
|
14
utils.go
14
utils.go
|
@ -39,20 +39,6 @@ const SERVER_ADDRESS_HELP = `accepted server address formats:
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
func send_popup(conn *minecraft.Conn, text string) {
|
|
||||||
conn.WritePacket(&packet.Text{
|
|
||||||
TextType: packet.TextTypePopup,
|
|
||||||
Message: text,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func send_message(conn *minecraft.Conn, text string) {
|
|
||||||
conn.WritePacket(&packet.Text{
|
|
||||||
TextType: packet.TextTypeSystem,
|
|
||||||
Message: "§8[§bBedrocktool§8]§r " + text,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func server_input(server string) (address, name string, err error) {
|
func server_input(server string) (address, name string, err error) {
|
||||||
if server == "" { // no arg provided, interactive input
|
if server == "" { // no arg provided, interactive input
|
||||||
fmt.Printf("Enter Server: ")
|
fmt.Printf("Enter Server: ")
|
||||||
|
|
16
world.go
16
world.go
|
@ -109,13 +109,13 @@ var IngameCommands = map[string]IngameCommand{
|
||||||
|
|
||||||
func setnameCommand(w *WorldState, cmdline []string) bool {
|
func setnameCommand(w *WorldState, cmdline []string) bool {
|
||||||
w.WorldName = strings.Join(cmdline, " ")
|
w.WorldName = strings.Join(cmdline, " ")
|
||||||
send_message(w.proxy.client, fmt.Sprintf("worldName is now: %s", w.WorldName))
|
w.proxy.sendMessage(fmt.Sprintf("worldName is now: %s", w.WorldName))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func toggleVoid(w *WorldState, cmdline []string) bool {
|
func toggleVoid(w *WorldState, cmdline []string) bool {
|
||||||
w.voidgen = !w.voidgen
|
w.voidgen = !w.voidgen
|
||||||
send_message(w.proxy.client, fmt.Sprintf("using void generator: %t", w.voidgen))
|
w.proxy.sendMessage(fmt.Sprintf("using void generator: %t", w.voidgen))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,7 +496,7 @@ func (w *WorldState) OnConnect(proxy *ProxyContext) {
|
||||||
w.Dim = dimension_ids[uint8(dim_id)]
|
w.Dim = dimension_ids[uint8(dim_id)]
|
||||||
}
|
}
|
||||||
|
|
||||||
send_message(w.proxy.client, "use /setname <worldname>\nto set the world name")
|
w.proxy.sendMessage("use /setname <worldname>\nto set the world name")
|
||||||
|
|
||||||
G_exit = append(G_exit, func() {
|
G_exit = append(G_exit, func() {
|
||||||
w.SaveAndReset()
|
w.SaveAndReset()
|
||||||
|
@ -509,9 +509,11 @@ func (w *WorldState) OnConnect(proxy *ProxyContext) {
|
||||||
default:
|
default:
|
||||||
t := time.NewTimer(1 * time.Second)
|
t := time.NewTimer(1 * time.Second)
|
||||||
for range t.C {
|
for range t.C {
|
||||||
err := w.proxy.client.WritePacket(&MAP_ITEM_PACKET)
|
if w.proxy.client != nil {
|
||||||
if err != nil {
|
err := w.proxy.client.WritePacket(&MAP_ITEM_PACKET)
|
||||||
return
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -550,7 +552,7 @@ func (w *WorldState) ProcessPacketServer(pk packet.Packet) packet.Packet {
|
||||||
case *packet.LevelChunk:
|
case *packet.LevelChunk:
|
||||||
w.ProcessLevelChunk(pk)
|
w.ProcessLevelChunk(pk)
|
||||||
w.ui.Send(w)
|
w.ui.Send(w)
|
||||||
send_popup(w.proxy.client, fmt.Sprintf("%d chunks loaded\nname: %s", len(w.chunks), w.WorldName))
|
w.proxy.sendPopup(fmt.Sprintf("%d chunks loaded\nname: %s", len(w.chunks), w.WorldName))
|
||||||
case *packet.SubChunk:
|
case *packet.SubChunk:
|
||||||
w.ProcessSubChunk(pk)
|
w.ProcessSubChunk(pk)
|
||||||
case *packet.AvailableCommands:
|
case *packet.AvailableCommands:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user