mirror of
https://github.com/CosmicStar98/bedrocktool.git
synced 2024-06-25 06:29:45 +00:00
add custom items, (untested probably not working entities)
This commit is contained in:
parent
ea6dea7953
commit
32f1e8019a
|
@ -72,7 +72,7 @@ func (c *CaptureCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interfac
|
||||||
|
|
||||||
proxy := utils.NewProxy()
|
proxy := utils.NewProxy()
|
||||||
proxy.PacketFunc = func(header packet.Header, payload []byte, src, dst net.Addr) {
|
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)
|
buf := bytes.NewBuffer(nil)
|
||||||
header.Write(buf)
|
header.Write(buf)
|
||||||
|
|
112
subcommands/world/chunk.go
Normal file
112
subcommands/world/chunk.go
Normal 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
133
subcommands/world/entity.go
Normal 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
167
subcommands/world/items.go
Normal 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)
|
||||||
|
}
|
|
@ -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() {
|
func (m *MapUI) Stop() {
|
||||||
|
@ -139,21 +154,6 @@ func (m *MapUI) SchedRedraw() {
|
||||||
m.needRedraw = true
|
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
|
// draw chunk images to the map image
|
||||||
func (m *MapUI) Redraw() {
|
func (m *MapUI) Redraw() {
|
||||||
for {
|
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() {
|
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.renderQueue.Enqueue(&RenderElem{pos, ch})
|
||||||
m.SchedRedraw()
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -7,24 +7,18 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
|
||||||
"image/png"
|
"image/png"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
"github.com/bedrock-tool/bedrocktool/locale"
|
||||||
"github.com/bedrock-tool/bedrocktool/utils"
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
"github.com/bedrock-tool/bedrocktool/utils/behaviourpack"
|
"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/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"
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||||
"github.com/df-mc/dragonfly/server/world/mcdb"
|
"github.com/df-mc/dragonfly/server/world/mcdb"
|
||||||
|
@ -33,10 +27,7 @@ import (
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/resource"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
//_ "github.com/df-mc/dragonfly/server/block" // to load blocks
|
|
||||||
//_ "net/http/pprof"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TPlayerPos struct {
|
type TPlayerPos struct {
|
||||||
|
@ -46,11 +37,6 @@ type TPlayerPos struct {
|
||||||
HeadYaw float32
|
HeadYaw float32
|
||||||
}
|
}
|
||||||
|
|
||||||
type itemContainer struct {
|
|
||||||
OpenPacket *packet.ContainerOpen
|
|
||||||
Content *packet.InventoryContent
|
|
||||||
}
|
|
||||||
|
|
||||||
// the state used for drawing and saving
|
// the state used for drawing and saving
|
||||||
|
|
||||||
type WorldState struct {
|
type WorldState struct {
|
||||||
|
@ -60,12 +46,12 @@ type WorldState struct {
|
||||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||||
blockNBT map[protocol.SubChunkPos][]map[string]any
|
blockNBT map[protocol.SubChunkPos][]map[string]any
|
||||||
openItemContainers map[byte]*itemContainer
|
openItemContainers map[byte]*itemContainer
|
||||||
|
entities map[uint64]*entityState
|
||||||
|
|
||||||
Dim world.Dimension
|
Dim world.Dimension
|
||||||
WorldName string
|
WorldName string
|
||||||
ServerName string
|
ServerName string
|
||||||
worldCounter int
|
worldCounter int
|
||||||
packs map[string]*resource.Pack
|
|
||||||
bp *behaviourpack.BehaviourPack
|
bp *behaviourpack.BehaviourPack
|
||||||
|
|
||||||
withPacks bool
|
withPacks bool
|
||||||
|
@ -84,6 +70,7 @@ func NewWorldState() *WorldState {
|
||||||
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
|
||||||
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
|
||||||
openItemContainers: make(map[byte]*itemContainer),
|
openItemContainers: make(map[byte]*itemContainer),
|
||||||
|
entities: make(map[uint64]*entityState),
|
||||||
Dim: nil,
|
Dim: nil,
|
||||||
WorldName: "world",
|
WorldName: "world",
|
||||||
PlayerPos: TPlayerPos{},
|
PlayerPos: TPlayerPos{},
|
||||||
|
@ -111,7 +98,9 @@ func init() {
|
||||||
for i := range Offset_table {
|
for i := range Offset_table {
|
||||||
Offset_table[i] = protocol.SubChunkOffset{0, int8(i), 0}
|
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{})
|
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 {
|
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)
|
server_address, hostname, err := utils.ServerInput(ctx, c.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
|
@ -164,12 +147,19 @@ func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{
|
||||||
proxy.AlwaysGetPacks = true
|
proxy.AlwaysGetPacks = true
|
||||||
proxy.ConnectCB = w.OnConnect
|
proxy.ConnectCB = w.OnConnect
|
||||||
proxy.PacketCB = func(pk packet.Packet, proxy *utils.ProxyContext, toServer bool) (packet.Packet, error) {
|
proxy.PacketCB = func(pk packet.Packet, proxy *utils.ProxyContext, toServer bool) (packet.Packet, error) {
|
||||||
var forward bool
|
var forward bool = true
|
||||||
|
|
||||||
if toServer {
|
if toServer {
|
||||||
pk, forward = w.ProcessPacketClient(pk)
|
// from client
|
||||||
|
pk = w.processItemPacketsClient(pk, &forward)
|
||||||
|
pk = w.processMapPacketsClient(pk, &forward)
|
||||||
} else {
|
} else {
|
||||||
pk, forward = w.ProcessPacketServer(pk)
|
// from server
|
||||||
|
pk = w.processItemPacketsServer(pk)
|
||||||
|
pk = w.ProcessChunkPackets(pk)
|
||||||
|
pk = w.ProcessEntityPackets(pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !forward {
|
if !forward {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -185,98 +175,6 @@ func (c *WorldCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{
|
||||||
return 0
|
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) {
|
func (w *WorldState) ProcessAnimate(pk *packet.Animate) {
|
||||||
if pk.ActionType == packet.AnimateActionSwingArm {
|
if pk.ActionType == packet.AnimateActionSwingArm {
|
||||||
w.ui.ChangeZoom()
|
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) {
|
func (w *WorldState) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
|
||||||
last := w.PlayerPos
|
last := w.PlayerPos
|
||||||
w.PlayerPos = TPlayerPos{
|
w.PlayerPos = TPlayerPos{
|
||||||
|
@ -342,13 +226,31 @@ func (w *WorldState) SaveAndReset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// save block nbt data
|
// 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
|
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...)
|
blockNBT[cp] = append(blockNBT[cp], v...)
|
||||||
}
|
}
|
||||||
for cp, v := range blockNBT {
|
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 {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -473,23 +375,7 @@ func (w *WorldState) SaveAndReset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
// save behaviourpack
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if w.bp.HasContent() {
|
if w.bp.HasContent() {
|
||||||
name := strings.ReplaceAll(w.ServerName, "/", "-") + "_blocks"
|
name := strings.ReplaceAll(w.ServerName, "/", "-") + "_blocks"
|
||||||
pack_folder := path.Join(folder, "behavior_packs", name)
|
pack_folder := path.Join(folder, "behavior_packs", name)
|
||||||
|
@ -505,6 +391,33 @@ func (w *WorldState) SaveAndReset() {
|
||||||
PackId: w.bp.Manifest.Header.UUID,
|
PackId: w.bp.Manifest.Header.UUID,
|
||||||
Version: w.bp.Manifest.Header.Version,
|
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 {
|
if w.saveImage {
|
||||||
|
@ -515,7 +428,6 @@ func (w *WorldState) SaveAndReset() {
|
||||||
|
|
||||||
// zip it
|
// zip it
|
||||||
filename := folder + ".mcworld"
|
filename := folder + ".mcworld"
|
||||||
|
|
||||||
if err := utils.ZipFolder(filename, folder); err != nil {
|
if err := utils.ZipFolder(filename, folder); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
@ -531,9 +443,7 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
|
||||||
world.InsertCustomItems(gd.Items)
|
world.InsertCustomItems(gd.Items)
|
||||||
|
|
||||||
for _, ie := range 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")
|
map_item_id, _ := world.ItemRidByName("minecraft:filled_map")
|
||||||
|
@ -551,12 +461,6 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
|
||||||
world.InsertCustomBlocks(gd.CustomBlocks)
|
world.InsertCustomBlocks(gd.CustomBlocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.withPacks {
|
|
||||||
go func() {
|
|
||||||
w.packs, _ = utils.GetPacks(w.proxy.Server)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // check game version
|
{ // check game version
|
||||||
gv := strings.Split(gd.BaseGameVersion, ".")
|
gv := strings.Split(gd.BaseGameVersion, ".")
|
||||||
var err error
|
var err error
|
||||||
|
@ -580,26 +484,13 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
|
||||||
w.proxy.SendMessage(locale.Loc("use_setname", nil))
|
w.proxy.SendMessage(locale.Loc("use_setname", nil))
|
||||||
|
|
||||||
w.ui.Start()
|
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{
|
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{
|
Cmd: protocol.Command{
|
||||||
Name: "setname",
|
Name: "setname",
|
||||||
Description: locale.Loc("setname_desc", nil),
|
Description: locale.Loc("setname_desc", nil),
|
||||||
|
@ -618,179 +509,20 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext) {
|
||||||
})
|
})
|
||||||
|
|
||||||
proxy.AddCommand(utils.IngameCommand{
|
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{
|
Cmd: protocol.Command{
|
||||||
Name: "void",
|
Name: "void",
|
||||||
Description: locale.Loc("void_desc", nil),
|
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
|
|
||||||
}
|
|
||||||
|
|
20
utils/behaviourpack/block.go
Normal file
20
utils/behaviourpack/block.go
Normal 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)
|
||||||
|
}
|
|
@ -2,17 +2,12 @@ package behaviourpack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bedrock-tool/bedrocktool/utils"
|
"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/sandertv/gophertunnel/minecraft/resource"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -22,39 +17,7 @@ type BehaviourPack struct {
|
||||||
Manifest *resource.Manifest
|
Manifest *resource.Manifest
|
||||||
blocks []blockBehaviour
|
blocks []blockBehaviour
|
||||||
items map[string]itemBehaviour
|
items map[string]itemBehaviour
|
||||||
}
|
entities map[string]entityBehaviour
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(name string) *BehaviourPack {
|
func New(name string) *BehaviourPack {
|
||||||
|
@ -65,22 +28,23 @@ func New(name string) *BehaviourPack {
|
||||||
Header: resource.Header{
|
Header: resource.Header{
|
||||||
Name: "pack.name",
|
Name: "pack.name",
|
||||||
Description: "pack.description",
|
Description: "pack.description",
|
||||||
UUID: rand_seeded_uuid(name + "_datapack"),
|
UUID: utils.Rand_seeded_uuid(name + "_datapack"),
|
||||||
Version: [3]int{1, 0, 0},
|
Version: [3]int{1, 0, 0},
|
||||||
MinimumGameVersion: [3]int{1, 19, 50},
|
MinimumGameVersion: [3]int{1, 19, 50},
|
||||||
},
|
},
|
||||||
Modules: []resource.Module{
|
Modules: []resource.Module{
|
||||||
{
|
{
|
||||||
Type: "data",
|
Type: "data",
|
||||||
UUID: rand_seeded_uuid(name + "_data_module"),
|
UUID: utils.Rand_seeded_uuid(name + "_data_module"),
|
||||||
Version: [3]int{1, 0, 0},
|
Version: [3]int{1, 0, 0},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Dependencies: []resource.Dependency{},
|
Dependencies: []resource.Dependency{},
|
||||||
Capabilities: []resource.Capability{},
|
Capabilities: []resource.Capability{},
|
||||||
},
|
},
|
||||||
blocks: []blockBehaviour{},
|
blocks: []blockBehaviour{},
|
||||||
items: make(map[string]itemBehaviour),
|
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) {
|
func (bp *BehaviourPack) CheckAddLink(pack utils.Pack) {
|
||||||
z, err := zip.NewReader(pack, int64(pack.Len()))
|
z, err := zip.NewReader(pack, int64(pack.Len()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = z.Open("blocks.json")
|
if len(bp.blocks) > 0 {
|
||||||
if err != nil {
|
_, err = z.Open("blocks.json")
|
||||||
return
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
h := pack.Manifest().Header
|
h := pack.Manifest().Header
|
||||||
bp.AddDependency(h.UUID, h.Version)
|
bp.AddDependency(h.UUID, h.Version)
|
||||||
|
@ -142,6 +75,11 @@ func (bp *BehaviourPack) HasContent() bool {
|
||||||
return len(bp.blocks) > 0 || len(bp.items) > 0
|
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 {
|
func (bp *BehaviourPack) Save(fpath string) error {
|
||||||
{ // write manifest
|
{ // write manifest
|
||||||
w, err := os.Create(path.Join(fpath, "manifest.json"))
|
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 := json.NewEncoder(w)
|
||||||
e.SetIndent("", "\t")
|
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
|
if len(bp.blocks) > 0 { // blocks
|
||||||
blocks_dir := path.Join(fpath, "blocks")
|
blocks_dir := path.Join(fpath, "blocks")
|
||||||
os.Mkdir(blocks_dir, 0o755)
|
os.Mkdir(blocks_dir, 0o755)
|
||||||
for _, be := range bp.blocks {
|
for _, be := range bp.blocks {
|
||||||
ns_name := strings.Split(be.MinecraftBlock.Description.Identifier, ":")
|
err := _add_thing(blocks_dir, be.MinecraftBlock.Description.Identifier, be)
|
||||||
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"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e := json.NewEncoder(w)
|
|
||||||
e.SetIndent("", "\t")
|
|
||||||
check(e.Encode(be))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(bp.items) > 0 { // items
|
if len(bp.items) > 0 { // items
|
||||||
items_dir := path.Join(fpath, "items")
|
items_dir := path.Join(fpath, "items")
|
||||||
os.Mkdir(items_dir, 0o755)
|
os.Mkdir(items_dir, 0o755)
|
||||||
for _, ib := range bp.items {
|
for _, ib := range bp.items {
|
||||||
ns_name := strings.Split(ib.MinecraftItem.Description.Identifier, ":")
|
err := _add_thing(items_dir, ib.MinecraftItem.Description.Identifier, ib)
|
||||||
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"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
68
utils/behaviourpack/entity.go
Normal file
68
utils/behaviourpack/entity.go
Normal 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
|
||||||
|
}
|
48
utils/behaviourpack/item.go
Normal file
48
utils/behaviourpack/item.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,22 +13,23 @@ import (
|
||||||
|
|
||||||
//go:embed key.gpg
|
//go:embed key.gpg
|
||||||
var key_gpg []byte
|
var key_gpg []byte
|
||||||
var recip *openpgp.Entity
|
var recipients []*openpgp.Entity
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
block, err := armor.Decode(bytes.NewBuffer(key_gpg))
|
block, err := armor.Decode(bytes.NewBuffer(key_gpg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
recip, err = openpgp.ReadEntity(packet.NewReader(block.Body))
|
recip, err := openpgp.ReadEntity(packet.NewReader(block.Body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
recipients = append(recipients, recip)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Enc(name string, data []byte) ([]byte, error) {
|
func Enc(name string, data []byte) ([]byte, error) {
|
||||||
w := bytes.NewBuffer(nil)
|
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(),
|
IsBinary: true, FileName: name, ModTime: time.Now(),
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != 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) {
|
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(),
|
IsBinary: true, FileName: name, ModTime: time.Now(),
|
||||||
}, nil)
|
}, nil)
|
||||||
return wc, err
|
return wc, err
|
||||||
|
|
|
@ -34,3 +34,18 @@ func BlendColors(c1, c2 color.RGBA) (ret color.RGBA) {
|
||||||
ret.A = blendAlphaValue(c1.A, c2.A)
|
ret.A = blendAlphaValue(c1.A, c2.A)
|
||||||
return ret
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ func ServerInput(ctx context.Context, server string) (address, name string, err
|
||||||
if len(realm_info) == 3 {
|
if len(realm_info) == 3 {
|
||||||
id = realm_info[2]
|
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 {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,11 @@ import (
|
||||||
|
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
"github.com/bedrock-tool/bedrocktool/locale"
|
||||||
"github.com/google/subcommands"
|
"github.com/google/subcommands"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/realms"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func get_realm(ctx context.Context, api *realms.Client, realm_name, id string) (name string, address string, err error) {
|
func get_realm(ctx context.Context, realm_name, id string) (name string, address string, err error) {
|
||||||
realms, err := api.Realms(ctx)
|
realms, err := GetRealmsApi().Realms(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
@ -44,8 +43,7 @@ func (c *RealmListCMD) Usage() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RealmListCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
func (c *RealmListCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||||
api := realms.NewClient(GetTokenSource())
|
realms, err := GetRealmsApi().Realms(ctx)
|
||||||
realms, err := api.Realms(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sandertv/gophertunnel/minecraft"
|
"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)
|
b := protocol.NewWriter(f, 0)
|
||||||
pk.Marshal(b)
|
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 game_started {
|
||||||
if packetCB != nil {
|
if packetCB != nil {
|
||||||
|
|
Binary file not shown.
|
@ -13,6 +13,7 @@ type Pack interface {
|
||||||
ReadAll() ([]byte, error)
|
ReadAll() ([]byte, error)
|
||||||
Decrypt() ([]byte, error)
|
Decrypt() ([]byte, error)
|
||||||
Encrypted() bool
|
Encrypted() bool
|
||||||
|
CanDecrypt() bool
|
||||||
UUID() string
|
UUID() string
|
||||||
Name() string
|
Name() string
|
||||||
Version() string
|
Version() string
|
||||||
|
@ -42,6 +43,10 @@ func (p *Packb) ReadAll() ([]byte, error) {
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Packb) CanDecrypt() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Packb) Decrypt() ([]byte, error) {
|
func (p *Packb) Decrypt() ([]byte, error) {
|
||||||
return nil, errors.New("no_decrypt")
|
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)
|
packs = make(map[string]*resource.Pack)
|
||||||
for _, pack := range server.ResourcePacks() {
|
for _, pack := range server.ResourcePacks() {
|
||||||
pack := PackFromBase(pack)
|
pack := PackFromBase(pack)
|
||||||
if pack.Encrypted() {
|
if pack.Encrypted() && pack.CanDecrypt() {
|
||||||
data, err := pack.Decrypt()
|
data, err := pack.Decrypt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
@ -152,3 +154,10 @@ func Clamp(a, b int) int {
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Rand_seeded_uuid(str string) string {
|
||||||
|
h := sha256.Sum256([]byte(str))
|
||||||
|
id, _ := uuid.NewRandomFromReader(bytes.NewBuffer(h[:]))
|
||||||
|
return id.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user