bedrocktool/utils/replay.go

205 lines
4.9 KiB
Go
Raw Normal View History

2022-09-04 14:26:32 +00:00
package utils
2022-09-03 22:56:40 +00:00
import (
"bytes"
2022-09-03 22:56:40 +00:00
"context"
"encoding/binary"
2023-02-08 11:00:36 +00:00
"fmt"
"io"
"net"
2022-09-03 22:56:40 +00:00
"os"
2023-02-08 11:00:36 +00:00
"time"
2022-09-03 22:56:40 +00:00
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol"
2022-09-04 00:24:58 +00:00
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
2022-09-03 22:56:40 +00:00
"github.com/sirupsen/logrus"
)
2023-02-08 11:00:36 +00:00
type replayHeader struct {
Version int32
}
var replayMagic = []byte("BTCP")
const (
currentReplayVersion = 2
)
func WriteReplayHeader(f io.Writer) {
f.Write(replayMagic)
header := replayHeader{
Version: currentReplayVersion,
}
binary.Write(f, binary.LittleEndian, &header)
}
2023-03-23 19:39:47 +00:00
func createReplayConnection(ctx context.Context, filename string, proxy *ProxyContext) error {
logrus.Infof("Reading replay %s", filename)
2022-09-04 00:24:58 +00:00
2022-09-03 22:56:40 +00:00
f, err := os.Open(filename)
if err != nil {
return err
}
2023-02-08 11:00:36 +00:00
stat, err := f.Stat()
if err != nil {
return err
}
totalSize := stat.Size()
// default version is version 1, since that didnt have a header
ver := 1
magic := make([]byte, 4)
io.ReadAtLeast(f, magic, 4)
if bytes.Equal(magic, replayMagic) {
var header replayHeader
if err := binary.Read(f, binary.LittleEndian, &header); err != nil {
return err
}
2023-02-08 11:00:36 +00:00
ver = int(header.Version)
} else {
logrus.Info("Version 1 capture assumed.")
f.Seek(-4, io.SeekCurrent)
2022-09-03 22:56:40 +00:00
}
2023-04-02 14:49:24 +00:00
server, client := &net.UDPAddr{
IP: net.IPv4(1, 1, 1, 1),
}, &net.UDPAddr{
IP: net.IPv4(2, 2, 2, 2),
}
2023-04-04 01:51:13 +00:00
proxy.clientAddr = client
2023-04-02 14:49:24 +00:00
2022-09-04 14:26:32 +00:00
proxy.Server = minecraft.NewConn()
2022-09-03 22:56:40 +00:00
2023-01-29 21:20:13 +00:00
gameStarted := false
i := 0
2022-09-03 22:56:40 +00:00
for {
i += 1
2022-10-14 22:42:43 +00:00
var magic uint32 = 0
2023-01-29 21:20:13 +00:00
var packetLength uint32 = 0
var toServer bool = false
2023-02-08 11:00:36 +00:00
timeReceived := time.Now()
offset, _ := f.Seek(0, io.SeekCurrent)
2023-02-08 11:00:36 +00:00
if offset == totalSize {
logrus.Info("Reached End")
2023-04-04 01:51:13 +00:00
break
2022-09-03 22:56:40 +00:00
}
2022-10-14 22:42:43 +00:00
binary.Read(f, binary.LittleEndian, &magic)
if magic != 0xAAAAAAAA {
2023-02-08 11:00:36 +00:00
return fmt.Errorf("wrong Magic")
2022-10-14 22:42:43 +00:00
}
2023-01-29 21:20:13 +00:00
binary.Read(f, binary.LittleEndian, &packetLength)
binary.Read(f, binary.LittleEndian, &toServer)
2023-02-08 11:00:36 +00:00
if ver >= 2 {
var timeMs int64
binary.Read(f, binary.LittleEndian, &timeMs)
timeReceived = time.UnixMilli(timeMs)
}
2023-01-29 21:20:13 +00:00
payload := make([]byte, packetLength)
n, err := f.Read(payload)
if err != nil {
logrus.Error(err)
2023-04-04 01:51:13 +00:00
break
}
2023-01-29 21:20:13 +00:00
if n != int(packetLength) {
2023-02-08 11:00:36 +00:00
return fmt.Errorf("truncated %d", i)
2022-09-04 00:24:58 +00:00
}
2022-09-03 22:56:40 +00:00
2022-10-14 22:42:43 +00:00
var magic2 uint32
binary.Read(f, binary.LittleEndian, &magic2)
if magic2 != 0xBBBBBBBB {
2023-02-08 11:00:36 +00:00
return fmt.Errorf("wrong Magic2")
2022-10-14 22:42:43 +00:00
}
2023-01-29 21:20:13 +00:00
pkData, err := minecraft.ParseData(payload, proxy.Server)
2022-09-03 22:56:40 +00:00
if err != nil {
return err
}
2023-01-29 21:20:13 +00:00
pks, err := pkData.Decode(proxy.Server)
2022-09-03 22:56:40 +00:00
if err != nil {
logrus.Error(err)
2022-09-03 22:56:40 +00:00
continue
}
for _, pk := range pks {
f := bytes.NewBuffer(nil)
b := protocol.NewWriter(f, 0)
pk.Marshal(b)
2023-04-02 14:49:24 +00:00
hdr := packet.Header{PacketID: pk.ID()}
var src, dst net.Addr
if toServer {
src = client
dst = server
} else {
src = server
dst = client
}
for _, handler := range proxy.handlers {
if handler.PacketFunc != nil {
handler.PacketFunc(hdr, f.Bytes(), src, dst)
}
}
2023-01-29 21:20:13 +00:00
if gameStarted {
2023-04-02 14:49:24 +00:00
for _, handler := range proxy.handlers {
if handler.PacketCB != nil {
handler.PacketCB(pk, toServer, timeReceived)
}
2022-09-04 13:24:55 +00:00
}
2022-09-03 22:56:40 +00:00
} else {
2022-09-04 13:24:55 +00:00
switch pk := pk.(type) {
case *packet.StartGame:
2022-09-04 14:26:32 +00:00
proxy.Server.SetGameData(minecraft.GameData{
2022-09-04 13:24:55 +00:00
WorldName: pk.WorldName,
WorldSeed: pk.WorldSeed,
Difficulty: pk.Difficulty,
EntityUniqueID: pk.EntityUniqueID,
EntityRuntimeID: pk.EntityRuntimeID,
PlayerGameMode: pk.PlayerGameMode,
PersonaDisabled: pk.PersonaDisabled,
CustomSkinsDisabled: pk.CustomSkinsDisabled,
BaseGameVersion: pk.BaseGameVersion,
PlayerPosition: pk.PlayerPosition,
Pitch: pk.Pitch,
Yaw: pk.Yaw,
Dimension: pk.Dimension,
WorldSpawn: pk.WorldSpawn,
EditorWorld: pk.EditorWorld,
WorldGameMode: pk.WorldGameMode,
GameRules: pk.GameRules,
Time: pk.Time,
ServerBlockStateChecksum: pk.ServerBlockStateChecksum,
CustomBlocks: pk.Blocks,
Items: pk.Items,
PlayerMovementSettings: pk.PlayerMovementSettings,
ServerAuthoritativeInventory: pk.ServerAuthoritativeInventory,
Experiments: pk.Experiments,
ClientSideGeneration: pk.ClientSideGeneration,
ChatRestrictionLevel: pk.ChatRestrictionLevel,
DisablePlayerInteractions: pk.DisablePlayerInteractions,
})
2023-01-29 21:20:13 +00:00
gameStarted = true
2023-04-02 14:49:24 +00:00
for _, handler := range proxy.handlers {
if handler.ConnectCB != nil {
handler.ConnectCB(nil)
}
2022-09-04 13:24:55 +00:00
}
}
2022-09-03 22:56:40 +00:00
}
}
2023-04-04 01:51:13 +00:00
}
for _, handler := range proxy.handlers {
if handler.OnEnd != nil {
handler.OnEnd()
2023-04-02 14:49:24 +00:00
}
2022-09-03 22:56:40 +00:00
}
2023-04-04 01:51:13 +00:00
return nil
2022-09-03 22:56:40 +00:00
}