add custom items, (untested probably not working entities)

This commit is contained in:
olebeck 2023-01-29 15:08:41 +00:00
parent ea6dea7953
commit 32f1e8019a
18 changed files with 752 additions and 475 deletions

View File

@ -72,7 +72,7 @@ func (c *CaptureCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interfac
proxy := utils.NewProxy()
proxy.PacketFunc = func(header packet.Header, payload []byte, src, dst net.Addr) {
from_client := src.String() == proxy.Client.LocalAddr().String()
from_client := dst.String() == proxy.Server.RemoteAddr().String()
buf := bytes.NewBuffer(nil)
header.Write(buf)

112
subcommands/world/chunk.go Normal file
View File

@ -0,0 +1,112 @@
package world
import (
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/df-mc/dragonfly/server/world"
"github.com/df-mc/dragonfly/server/world/chunk"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sirupsen/logrus"
)
func (w *WorldState) processChangeDimension(pk *packet.ChangeDimension) {
if len(w.chunks) > 0 {
w.SaveAndReset()
} else {
logrus.Info(locale.Loc("not_saving_empty", nil))
w.Reset()
}
dim_id := pk.Dimension
if w.ispre118 {
dim_id += 10
}
w.Dim = dimension_ids[uint8(dim_id)]
}
func (w *WorldState) processLevelChunk(pk *packet.LevelChunk) {
_, exists := w.chunks[pk.Position]
if exists {
return
}
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, int(pk.SubChunkCount), w.Dim.Range(), w.ispre118, w.bp != nil)
if err != nil {
logrus.Error(err)
return
}
if blockNBTs != nil {
w.blockNBT[protocol.SubChunkPos{
pk.Position.X(), 0, pk.Position.Z(),
}] = blockNBTs
}
w.chunks[pk.Position] = ch
if pk.SubChunkRequestMode == protocol.SubChunkRequestModeLegacy {
w.ui.SetChunk(pk.Position, ch)
} else {
w.ui.SetChunk(pk.Position, nil)
// request all the subchunks
max := w.Dim.Range().Height() / 16
if pk.SubChunkRequestMode == protocol.SubChunkRequestModeLimited {
max = int(pk.HighestSubChunk)
}
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
Dimension: int32(w.Dim.EncodeDimension()),
Position: protocol.SubChunkPos{
pk.Position.X(), 0, pk.Position.Z(),
},
Offsets: Offset_table[:max],
})
}
}
func (w *WorldState) processSubChunk(pk *packet.SubChunk) {
pos_to_redraw := make(map[protocol.ChunkPos]bool)
for _, sub := range pk.SubChunkEntries {
var (
abs_x = pk.Position[0] + int32(sub.Offset[0])
abs_y = pk.Position[1] + int32(sub.Offset[1])
abs_z = pk.Position[2] + int32(sub.Offset[2])
subpos = protocol.SubChunkPos{abs_x, abs_y, abs_z}
pos = protocol.ChunkPos{abs_x, abs_z}
)
ch := w.chunks[pos]
if ch == nil {
logrus.Error(locale.Loc("subchunk_before_chunk", nil))
continue
}
blockNBT, err := ch.ApplySubChunkEntry(uint8(abs_y), &sub)
if err != nil {
logrus.Error(err)
}
if blockNBT != nil {
w.blockNBT[subpos] = blockNBT
}
pos_to_redraw[pos] = true
}
// redraw the chunks
for pos := range pos_to_redraw {
w.ui.SetChunk(pos, w.chunks[pos])
}
w.ui.SchedRedraw()
}
func (w *WorldState) ProcessChunkPackets(pk packet.Packet) packet.Packet {
switch pk := pk.(type) {
case *packet.ChangeDimension:
w.processChangeDimension(pk)
case *packet.LevelChunk:
w.processLevelChunk(pk)
w.proxy.SendPopup(locale.Locm("popup_chunk_count", locale.Strmap{"Count": len(w.chunks), "Name": w.WorldName}, len(w.chunks)))
case *packet.SubChunk:
w.processSubChunk(pk)
}
return pk
}

133
subcommands/world/entity.go Normal file
View File

@ -0,0 +1,133 @@
package world
import (
"github.com/bedrock-tool/bedrocktool/utils/behaviourpack"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl32"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
type entityState struct {
RuntimeId uint64
UniqueId int64
EntityType string
Position mgl32.Vec3
Pitch, Yaw float32
HeadYaw, BodyYaw float32
Velocity mgl32.Vec3
Metadata map[uint32]any
}
type serverEntity struct {
world.Entity
EntityType serverEntityType
}
type serverEntityType struct {
world.SaveableEntityType
Encoded string
NBT map[string]any
}
func (t serverEntityType) EncodeEntity() string {
return t.Encoded
}
func (t serverEntityType) DecodeNBT(m map[string]any) world.Entity {
return nil // not implemented, and never should
}
func (t serverEntityType) EncodeNBT(e *serverEntity) map[string]any {
return t.NBT
}
func (t serverEntityType) BBox(e world.Entity) cube.BBox {
return cube.Box(0, 0, 0, 1, 1, 1)
}
func (e serverEntity) Type() world.EntityType {
return e.EntityType
}
func (w *WorldState) processAddActor(pk *packet.AddActor) {
e, ok := w.entities[pk.EntityRuntimeID]
if !ok {
e = &entityState{
RuntimeId: pk.EntityRuntimeID,
UniqueId: pk.EntityUniqueID,
EntityType: pk.EntityType,
Metadata: make(map[uint32]any),
}
w.entities[pk.EntityRuntimeID] = e
w.bp.AddEntity(behaviourpack.EntityIn{
Identifier: pk.EntityType,
Attr: pk.Attributes,
})
}
e.Position = pk.Position
e.Pitch = pk.Pitch
e.Yaw = pk.Yaw
e.BodyYaw = pk.BodyYaw
e.HeadYaw = pk.HeadYaw
e.Velocity = pk.Velocity
for k, v := range pk.EntityMetadata {
e.Metadata[k] = v
}
}
func (w *WorldState) ProcessEntityPackets(pk packet.Packet) packet.Packet {
switch pk := pk.(type) {
case *packet.AddActor:
w.processAddActor(pk)
case *packet.RemoveActor:
delete(w.entities, uint64(pk.EntityUniqueID))
case *packet.SetActorData:
e, ok := w.entities[pk.EntityRuntimeID]
if ok {
for k, v := range pk.EntityMetadata {
e.Metadata[k] = v
}
}
case *packet.SetActorMotion:
e, ok := w.entities[pk.EntityRuntimeID]
if ok {
e.Velocity = pk.Velocity
}
case *packet.MoveActorDelta:
e, ok := w.entities[pk.EntityRuntimeID]
if ok {
if pk.Flags&packet.MoveActorDeltaFlagHasX != 0 {
e.Position[0] = pk.Position[0]
}
if pk.Flags&packet.MoveActorDeltaFlagHasY != 0 {
e.Position[1] = pk.Position[1]
}
if pk.Flags&packet.MoveActorDeltaFlagHasZ != 0 {
e.Position[2] = pk.Position[2]
}
if pk.Flags&packet.MoveActorDeltaFlagHasRotX != 0 {
e.Pitch = pk.Rotation.X()
}
if pk.Flags&packet.MoveActorDeltaFlagHasRotY != 0 {
e.Yaw = pk.Rotation.Y()
}
//if pk.Flags&packet.MoveActorDeltaFlagHasRotZ != 0 {
// no roll
//}
}
case *packet.MoveActorAbsolute:
e, ok := w.entities[pk.EntityRuntimeID]
if ok {
e.Position = pk.Position
e.Pitch = pk.Rotation.X()
e.Yaw = pk.Rotation.Y()
}
}
return pk
}

167
subcommands/world/items.go Normal file
View File

@ -0,0 +1,167 @@
package world
import (
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/bedrock-tool/bedrocktool/utils/nbtconv"
"github.com/df-mc/dragonfly/server/block"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/item/inventory"
"github.com/df-mc/dragonfly/server/world"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sirupsen/logrus"
)
type itemContainer struct {
OpenPacket *packet.ContainerOpen
Content *packet.InventoryContent
}
func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
switch pk := pk.(type) {
case *packet.ContainerOpen:
if w.experimentInventory {
// add to open containers
existing, ok := w.openItemContainers[pk.WindowID]
if !ok {
existing = &itemContainer{}
}
w.openItemContainers[pk.WindowID] = &itemContainer{
OpenPacket: pk,
Content: existing.Content,
}
}
case *packet.InventoryContent:
if w.experimentInventory {
// save content
existing, ok := w.openItemContainers[byte(pk.WindowID)]
if !ok {
if pk.WindowID == 0x0 { // inventory
w.openItemContainers[byte(pk.WindowID)] = &itemContainer{
Content: pk,
}
}
break
}
existing.Content = pk
}
case *packet.ContainerClose:
if w.experimentInventory {
switch pk.WindowID {
case protocol.WindowIDArmour: // todo handle
case protocol.WindowIDOffHand: // todo handle
case protocol.WindowIDUI:
case protocol.WindowIDInventory: // todo handle
default:
// find container info
existing, ok := w.openItemContainers[byte(pk.WindowID)]
if !ok {
logrus.Warn(locale.Loc("warn_window_closed_not_open", nil))
break
}
if existing.Content == nil {
break
}
pos := existing.OpenPacket.ContainerPosition
cp := protocol.SubChunkPos{pos.X() << 4, pos.Z() << 4}
// create inventory
inv := inventory.New(len(existing.Content.Content), nil)
for i, c := range existing.Content.Content {
item := stackToItem(c.Stack)
inv.SetItem(i, item)
}
// put into subchunk
nbts := w.blockNBT[cp]
for i, v := range nbts {
nbt_pos := protocol.BlockPos{v["x"].(int32), v["y"].(int32), v["z"].(int32)}
if nbt_pos == pos {
w.blockNBT[cp][i]["Items"] = nbtconv.InvToNBT(inv)
}
}
w.proxy.SendMessage(locale.Loc("saved_block_inv", nil))
// remove it again
delete(w.openItemContainers, byte(pk.WindowID))
}
}
case *packet.ItemComponent:
w.bp.ApplyComponentEntries(pk.Items)
}
return pk
}
func (w *WorldState) processItemPacketsClient(pk packet.Packet, forward *bool) packet.Packet {
switch pk := pk.(type) {
case *packet.ItemStackRequest:
var requests []protocol.ItemStackRequest
for _, isr := range pk.Requests {
for _, sra := range isr.Actions {
if sra, ok := sra.(*protocol.TakeStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.DropStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.DestroyStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.PlaceInContainerStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.TakeOutContainerStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.DestroyStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
}
requests = append(requests, isr)
}
pk.Requests = requests
case *packet.MobEquipment:
if pk.NewItem.Stack.NBTData["map_uuid"] == int64(VIEW_MAP_ID) {
*forward = false
}
}
return pk
}
// stackToItem converts a network ItemStack representation back to an item.Stack.
func stackToItem(it protocol.ItemStack) item.Stack {
t, ok := world.ItemByRuntimeID(it.NetworkID, int16(it.MetadataValue))
if !ok {
t = block.Air{}
}
if it.BlockRuntimeID > 0 {
// It shouldn't matter if it (for whatever reason) wasn't able to get the block runtime ID,
// since on the next line, we assert that the block is an item. If it didn't succeed, it'll
// return air anyway.
b, _ := world.BlockByRuntimeID(uint32(it.BlockRuntimeID))
if t, ok = b.(world.Item); !ok {
t = block.Air{}
}
}
//noinspection SpellCheckingInspection
if nbter, ok := t.(world.NBTer); ok && len(it.NBTData) != 0 {
t = nbter.DecodeNBT(it.NBTData).(world.Item)
}
s := item.NewStack(t, int(it.Count))
return nbtconv.ReadItem(it.NBTData, &s)
}

View File

@ -111,6 +111,21 @@ func (m *MapUI) Start() {
}
}
}()
go func() { // send map item
t := time.NewTicker(1 * time.Second)
for range t.C {
if m.w.ctx.Err() != nil {
return
}
if m.w.proxy.Client != nil {
err := m.w.proxy.Client.WritePacket(&MAP_ITEM_PACKET)
if err != nil {
logrus.Error(err)
return
}
}
}
}()
}
func (m *MapUI) Stop() {
@ -139,21 +154,6 @@ func (m *MapUI) SchedRedraw() {
m.needRedraw = true
}
// draw_img_scaled_pos draws src onto dst at bottom_left, scaled to size
func draw_img_scaled_pos(dst *image.RGBA, src *image.RGBA, bottom_left image.Point, size_scaled int) {
sbx := src.Bounds().Dx()
ratio := int(float64(sbx) / float64(size_scaled))
for x_out := bottom_left.X; x_out < bottom_left.X+size_scaled; x_out++ {
for y_out := bottom_left.Y; y_out < bottom_left.Y+size_scaled; y_out++ {
x_in := (x_out - bottom_left.X) * ratio
y_in := (y_out - bottom_left.Y) * ratio
c := src.At(x_in, y_in)
dst.Set(x_out, y_out, c)
}
}
}
// draw chunk images to the map image
func (m *MapUI) Redraw() {
for {
@ -191,7 +191,7 @@ func (m *MapUI) Redraw() {
}
if !m.img.Rect.Intersect(image.Rect(px_pos.X, px_pos.Y, px_pos.X+sz_chunk, px_pos.Y+sz_chunk)).Empty() {
draw_img_scaled_pos(m.img, m.renderedChunks[_ch], px_pos, sz_chunk)
utils.Draw_img_scaled_pos(m.img, m.renderedChunks[_ch], px_pos, sz_chunk)
}
}
@ -235,3 +235,20 @@ func (m *MapUI) SetChunk(pos protocol.ChunkPos, ch *chunk.Chunk) {
m.renderQueue.Enqueue(&RenderElem{pos, ch})
m.SchedRedraw()
}
func (w *WorldState) processMapPacketsClient(pk packet.Packet, forward *bool) 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.SchedRedraw()
*forward = false
}
case *packet.Animate:
w.ProcessAnimate(pk)
}
return pk
}

View File

@ -7,24 +7,18 @@ import (
"flag"
"fmt"
"image"
"image/draw"
"image/png"
"math/rand"
"os"
"path"
"strconv"
"strings"
"time"
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/bedrock-tool/bedrocktool/utils"
"github.com/bedrock-tool/bedrocktool/utils/behaviourpack"
"github.com/bedrock-tool/bedrocktool/utils/nbtconv"
"github.com/df-mc/dragonfly/server/block"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/item/inventory"
"github.com/df-mc/dragonfly/server/world"
"github.com/df-mc/dragonfly/server/world/chunk"
"github.com/df-mc/dragonfly/server/world/mcdb"
@ -33,10 +27,7 @@ import (
"github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sandertv/gophertunnel/minecraft/resource"
"github.com/sirupsen/logrus"
//_ "github.com/df-mc/dragonfly/server/block" // to load blocks
//_ "net/http/pprof"
)
type TPlayerPos struct {
@ -46,11 +37,6 @@ type TPlayerPos struct {
HeadYaw float32
}
type itemContainer struct {
OpenPacket *packet.ContainerOpen
Content *packet.InventoryContent
}
// the state used for drawing and saving
type WorldState struct {
@ -60,12 +46,12 @@ type WorldState struct {
chunks map[protocol.ChunkPos]*chunk.Chunk
blockNBT map[protocol.SubChunkPos][]map[string]any
openItemContainers map[byte]*itemContainer
entities map[uint64]*entityState
Dim world.Dimension
WorldName string
ServerName string
worldCounter int
packs map[string]*resource.Pack
bp *behaviourpack.BehaviourPack
withPacks bool
@ -84,6 +70,7 @@ func NewWorldState() *WorldState {
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
openItemContainers: make(map[byte]*itemContainer),
entities: make(map[uint64]*entityState),
Dim: nil,
WorldName: "world",
PlayerPos: TPlayerPos{},
@ -111,7 +98,9 @@ func init() {
for i := range Offset_table {
Offset_table[i] = protocol.SubChunkOffset{0, int8(i), 0}
}
draw.Draw(black_16x16, image.Rect(0, 0, 16, 16), image.Black, image.Point{}, draw.Src)
for i := 3; i < len(black_16x16.Pix); i += 4 {
black_16x16.Pix[i] = 255
}
utils.RegisterCommand(&WorldCMD{})
}
@ -139,12 +128,6 @@ func (c *WorldCMD) Usage() string {
}
func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
/*
go func() {
http.ListenAndServe(":8000", nil)
}()
*/
server_address, hostname, err := utils.ServerInput(ctx, c.Address)
if err != nil {
logrus.Error(err)
@ -164,12 +147,19 @@ func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{
proxy.AlwaysGetPacks = true
proxy.ConnectCB = w.OnConnect
proxy.PacketCB = func(pk packet.Packet, proxy *utils.ProxyContext, toServer bool) (packet.Packet, error) {
var forward bool
var forward bool = true
if toServer {
pk, forward = w.ProcessPacketClient(pk)
// from client
pk = w.processItemPacketsClient(pk, &forward)
pk = w.processMapPacketsClient(pk, &forward)
} else {
pk, forward = w.ProcessPacketServer(pk)
// from server
pk = w.processItemPacketsServer(pk)
pk = w.ProcessChunkPackets(pk)
pk = w.ProcessEntityPackets(pk)
}
if !forward {
return nil, nil
}
@ -185,98 +175,6 @@ func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{
return 0
}
func (w *WorldState) setnameCommand(cmdline []string) bool {
w.WorldName = strings.Join(cmdline, " ")
w.proxy.SendMessage(locale.Loc("worldname_set", locale.Strmap{"Name": w.WorldName}))
return true
}
func (w *WorldState) toggleVoid(cmdline []string) bool {
w.voidgen = !w.voidgen
var s string
if w.voidgen {
s = locale.Loc("void_generator_true", nil)
} else {
s = locale.Loc("void_generator_false", nil)
}
w.proxy.SendMessage(s)
return true
}
func (w *WorldState) ProcessLevelChunk(pk *packet.LevelChunk) {
_, exists := w.chunks[pk.Position]
if exists {
return
}
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, int(pk.SubChunkCount), w.Dim.Range(), w.ispre118, w.bp != nil)
if err != nil {
logrus.Error(err)
return
}
if blockNBTs != nil {
w.blockNBT[protocol.SubChunkPos{
pk.Position.X(), 0, pk.Position.Z(),
}] = blockNBTs
}
w.chunks[pk.Position] = ch
if pk.SubChunkRequestMode == protocol.SubChunkRequestModeLegacy {
w.ui.SetChunk(pk.Position, ch)
} else {
w.ui.SetChunk(pk.Position, nil)
// request all the subchunks
max := w.Dim.Range().Height() / 16
if pk.SubChunkRequestMode == protocol.SubChunkRequestModeLimited {
max = int(pk.HighestSubChunk)
}
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
Dimension: int32(w.Dim.EncodeDimension()),
Position: protocol.SubChunkPos{
pk.Position.X(), 0, pk.Position.Z(),
},
Offsets: Offset_table[:max],
})
}
}
func (w *WorldState) ProcessSubChunk(pk *packet.SubChunk) {
pos_to_redraw := make(map[protocol.ChunkPos]bool)
for _, sub := range pk.SubChunkEntries {
var (
abs_x = pk.Position[0] + int32(sub.Offset[0])
abs_y = pk.Position[1] + int32(sub.Offset[1])
abs_z = pk.Position[2] + int32(sub.Offset[2])
subpos = protocol.SubChunkPos{abs_x, abs_y, abs_z}
pos = protocol.ChunkPos{abs_x, abs_z}
)
ch := w.chunks[pos]
if ch == nil {
logrus.Error(locale.Loc("subchunk_before_chunk", nil))
continue
}
blockNBT, err := ch.ApplySubChunkEntry(uint8(abs_y), &sub)
if err != nil {
logrus.Error(err)
}
if blockNBT != nil {
w.blockNBT[subpos] = blockNBT
}
pos_to_redraw[pos] = true
}
// redraw the chunks
for pos := range pos_to_redraw {
w.ui.SetChunk(pos, w.chunks[pos])
}
w.ui.SchedRedraw()
}
func (w *WorldState) ProcessAnimate(pk *packet.Animate) {
if pk.ActionType == packet.AnimateActionSwingArm {
w.ui.ChangeZoom()
@ -284,20 +182,6 @@ func (w *WorldState) ProcessAnimate(pk *packet.Animate) {
}
}
func (w *WorldState) ProcessChangeDimension(pk *packet.ChangeDimension) {
if len(w.chunks) > 0 {
w.SaveAndReset()
} else {
logrus.Info(locale.Loc("not_saving_empty", nil))
w.Reset()
}
dim_id := pk.Dimension
if w.ispre118 {
dim_id += 10
}
w.Dim = dimension_ids[uint8(dim_id)]
}
func (w *WorldState) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
last := w.PlayerPos
w.PlayerPos = TPlayerPos{
@ -342,13 +226,31 @@ func (w *WorldState) SaveAndReset() {
}
// save block nbt data
blockNBT := make(map[protocol.ChunkPos][]map[string]any)
blockNBT := make(map[world.ChunkPos][]map[string]any)
for scp, v := range w.blockNBT { // 3d to 2d
cp := protocol.ChunkPos{scp.X(), scp.Z()}
cp := world.ChunkPos{scp.X(), scp.Z()}
blockNBT[cp] = append(blockNBT[cp], v...)
}
for cp, v := range blockNBT {
err = provider.SaveBlockNBT((world.ChunkPos)(cp), v, w.Dim)
err = provider.SaveBlockNBT(cp, v, w.Dim)
if err != nil {
logrus.Error(err)
}
}
chunkEntities := make(map[world.ChunkPos][]world.Entity)
for _, es := range w.entities {
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
chunkEntities[cp] = append(chunkEntities[cp], serverEntity{
EntityType: serverEntityType{
Encoded: es.EntityType,
},
})
}
for cp, v := range chunkEntities {
err = provider.SaveEntities(cp, v, w.Dim)
if err != nil {
logrus.Error(err)
}
@ -473,23 +375,7 @@ func (w *WorldState) SaveAndReset() {
}
}
{
var rdeps []dep
for k, p := range w.packs {
logrus.Infof(locale.Loc("adding_pack", locale.Strmap{"Name": k}))
pack_folder := path.Join(folder, "resource_packs", k)
os.MkdirAll(pack_folder, 0o755)
data := make([]byte, p.Len())
p.ReadAt(data, 0)
utils.UnpackZip(bytes.NewReader(data), int64(len(data)), pack_folder)
rdeps = append(rdeps, dep{
PackId: p.Manifest().Header.Name,
Version: p.Manifest().Header.Version,
})
}
add_packs_json("world_resource_packs.json", rdeps)
}
// save behaviourpack
if w.bp.HasContent() {
name := strings.ReplaceAll(w.ServerName, "/", "-") + "_blocks"
pack_folder := path.Join(folder, "behavior_packs", name)
@ -505,6 +391,33 @@ func (w *WorldState) SaveAndReset() {
PackId: w.bp.Manifest.Header.UUID,
Version: w.bp.Manifest.Header.Version,
}})
// force resource packs for worlds with custom blocks
w.withPacks = true
}
// add resource packs
if w.withPacks {
packs, err := utils.GetPacks(w.proxy.Server)
if err != nil {
logrus.Error(err)
} else {
var rdeps []dep
for k, p := range packs {
logrus.Infof(locale.Loc("adding_pack", locale.Strmap{"Name": k}))
pack_folder := path.Join(folder, "resource_packs", p.Name())
os.MkdirAll(pack_folder, 0o755)
data := make([]byte, p.Len())
p.ReadAt(data, 0)
utils.UnpackZip(bytes.NewReader(data), int64(len(data)), pack_folder)
rdeps = append(rdeps, dep{
PackId: p.Manifest().Header.Name,
Version: p.Manifest().Header.Version,
})
}
add_packs_json("world_resource_packs.json", rdeps)
}
}
if w.saveImage {
@ -515,7 +428,6 @@ func (w *WorldState) SaveAndReset() {
// zip it
filename := folder + ".mcworld"
if err := utils.ZipFolder(filename, folder); err != nil {
fmt.Println(err)
}
@ -531,9 +443,7 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
world.InsertCustomItems(gd.Items)
for _, ie := range gd.Items {
if ie.ComponentBased {
w.bp.AddItem(ie)
}
w.bp.AddItem(ie)
}
map_item_id, _ := world.ItemRidByName("minecraft:filled_map")
@ -551,12 +461,6 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
world.InsertCustomBlocks(gd.CustomBlocks)
}
if w.withPacks {
go func() {
w.packs, _ = utils.GetPacks(w.proxy.Server)
}()
}
{ // check game version
gv := strings.Split(gd.BaseGameVersion, ".")
var err error
@ -580,26 +484,13 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
w.proxy.SendMessage(locale.Loc("use_setname", nil))
w.ui.Start()
go func() { // send map item
select {
case <-w.ctx.Done():
return
default:
t := time.NewTicker(1 * time.Second)
for range t.C {
if w.proxy.Client != nil {
err := w.proxy.Client.WritePacket(&MAP_ITEM_PACKET)
if err != nil {
logrus.Error(err)
return
}
}
}
}
}()
proxy.AddCommand(utils.IngameCommand{
Exec: w.setnameCommand,
Exec: func(cmdline []string) bool {
w.WorldName = strings.Join(cmdline, " ")
w.proxy.SendMessage(locale.Loc("worldname_set", locale.Strmap{"Name": w.WorldName}))
return true
},
Cmd: protocol.Command{
Name: "setname",
Description: locale.Loc("setname_desc", nil),
@ -618,179 +509,20 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
})
proxy.AddCommand(utils.IngameCommand{
Exec: w.toggleVoid,
Exec: func(cmdline []string) bool {
w.voidgen = !w.voidgen
var s string
if w.voidgen {
s = locale.Loc("void_generator_true", nil)
} else {
s = locale.Loc("void_generator_false", nil)
}
w.proxy.SendMessage(s)
return true
},
Cmd: protocol.Command{
Name: "void",
Description: locale.Loc("void_desc", nil),
},
})
}
func (w *WorldState) ProcessPacketClient(pk packet.Packet) (packet.Packet, bool) {
forward := true
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.SchedRedraw()
forward = false
}
case *packet.ItemStackRequest:
var requests []protocol.ItemStackRequest
for _, isr := range pk.Requests {
for _, sra := range isr.Actions {
if sra, ok := sra.(*protocol.TakeStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.DropStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.DestroyStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.PlaceInContainerStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.TakeOutContainerStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
if sra, ok := sra.(*protocol.DestroyStackRequestAction); ok {
if sra.Source.StackNetworkID == MAP_ITEM_PACKET.Content[0].StackNetworkID {
continue
}
}
}
requests = append(requests, isr)
}
pk.Requests = requests
case *packet.MobEquipment:
if pk.NewItem.Stack.NBTData["map_uuid"] == int64(VIEW_MAP_ID) {
forward = false
}
case *packet.Animate:
w.ProcessAnimate(pk)
}
return pk, forward
}
// stackToItem converts a network ItemStack representation back to an item.Stack.
func stackToItem(it protocol.ItemStack) item.Stack {
t, ok := world.ItemByRuntimeID(it.NetworkID, int16(it.MetadataValue))
if !ok {
t = block.Air{}
}
if it.BlockRuntimeID > 0 {
// It shouldn't matter if it (for whatever reason) wasn't able to get the block runtime ID,
// since on the next line, we assert that the block is an item. If it didn't succeed, it'll
// return air anyway.
b, _ := world.BlockByRuntimeID(uint32(it.BlockRuntimeID))
if t, ok = b.(world.Item); !ok {
t = block.Air{}
}
}
//noinspection SpellCheckingInspection
if nbter, ok := t.(world.NBTer); ok && len(it.NBTData) != 0 {
t = nbter.DecodeNBT(it.NBTData).(world.Item)
}
s := item.NewStack(t, int(it.Count))
return nbtconv.ReadItem(it.NBTData, &s)
}
func (w *WorldState) ProcessPacketServer(pk packet.Packet) (packet.Packet, bool) {
switch pk := pk.(type) {
case *packet.ChangeDimension:
w.ProcessChangeDimension(pk)
case *packet.LevelChunk:
w.ProcessLevelChunk(pk)
w.proxy.SendPopup(locale.Locm("popup_chunk_count", locale.Strmap{"Count": len(w.chunks), "Name": w.WorldName}, len(w.chunks)))
case *packet.SubChunk:
w.ProcessSubChunk(pk)
case *packet.ContainerOpen:
if w.experimentInventory {
// add to open containers
existing, ok := w.openItemContainers[pk.WindowID]
if !ok {
existing = &itemContainer{}
}
w.openItemContainers[pk.WindowID] = &itemContainer{
OpenPacket: pk,
Content: existing.Content,
}
}
case *packet.InventoryContent:
if w.experimentInventory {
// save content
existing, ok := w.openItemContainers[byte(pk.WindowID)]
if !ok {
if pk.WindowID == 0x0 { // inventory
w.openItemContainers[byte(pk.WindowID)] = &itemContainer{
Content: pk,
}
}
break
}
existing.Content = pk
}
case *packet.ContainerClose:
if w.experimentInventory {
switch pk.WindowID {
case protocol.WindowIDArmour: // todo handle
case protocol.WindowIDOffHand: // todo handle
case protocol.WindowIDUI:
case protocol.WindowIDInventory: // todo handle
default:
// find container info
existing, ok := w.openItemContainers[byte(pk.WindowID)]
if !ok {
logrus.Warn(locale.Loc("warn_window_closed_not_open", nil))
break
}
if existing.Content == nil {
break
}
pos := existing.OpenPacket.ContainerPosition
cp := protocol.SubChunkPos{pos.X() << 4, pos.Z() << 4}
// create inventory
inv := inventory.New(len(existing.Content.Content), nil)
for i, c := range existing.Content.Content {
item := stackToItem(c.Stack)
inv.SetItem(i, item)
}
// put into subchunk
nbts := w.blockNBT[cp]
for i, v := range nbts {
nbt_pos := protocol.BlockPos{v["x"].(int32), v["y"].(int32), v["z"].(int32)}
if nbt_pos == pos {
w.blockNBT[cp][i]["Items"] = nbtconv.InvToNBT(inv)
}
}
w.proxy.SendMessage(locale.Loc("saved_block_inv", nil))
// remove it again
delete(w.openItemContainers, byte(pk.WindowID))
}
}
case *packet.ItemComponent:
w.bp.ApplyComponentEntries(pk.Items)
}
return pk, true
}

View File

@ -0,0 +1,20 @@
package behaviourpack
import (
"github.com/df-mc/dragonfly/server/world"
"github.com/sandertv/gophertunnel/minecraft/protocol"
)
type blockBehaviour struct {
FormatVersion string `json:"format_version"`
MinecraftBlock world.MinecraftBlock `json:"minecraft:block"`
}
func (bp *BehaviourPack) AddBlock(block protocol.BlockEntry) {
entry := blockBehaviour{
FormatVersion: bp.formatVersion,
MinecraftBlock: world.ParseBlock(block),
}
bp.blocks = append(bp.blocks, entry)
}

View File

@ -2,17 +2,12 @@ package behaviourpack
import (
"archive/zip"
"bytes"
"crypto/sha256"
"encoding/json"
"os"
"path"
"strings"
"github.com/bedrock-tool/bedrocktool/utils"
"github.com/df-mc/dragonfly/server/world"
"github.com/google/uuid"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/resource"
"github.com/sirupsen/logrus"
)
@ -22,39 +17,7 @@ type BehaviourPack struct {
Manifest *resource.Manifest
blocks []blockBehaviour
items map[string]itemBehaviour
}
type blockBehaviour struct {
FormatVersion string `json:"format_version"`
MinecraftBlock world.MinecraftBlock `json:"minecraft:block"`
}
type itemDescription struct {
Category string `json:"category"`
Identifier string `json:"identifier"`
IsExperimental bool `json:"is_experimental"`
}
type minecraftItem struct {
Description itemDescription `json:"description"`
Components map[string]any `json:"components,omitempty"`
}
type itemBehaviour struct {
FormatVersion string `json:"format_version"`
MinecraftItem minecraftItem `json:"minecraft:item"`
}
func check(err error) {
if err != nil {
logrus.Fatal(err)
}
}
func rand_seeded_uuid(str string) string {
h := sha256.Sum256([]byte(str))
id, _ := uuid.NewRandomFromReader(bytes.NewBuffer(h[:]))
return id.String()
entities map[string]entityBehaviour
}
func New(name string) *BehaviourPack {
@ -65,22 +28,23 @@ func New(name string) *BehaviourPack {
Header: resource.Header{
Name: "pack.name",
Description: "pack.description",
UUID: rand_seeded_uuid(name + "_datapack"),
UUID: utils.Rand_seeded_uuid(name + "_datapack"),
Version: [3]int{1, 0, 0},
MinimumGameVersion: [3]int{1, 19, 50},
},
Modules: []resource.Module{
{
Type: "data",
UUID: rand_seeded_uuid(name + "_data_module"),
UUID: utils.Rand_seeded_uuid(name + "_data_module"),
Version: [3]int{1, 0, 0},
},
},
Dependencies: []resource.Dependency{},
Capabilities: []resource.Capability{},
},
blocks: []blockBehaviour{},
items: make(map[string]itemBehaviour),
blocks: []blockBehaviour{},
items: make(map[string]itemBehaviour),
entities: make(map[string]entityBehaviour),
}
}
@ -91,48 +55,17 @@ func (bp *BehaviourPack) AddDependency(id string, ver [3]int) {
})
}
func (bp *BehaviourPack) AddBlock(block protocol.BlockEntry) {
entry := blockBehaviour{
FormatVersion: bp.formatVersion,
MinecraftBlock: world.ParseBlock(block),
}
bp.blocks = append(bp.blocks, entry)
}
func (bp *BehaviourPack) AddItem(item protocol.ItemEntry) {
entry := itemBehaviour{
FormatVersion: bp.formatVersion,
MinecraftItem: minecraftItem{
Description: itemDescription{
Identifier: item.Name,
IsExperimental: true,
},
Components: make(map[string]any),
},
}
bp.items[item.Name] = entry
}
func (bp *BehaviourPack) ApplyComponentEntries(entries []protocol.ItemComponentEntry) {
for _, ice := range entries {
item, ok := bp.items[ice.Name]
if !ok {
continue
}
item.MinecraftItem.Components = ice.Data
}
}
func (bp *BehaviourPack) CheckAddLink(pack utils.Pack) {
z, err := zip.NewReader(pack, int64(pack.Len()))
if err != nil {
logrus.Error(err)
return
}
_, err = z.Open("blocks.json")
if err != nil {
return
if len(bp.blocks) > 0 {
_, err = z.Open("blocks.json")
if err != nil {
return
}
}
h := pack.Manifest().Header
bp.AddDependency(h.UUID, h.Version)
@ -142,6 +75,11 @@ func (bp *BehaviourPack) HasContent() bool {
return len(bp.blocks) > 0 || len(bp.items) > 0
}
func ns_name_split(identifier string) (ns, name string) {
ns_name := strings.Split(identifier, ":")
return ns_name[0], ns_name[len(ns_name)-1]
}
func (bp *BehaviourPack) Save(fpath string) error {
{ // write manifest
w, err := os.Create(path.Join(fpath, "manifest.json"))
@ -150,43 +88,54 @@ func (bp *BehaviourPack) Save(fpath string) error {
}
e := json.NewEncoder(w)
e.SetIndent("", "\t")
check(e.Encode(bp.Manifest))
if err = e.Encode(bp.Manifest); err != nil {
return err
}
}
_add_thing := func(base, identifier string, thing any) error {
ns, name := ns_name_split(identifier)
thing_dir := path.Join(base, ns)
os.Mkdir(thing_dir, 0o755)
w, err := os.Create(path.Join(thing_dir, name+".json"))
if err != nil {
return err
}
e := json.NewEncoder(w)
e.SetIndent("", "\t")
return e.Encode(thing)
}
if len(bp.blocks) > 0 { // blocks
blocks_dir := path.Join(fpath, "blocks")
os.Mkdir(blocks_dir, 0o755)
for _, be := range bp.blocks {
ns_name := strings.Split(be.MinecraftBlock.Description.Identifier, ":")
ns := ns_name[0]
name := ns_name[len(ns_name)-1]
block_dir := path.Join(blocks_dir, ns)
os.Mkdir(block_dir, 0o755)
w, err := os.Create(path.Join(block_dir, name+".json"))
err := _add_thing(blocks_dir, be.MinecraftBlock.Description.Identifier, be)
if err != nil {
return err
}
e := json.NewEncoder(w)
e.SetIndent("", "\t")
check(e.Encode(be))
}
}
if len(bp.items) > 0 { // items
items_dir := path.Join(fpath, "items")
os.Mkdir(items_dir, 0o755)
for _, ib := range bp.items {
ns_name := strings.Split(ib.MinecraftItem.Description.Identifier, ":")
ns := ns_name[0]
name := ns_name[len(ns_name)-1]
item_dir := path.Join(items_dir, ns)
os.Mkdir(item_dir, 0o755)
w, err := os.Create(path.Join(item_dir, name+".json"))
err := _add_thing(items_dir, ib.MinecraftItem.Description.Identifier, ib)
if err != nil {
return err
}
e := json.NewEncoder(w)
e.SetIndent("", "\t")
check(e.Encode(ib))
}
}
if len(bp.entities) > 0 { // items
items_dir := path.Join(fpath, "entities")
os.Mkdir(items_dir, 0o755)
for _, eb := range bp.entities {
err := _add_thing(items_dir, eb.MinecraftEntity.Description.Identifier, eb)
if err != nil {
return err
}
}
}
return nil
}

View File

@ -0,0 +1,68 @@
package behaviourpack
import "github.com/sandertv/gophertunnel/minecraft/protocol"
type clientEntityDescription struct {
Identifier string `json:"identifier"`
Spawnable bool `json:"is_spawnable"`
Summonable bool `json:"is_summonable"`
Experimental bool `json:"is_experimental"`
}
type minecraftClientEntity struct {
Description clientEntityDescription `json:"description"`
ComponentGroups map[string]any `json:"component_groups"`
Components map[string]any `json:"components"`
Events map[string]any `json:"events"`
}
type entityBehaviour struct {
FormatVersion string `json:"format_version"`
MinecraftEntity minecraftClientEntity `json:"minecraft:client_entity"`
}
type EntityIn struct {
Identifier string
Attr []protocol.AttributeValue
}
func (bp *BehaviourPack) AddEntity(entity EntityIn) {
ns, _ := ns_name_split(entity.Identifier)
if ns == "minecraft" {
return
}
if _, ok := bp.entities[entity.Identifier]; ok {
return
}
entry := entityBehaviour{
FormatVersion: bp.formatVersion,
MinecraftEntity: minecraftClientEntity{
Description: clientEntityDescription{
Identifier: entity.Identifier,
Spawnable: true,
Summonable: true,
Experimental: true,
},
ComponentGroups: nil,
Components: make(map[string]any),
Events: nil,
},
}
for _, av := range entity.Attr {
switch av.Name {
case "minecraft:health":
entry.MinecraftEntity.Components["minecraft:health"] = map[string]int{
"value": int(av.Value),
"max": int(av.Max),
}
case "minecraft:movement":
entry.MinecraftEntity.Components["minecraft:movement"] = map[string]any{
"value": av.Value,
}
}
}
bp.entities[entity.Identifier] = entry
}

View File

@ -0,0 +1,48 @@
package behaviourpack
import "github.com/sandertv/gophertunnel/minecraft/protocol"
type itemDescription struct {
Category string `json:"category"`
Identifier string `json:"identifier"`
IsExperimental bool `json:"is_experimental"`
}
type minecraftItem struct {
Description itemDescription `json:"description"`
Components map[string]any `json:"components,omitempty"`
}
type itemBehaviour struct {
FormatVersion string `json:"format_version"`
MinecraftItem minecraftItem `json:"minecraft:item"`
}
func (bp *BehaviourPack) AddItem(item protocol.ItemEntry) {
ns, _ := ns_name_split(item.Name)
if ns == "minecraft" {
return
}
entry := itemBehaviour{
FormatVersion: bp.formatVersion,
MinecraftItem: minecraftItem{
Description: itemDescription{
Identifier: item.Name,
IsExperimental: true,
},
Components: make(map[string]any),
},
}
bp.items[item.Name] = entry
}
func (bp *BehaviourPack) ApplyComponentEntries(entries []protocol.ItemComponentEntry) {
for _, ice := range entries {
item, ok := bp.items[ice.Name]
if !ok {
continue
}
item.MinecraftItem.Components = ice.Data
}
}

View File

@ -13,22 +13,23 @@ import (
//go:embed key.gpg
var key_gpg []byte
var recip *openpgp.Entity
var recipients []*openpgp.Entity
func init() {
block, err := armor.Decode(bytes.NewBuffer(key_gpg))
if err != nil {
panic(err)
}
recip, err = openpgp.ReadEntity(packet.NewReader(block.Body))
recip, err := openpgp.ReadEntity(packet.NewReader(block.Body))
if err != nil {
panic(err)
}
recipients = append(recipients, recip)
}
func Enc(name string, data []byte) ([]byte, error) {
w := bytes.NewBuffer(nil)
wc, err := openpgp.Encrypt(w, []*openpgp.Entity{recip}, nil, &openpgp.FileHints{
wc, err := openpgp.Encrypt(w, recipients, nil, &openpgp.FileHints{
IsBinary: true, FileName: name, ModTime: time.Now(),
}, nil)
if err != nil {
@ -42,7 +43,7 @@ func Enc(name string, data []byte) ([]byte, error) {
}
func Encer(name string, w io.Writer) (io.WriteCloser, error) {
wc, err := openpgp.Encrypt(w, []*openpgp.Entity{recip}, nil, &openpgp.FileHints{
wc, err := openpgp.Encrypt(w, recipients, nil, &openpgp.FileHints{
IsBinary: true, FileName: name, ModTime: time.Now(),
}, nil)
return wc, err

View File

@ -34,3 +34,18 @@ func BlendColors(c1, c2 color.RGBA) (ret color.RGBA) {
ret.A = blendAlphaValue(c1.A, c2.A)
return ret
}
// Draw_img_scaled_pos draws src onto dst at bottom_left, scaled to size
func Draw_img_scaled_pos(dst *image.RGBA, src *image.RGBA, bottom_left image.Point, size_scaled int) {
sbx := src.Bounds().Dx()
ratio := int(float64(sbx) / float64(size_scaled))
for x_out := bottom_left.X; x_out < bottom_left.X+size_scaled; x_out++ {
for y_out := bottom_left.Y; y_out < bottom_left.Y+size_scaled; y_out++ {
x_in := (x_out - bottom_left.X) * ratio
y_in := (y_out - bottom_left.Y) * ratio
c := src.At(x_in, y_in)
dst.Set(x_out, y_out, c)
}
}
}

View File

@ -55,7 +55,7 @@ func ServerInput(ctx context.Context, server string) (address, name string, err
if len(realm_info) == 3 {
id = realm_info[2]
}
name, address, err = get_realm(context.Background(), GetRealmsApi(), realm_info[1], id)
name, address, err = get_realm(ctx, realm_info[1], id)
if err != nil {
return "", "", err
}

View File

@ -8,12 +8,11 @@ import (
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/google/subcommands"
"github.com/sandertv/gophertunnel/minecraft/realms"
"github.com/sirupsen/logrus"
)
func get_realm(ctx context.Context, api *realms.Client, realm_name, id string) (name string, address string, err error) {
realms, err := api.Realms(ctx)
func get_realm(ctx context.Context, realm_name, id string) (name string, address string, err error) {
realms, err := GetRealmsApi().Realms(ctx)
if err != nil {
return "", "", err
}
@ -44,8 +43,7 @@ func (c *RealmListCMD) Usage() string {
}
func (c *RealmListCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
api := realms.NewClient(GetTokenSource())
realms, err := api.Realms(ctx)
realms, err := GetRealmsApi().Realms(ctx)
if err != nil {
logrus.Error(err)
return 1

View File

@ -5,6 +5,7 @@ import (
"context"
"encoding/binary"
"io"
"net"
"os"
"github.com/sandertv/gophertunnel/minecraft"
@ -84,7 +85,9 @@ func create_replay_connection(ctx context.Context, filename string, onConnect Co
b := protocol.NewWriter(f, 0)
pk.Marshal(b)
// PacketLogger(packet.Header{PacketID: pk.ID()}, f.Bytes(), &net.UDPAddr{}, &net.UDPAddr{})
if G_debug {
PacketLogger(packet.Header{PacketID: pk.ID()}, f.Bytes(), &net.UDPAddr{}, &net.UDPAddr{})
}
if game_started {
if packetCB != nil {

Binary file not shown.

View File

@ -13,6 +13,7 @@ type Pack interface {
ReadAll() ([]byte, error)
Decrypt() ([]byte, error)
Encrypted() bool
CanDecrypt() bool
UUID() string
Name() string
Version() string
@ -42,6 +43,10 @@ func (p *Packb) ReadAll() ([]byte, error) {
return buf, nil
}
func (p *Packb) CanDecrypt() bool {
return false
}
func (p *Packb) Decrypt() ([]byte, error) {
return nil, errors.New("no_decrypt")
}
@ -59,7 +64,7 @@ func GetPacks(server *minecraft.Conn) (packs map[string]*resource.Pack, err erro
packs = make(map[string]*resource.Pack)
for _, pack := range server.ResourcePacks() {
pack := PackFromBase(pack)
if pack.Encrypted() {
if pack.Encrypted() && pack.CanDecrypt() {
data, err := pack.Decrypt()
if err != nil {
return nil, err

View File

@ -1,7 +1,9 @@
package utils
import (
"bytes"
"context"
"crypto/sha256"
"encoding/json"
"errors"
"net"
@ -152,3 +154,10 @@ func Clamp(a, b int) int {
}
return a
}
func Rand_seeded_uuid(str string) string {
h := sha256.Sum256([]byte(str))
id, _ := uuid.NewRandomFromReader(bytes.NewBuffer(h[:]))
return id.String()
}