move proxy code into one file

This commit is contained in:
olebeck 2022-09-03 19:32:30 +02:00
parent 88be34091a
commit c7c4512108
8 changed files with 348 additions and 339 deletions

View File

@ -17,10 +17,13 @@ import (
"github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sirupsen/logrus"
)
var SrcIp_client = net.IPv4(127, 0, 0, 1)
var SrcIp_server = net.IPv4(243, 0, 0, 2)
var (
SrcIp_client = net.IPv4(127, 0, 0, 1)
SrcIp_server = net.IPv4(243, 0, 0, 2)
)
func init() {
register_command(&CaptureCMD{})
@ -84,18 +87,15 @@ 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" + SERVER_ADDRESS_HELP
}
func (c *CaptureCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
address, hostname, err := server_input(c.server_address)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
log := logrus.New()
listener, serverConn, clientConn, err := create_proxy(ctx, address)
address, hostname, err := server_input(c.server_address)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
@ -112,44 +112,15 @@ func (c *CaptureCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interfac
_wl := sync.Mutex{}
go func() {
defer listener.Disconnect(clientConn, "connection lost")
defer serverConn.Close()
for {
pk, err := clientConn.ReadPacket()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read packet: %s\n", err)
return
}
_wl.Lock()
dump_packet(true, w, pk)
_wl.Unlock()
err = serverConn.WritePacket(pk)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write packet: %s\n", err)
return
}
}
}()
for {
pk, err := serverConn.ReadPacket()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read packet: %s\n", err)
return 1
}
err = create_proxy(ctx, log, address, nil, func(pk packet.Packet, proxy *ProxyContext, toServer bool) (packet.Packet, error) {
_wl.Lock()
dump_packet(false, w, pk)
dump_packet(toServer, w, pk)
_wl.Unlock()
err = clientConn.WritePacket(pk)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write packet: %s\n", err)
return 1
}
return pk, nil
})
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
return 0
}

View File

@ -10,26 +10,7 @@ import (
"github.com/df-mc/dragonfly/server/world/chunk"
)
func chunkGetColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) color.RGBA {
p := cube.Pos{int(x), int(y), int(z)}
have_up := false
p.Side(cube.FaceUp).Neighbours(func(neighbour cube.Pos) {
if neighbour.X() < 0 || neighbour.X() >= 16 || neighbour.Z() < 0 || neighbour.Z() >= 16 {
return
}
if !have_up {
block_rid := c.Block(uint8(neighbour[0]), int16(neighbour[1]), uint8(neighbour[2]), 0)
b, found := world.BlockByRuntimeID(block_rid)
if found {
if _, ok := b.(block.Air); !ok {
if _, ok := b.(block.Water); !ok {
have_up = true
}
}
}
}
}, cube.Range{int(y + 1), int(y + 1)})
func blockColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) color.RGBA {
col := color.RGBA{0, 0, 0, 255}
block_rid := c.Block(x, y, z, 0)
if block_rid == 0 && y == 0 { // void
@ -47,6 +28,30 @@ func chunkGetColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) color.RGBA {
}
*/
}
return col
}
func chunkGetColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) color.RGBA {
p := cube.Pos{int(x), int(y), int(z)}
have_up := false
p.Side(cube.FaceUp).Neighbours(func(neighbour cube.Pos) {
if neighbour.X() < 0 || neighbour.X() >= 16 || neighbour.Z() < 0 || neighbour.Z() >= 16 {
return
}
if !have_up {
block_rid := c.Block(uint8(neighbour[0]), int16(neighbour[1]), uint8(neighbour[2]), 0)
if block_rid > 0 {
b, found := world.BlockByRuntimeID(block_rid)
if found {
if _, ok := b.(block.Air); !ok {
have_up = true
}
}
}
}
}, cube.Range{int(y + 1), int(y + 1)})
col := blockColorAt(c, x, y, z)
if have_up {
if col.R > 10 {
@ -75,11 +80,9 @@ func Chunk2Img(c *chunk.Chunk) *image.RGBA {
col := chunkGetColorAt(c, x, height, z)
if height_liquid > height {
bw := &block.Water{}
wcol := bw.Color()
col.R = col.R/2 + wcol.R/2
col.G = col.G/2 + wcol.G/2
col.B = col.B/2 + wcol.B/2
bw := (&block.Water{}).Color()
bw.A = uint8(clamp(int(127+(height_liquid-height)*5), 255))
col = blendColors(col, bw)
}
img.SetRGBA(int(x), int(z), col)

View File

@ -181,7 +181,7 @@ func (m *MapUI) Send(w *WorldState) error {
}
m.send_lock.Unlock()
return w.ClientConn.WritePacket(&packet.ClientBoundMapItemData{
return w.proxy.client.WritePacket(&packet.ClientBoundMapItemData{
MapID: VIEW_MAP_ID,
Width: 128,
Height: 128,

167
proxy.go Normal file
View File

@ -0,0 +1,167 @@
package main
import (
"context"
"errors"
"fmt"
"sync"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sandertv/gophertunnel/minecraft/resource"
"github.com/sirupsen/logrus"
)
var G_disconnect_reason = "Connection lost"
type dummyProto struct {
id int32
ver string
}
func (p dummyProto) ID() int32 { return p.id }
func (p dummyProto) Ver() string { return p.ver }
func (p dummyProto) Packets() packet.Pool { return packet.NewPool() }
func (p dummyProto) ConvertToLatest(pk packet.Packet, _ *minecraft.Conn) []packet.Packet {
return []packet.Packet{pk}
}
func (p dummyProto) ConvertFromLatest(pk packet.Packet, _ *minecraft.Conn) []packet.Packet {
return []packet.Packet{pk}
}
type ProxyContext struct {
server *minecraft.Conn
client *minecraft.Conn
listener *minecraft.Listener
}
type (
PacketCallback func(pk packet.Packet, proxy *ProxyContext, toServer bool) (packet.Packet, error)
ConnectCallback func(proxy *ProxyContext)
)
func proxyLoop(ctx context.Context, proxy *ProxyContext, toServer bool, packetCBs []PacketCallback) error {
var c1, c2 *minecraft.Conn
if toServer {
c1 = proxy.client
c2 = proxy.server
} else {
c1 = proxy.server
c2 = proxy.client
}
for {
if ctx.Err() != nil {
return ctx.Err()
}
pk, err := c1.ReadPacket()
if err != nil {
return err
}
for _, packetCB := range packetCBs {
pk, err = packetCB(pk, proxy, toServer)
if err != nil {
return err
}
}
if pk != nil {
if err := c2.WritePacket(pk); err != nil {
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
G_disconnect_reason = disconnect.Error()
}
return err
}
}
}
}
func create_proxy(ctx context.Context, log *logrus.Logger, server_address string, onConnect ConnectCallback, packetCB PacketCallback) (err error) {
/*
if strings.HasSuffix(server_address, ".pcap") {
return create_replay_connection(server_address)
}
*/
GetTokenSource() // ask for login before listening
proxy := ProxyContext{}
var packs []*resource.Pack
if G_preload_packs {
fmt.Println("Preloading resourcepacks")
serverConn, err := connect_server(ctx, server_address, nil, true)
if err != nil {
return fmt.Errorf("failed to connect to %s: %s", server_address, err)
}
serverConn.Close()
packs = serverConn.ResourcePacks()
fmt.Printf("%d packs loaded\n", len(packs))
}
_status := minecraft.NewStatusProvider("Server")
proxy.listener, err = minecraft.ListenConfig{
StatusProvider: _status,
ResourcePacks: packs,
AcceptedProtocols: []minecraft.Protocol{
dummyProto{id: 544, ver: "1.19.20"},
},
}.Listen("raknet", ":19132")
if err != nil {
return err
}
defer proxy.listener.Close()
fmt.Printf("Listening on %s\n", proxy.listener.Addr())
c, err := proxy.listener.Accept()
if err != nil {
log.Fatal(err)
}
proxy.client = c.(*minecraft.Conn)
cd := proxy.client.ClientData()
proxy.server, err = connect_server(ctx, server_address, &cd, false)
if err != nil {
return fmt.Errorf("failed to connect to %s: %s", server_address, err)
}
// spawn and start the game
if err := spawn_conn(ctx, proxy.client, proxy.server); err != nil {
return fmt.Errorf("failed to spawn: %s", err)
}
defer proxy.server.Close()
defer proxy.listener.Disconnect(proxy.client, G_disconnect_reason)
if onConnect != nil {
onConnect(&proxy)
}
wg := sync.WaitGroup{}
// server to client
wg.Add(1)
go func() {
defer wg.Done()
if err := proxyLoop(ctx, &proxy, false, []PacketCallback{packetCB}); err != nil {
log.Error(err)
return
}
}()
// client to server
wg.Add(1)
go func() {
defer wg.Done()
if err := proxyLoop(ctx, &proxy, true, []PacketCallback{packetCB}); err != nil {
log.Error(err)
return
}
}()
wg.Wait()
return nil
}

2
rp.go
View File

@ -4,7 +4,7 @@ import "github.com/sandertv/gophertunnel/minecraft/resource"
func (w *WorldState) getPacks() (packs map[string]*resource.Pack, err error) {
packs = make(map[string]*resource.Pack)
for _, pack := range w.ServerConn.ResourcePacks() {
for _, pack := range w.proxy.server.ResourcePacks() {
packs[pack.Name()] = pack
}
return

View File

@ -2,13 +2,13 @@ package main
import (
"context"
"errors"
"flag"
"fmt"
"os"
"github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sirupsen/logrus"
)
type SkinProxyCMD struct {
@ -23,76 +23,33 @@ 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" + SERVER_ADDRESS_HELP
}
func (c *SkinProxyCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
log := logrus.New()
address, hostname, err := server_input(c.server_address)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
out_path := fmt.Sprintf("skins/%s", hostname)
os.MkdirAll(out_path, 0o755)
listener, clientConn, serverConn, err := create_proxy(ctx, address)
err = create_proxy(ctx, log, address, nil, func(pk packet.Packet, proxy *ProxyContext, toServer bool) (packet.Packet, error) {
if !toServer {
process_packet_skins(proxy.client, out_path, pk, c.filter)
}
return pk, nil
})
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
defer listener.Close()
out_path := fmt.Sprintf("skins/%s", hostname)
println("Connected")
println("Press ctrl+c to exit")
os.MkdirAll(out_path, 0755)
errs := make(chan error, 2)
go func() { // server -> client
defer serverConn.Close()
defer listener.Disconnect(clientConn, "connection lost")
for {
pk, err := serverConn.ReadPacket()
if err != nil {
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
_ = listener.Disconnect(clientConn, disconnect.Error())
}
return
}
process_packet_skins(clientConn, out_path, pk, c.filter)
if err = clientConn.WritePacket(pk); err != nil {
return
}
}
}()
go func() { // client -> server
for {
pk, err := clientConn.ReadPacket()
if err != nil {
return
}
if err := serverConn.WritePacket(pk); err != nil {
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
_ = listener.Disconnect(clientConn, disconnect.Error())
}
return
}
}
}()
for {
select {
case err := <-errs:
fmt.Fprintln(os.Stderr, err)
return 1
case <-ctx.Done():
return 0
}
}
return 0
}
func init() {

128
utils.go
View File

@ -23,11 +23,11 @@ import (
"unsafe"
"github.com/sandertv/gophertunnel/minecraft"
//"github.com/sandertv/gophertunnel/minecraft/gatherings"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/login"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sandertv/gophertunnel/minecraft/resource"
"golang.org/x/exp/slices"
)
@ -170,94 +170,6 @@ func spawn_conn(ctx context.Context, clientConn *minecraft.Conn, serverConn *min
return nil
}
type dummyProto struct {
id int32
ver string
}
func (p dummyProto) ID() int32 { return p.id }
func (p dummyProto) Ver() string { return p.ver }
func (p dummyProto) Packets() packet.Pool { return packet.NewPool() }
func (p dummyProto) ConvertToLatest(pk packet.Packet, _ *minecraft.Conn) []packet.Packet {
return []packet.Packet{pk}
}
func (p dummyProto) ConvertFromLatest(pk packet.Packet, _ *minecraft.Conn) []packet.Packet {
return []packet.Packet{pk}
}
func create_proxy(ctx context.Context, server_address string) (l *minecraft.Listener, clientConn, serverConn *minecraft.Conn, err error) {
/*
if strings.HasSuffix(server_address, ".pcap") {
return create_replay_connection(server_address)
}
*/
GetTokenSource() // ask for login before listening
var packs []*resource.Pack
if G_preload_packs {
fmt.Println("Preloading resourcepacks")
serverConn, err = connect_server(ctx, server_address, nil, true)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to connect to %s: %s", server_address, err)
}
serverConn.Close()
packs = serverConn.ResourcePacks()
fmt.Printf("%d packs loaded\n", len(packs))
}
_status := minecraft.NewStatusProvider("Server")
listener, err := minecraft.ListenConfig{
StatusProvider: _status,
ResourcePacks: packs,
AcceptedProtocols: []minecraft.Protocol{
dummyProto{id: 544, ver: "1.19.20"},
},
}.Listen("raknet", ":19132")
if err != nil {
return nil, nil, nil, err
}
l = listener
fmt.Printf("Listening on %s\n", listener.Addr())
c, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
clientConn = c.(*minecraft.Conn)
cd := clientConn.ClientData()
serverConn, err = connect_server(ctx, server_address, &cd, false)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to connect to %s: %s", server_address, err)
}
if err := spawn_conn(ctx, clientConn, serverConn); err != nil {
return nil, nil, nil, fmt.Errorf("failed to spawn: %s", err)
}
G_exit = append(G_exit, func() {
serverConn.Close()
l.Disconnect(clientConn, "Closing")
clientConn.Close()
l.Close()
})
/*
go func() {
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
clientConn.WritePacket(&packet.Text{
TextType: packet.TextTypeTip,
Message: a + "\n\n\n\n\n\n",
})
}
}()
*/
return l, clientConn, serverConn, nil
}
var PrivateIPNetworks = []net.IPNet{
{
IP: net.ParseIP("10.0.0.0"),
@ -386,7 +298,7 @@ var muted_packets = []string{
"*packet.AddActor",
"*packet.UpdateAttributes",
"*packet.Interact",
"*packet.LevelEvent",
//"*packet.LevelEvent",
"*packet.SetActorData",
"*packet.MoveActorDelta",
"*packet.MovePlayer",
@ -401,6 +313,7 @@ var muted_packets = []string{
"*packet.SubChunkRequest",
"*packet.Animate",
"*packet.NetworkStackLatency",
"*packet.InventoryTransaction",
}
func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
@ -428,6 +341,10 @@ func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
switch pk := pk.(type) {
case *packet.Disconnect:
fmt.Printf("Disconnect: %s", pk.Message)
case *packet.Event:
fmt.Printf("Event: %d %+v\n", pk.EventType, pk.EventData)
case *packet.LevelEvent:
fmt.Printf("LevelEvent: %+v\n", pk)
}
fmt.Printf("%s 0x%x, %s\n", dir, pk.ID(), pk_name)
}
@ -438,3 +355,34 @@ func img2rgba(img *image.RGBA) []color.RGBA {
header.Cap /= 4
return *(*[]color.RGBA)(unsafe.Pointer(&header))
}
// LERP is a linear interpolation function
func LERP(p1, p2, alpha float64) float64 {
return (1-alpha)*p1 + alpha*p2
}
func blendColorValue(c1, c2, a uint8) uint8 {
return uint8(LERP(float64(c1), float64(c2), float64(a)/float64(0xff)))
}
func blendAlphaValue(a1, a2 uint8) uint8 {
return uint8(LERP(float64(a1), float64(0xff), float64(a2)/float64(0xff)))
}
func blendColors(c1, c2 color.RGBA) (ret color.RGBA) {
ret.R = blendColorValue(c1.R, c2.R, c2.A)
ret.G = blendColorValue(c1.G, c2.G, c2.A)
ret.B = blendColorValue(c1.B, c2.B, c2.A)
ret.A = blendAlphaValue(c1.A, c2.A)
return ret
}
func clamp(a, b int) int {
if a > b {
return b
}
if a < 0 {
return 0
}
return a
}

203
world.go
View File

@ -3,7 +3,6 @@ package main
import (
"bytes"
"context"
"errors"
"flag"
"fmt"
"hash/crc32"
@ -23,7 +22,6 @@ import (
"github.com/df-mc/goleveldb/leveldb/opt"
"github.com/go-gl/mathgl/mgl32"
"github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sandertv/gophertunnel/minecraft/resource"
@ -42,6 +40,7 @@ type TPlayerPos struct {
// the state used for drawing and saving
type WorldState struct {
ctx context.Context
ispre118 bool
voidgen bool
chunks map[protocol.ChunkPos]*chunk.Chunk
@ -51,11 +50,11 @@ type WorldState struct {
WorldName string
ServerName string
worldCounter int
withPacks bool
packs map[string]*resource.Pack
PlayerPos TPlayerPos
ClientConn *minecraft.Conn
ServerConn *minecraft.Conn
PlayerPos TPlayerPos
proxy *ProxyContext
log *logrus.Logger
@ -110,13 +109,13 @@ var IngameCommands = map[string]IngameCommand{
func setnameCommand(w *WorldState, cmdline []string) bool {
w.WorldName = strings.Join(cmdline, " ")
send_message(w.ClientConn, fmt.Sprintf("worldName is now: %s", w.WorldName))
send_message(w.proxy.client, fmt.Sprintf("worldName is now: %s", w.WorldName))
return true
}
func toggleVoid(w *WorldState, cmdline []string) bool {
w.voidgen = !w.voidgen
send_message(w.ClientConn, fmt.Sprintf("using void generator: %t", w.voidgen))
send_message(w.proxy.client, fmt.Sprintf("using void generator: %t", w.voidgen))
return true
}
@ -166,14 +165,25 @@ func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{
return 1
}
listener, clientConn, serverConn, err := create_proxy(ctx, server_address)
w := NewWorldState()
w.log = c.log
w.voidgen = c.enableVoid
w.ServerName = hostname
w.withPacks = c.packs
w.ctx = ctx
err = create_proxy(ctx, c.log, server_address, w.OnConnect, func(pk packet.Packet, proxy *ProxyContext, toServer bool) (packet.Packet, error) {
if toServer {
pk = w.ProcessPacketClient(pk)
} else {
pk = w.ProcessPacketServer(pk)
}
return pk, nil
})
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
c.handleConn(ctx, listener, clientConn, serverConn, hostname)
return 0
}
@ -215,7 +225,7 @@ func (w *WorldState) ProcessLevelChunk(pk *packet.LevelChunk) {
max = int(pk.HighestSubChunk)
}
w.ServerConn.WritePacket(&packet.SubChunkRequest{
w.proxy.server.WritePacket(&packet.SubChunkRequest{
Dimension: int32(w.Dim.EncodeDimension()),
Position: protocol.SubChunkPos{
pk.Position.X(), 0, pk.Position.Z(),
@ -352,7 +362,7 @@ func (w *WorldState) SaveAndReset() {
// set gamerules
ld := provider.LevelDat()
gd := w.ServerConn.GameData()
gd := w.proxy.server.GameData()
for _, gr := range gd.GameRules {
switch gr.Name {
case "commandblockoutput":
@ -453,25 +463,20 @@ func (w *WorldState) SaveAndReset() {
w.Reset()
}
func (c *WorldCMD) handleConn(ctx context.Context, l *minecraft.Listener, cc, sc *minecraft.Conn, server_name string) {
var err error
w := NewWorldState()
w.ServerName = server_name
w.ClientConn = cc
w.ServerConn = sc
w.voidgen = c.enableVoid
w.log = c.log
func (w *WorldState) OnConnect(proxy *ProxyContext) {
w.proxy = proxy
if c.packs {
if w.withPacks {
fmt.Println("reformatting packs")
go func() {
w.packs, err = w.getPacks()
w.packs, _ = w.getPacks()
}()
}
{ // check game version
gd := w.ServerConn.GameData()
gd := w.proxy.server.GameData()
gv := strings.Split(gd.BaseGameVersion, ".")
var err error
if len(gv) > 1 {
var ver int
ver, err = strconv.Atoi(gv[1])
@ -483,117 +488,75 @@ func (c *WorldCMD) handleConn(ctx context.Context, l *minecraft.Listener, cc, sc
if w.ispre118 {
fmt.Println("using legacy (< 1.18)")
}
dim_id := gd.Dimension
if w.ispre118 {
dim_id += 10
}
w.Dim = dimension_ids[uint8(dim_id)]
}
send_message(w.ClientConn, "use /setname <worldname>\nto set the world name")
send_message(w.proxy.client, "use /setname <worldname>\nto set the world name")
G_exit = append(G_exit, func() {
w.SaveAndReset()
})
done := make(chan struct{})
go func() { // client loop
defer func() { done <- struct{}{} }()
for {
skip := false
pk, err := w.ClientConn.ReadPacket()
if err != nil {
return
}
switch pk := pk.(type) {
case *packet.MovePlayer:
w.SetPlayerPos(pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
case *packet.PlayerAuthInput:
w.SetPlayerPos(pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
case *packet.MapInfoRequest:
if pk.MapID == VIEW_MAP_ID {
w.ui.Send(w)
skip = true
}
case *packet.MobEquipment:
if pk.NewItem.Stack.NBTData["map_uuid"] == int64(VIEW_MAP_ID) {
skip = true
}
case *packet.Animate:
w.ProcessAnimate(pk)
case *packet.CommandRequest:
skip = w.ProcessCommand(pk)
}
if !skip {
if err := w.ServerConn.WritePacket(pk); err != nil {
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
_ = l.Disconnect(w.ClientConn, disconnect.Error())
}
return
}
}
}
}()
go func() { // send map item
select {
case <-ctx.Done():
case <-w.ctx.Done():
return
default:
for {
time.Sleep(1 * time.Second)
err := w.ClientConn.WritePacket(&MAP_ITEM_PACKET)
t := time.NewTimer(1 * time.Second)
for range t.C {
err := w.proxy.client.WritePacket(&MAP_ITEM_PACKET)
if err != nil {
return
}
}
}
}()
go func() { // server loop
defer w.ServerConn.Close()
defer l.Disconnect(w.ClientConn, "connection lost")
defer func() { done <- struct{}{} }()
gd := w.ServerConn.GameData()
dim_id := gd.Dimension
if w.ispre118 {
dim_id += 10
}
w.Dim = dimension_ids[uint8(dim_id)]
for {
pk, err := w.ServerConn.ReadPacket()
if err != nil {
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
_ = l.Disconnect(w.ClientConn, disconnect.Error())
}
return
}
switch pk := pk.(type) {
case *packet.ChangeDimension:
w.ProcessChangeDimension(pk)
case *packet.LevelChunk:
w.ProcessLevelChunk(pk)
w.ui.Send(w)
send_popup(w.ClientConn, fmt.Sprintf("%d chunks loaded\nname: %s", len(w.chunks), w.WorldName))
case *packet.SubChunk:
w.ProcessSubChunk(pk)
case *packet.AvailableCommands:
for _, ic := range IngameCommands {
pk.Commands = append(pk.Commands, ic.cmd)
}
}
if err := w.ClientConn.WritePacket(pk); err != nil {
return
}
}
}()
select {
case <-ctx.Done():
return
case <-done:
return
}
}
func (w *WorldState) ProcessPacketClient(pk packet.Packet) packet.Packet {
switch pk := pk.(type) {
case *packet.MovePlayer:
w.SetPlayerPos(pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
case *packet.PlayerAuthInput:
w.SetPlayerPos(pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
case *packet.MapInfoRequest:
if pk.MapID == VIEW_MAP_ID {
w.ui.Send(w)
pk = nil
}
case *packet.MobEquipment:
if pk.NewItem.Stack.NBTData["map_uuid"] == int64(VIEW_MAP_ID) {
pk = nil
}
case *packet.Animate:
w.ProcessAnimate(pk)
case *packet.CommandRequest:
if w.ProcessCommand(pk) {
pk = nil
}
}
return pk
}
func (w *WorldState) ProcessPacketServer(pk packet.Packet) packet.Packet {
switch pk := pk.(type) {
case *packet.ChangeDimension:
w.ProcessChangeDimension(pk)
case *packet.LevelChunk:
w.ProcessLevelChunk(pk)
w.ui.Send(w)
send_popup(w.proxy.client, fmt.Sprintf("%d chunks loaded\nname: %s", len(w.chunks), w.WorldName))
case *packet.SubChunk:
w.ProcessSubChunk(pk)
case *packet.AvailableCommands:
for _, ic := range IngameCommands {
pk.Commands = append(pk.Commands, ic.cmd)
}
}
return pk
}