293 lines
7.9 KiB
Go
293 lines
7.9 KiB
Go
package worlds
|
|
|
|
import (
|
|
"github.com/bedrock-tool/bedrocktool/utils/behaviourpack"
|
|
"github.com/bedrock-tool/bedrocktool/utils/nbtconv"
|
|
"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"
|
|
"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 protocol.EntityMetadata
|
|
Inventory map[byte]map[byte]protocol.ItemInstance
|
|
|
|
Helmet *protocol.ItemInstance
|
|
Chestplate *protocol.ItemInstance
|
|
Leggings *protocol.ItemInstance
|
|
Boots *protocol.ItemInstance
|
|
}
|
|
|
|
type serverEntityType struct {
|
|
Encoded string
|
|
NBT map[string]any
|
|
}
|
|
|
|
func (t serverEntityType) EncodeEntity() string {
|
|
return t.Encoded
|
|
}
|
|
|
|
func (t serverEntityType) BBox(e world.Entity) cube.BBox {
|
|
return cube.Box(-0.5, 0, -0.5, 0.5, 1, 0.5)
|
|
}
|
|
|
|
func (t serverEntityType) DecodeNBT(m map[string]any) world.Entity {
|
|
return nil // not implemented, and never should
|
|
}
|
|
|
|
func (t serverEntityType) EncodeNBT(e world.Entity) map[string]any {
|
|
return t.NBT
|
|
}
|
|
|
|
type serverEntity struct {
|
|
world.Entity
|
|
EntityType serverEntityType
|
|
}
|
|
|
|
var _ world.SaveableEntityType = &serverEntityType{}
|
|
|
|
func (e serverEntity) Type() world.EntityType {
|
|
return e.EntityType
|
|
}
|
|
|
|
func (w *worldsHandler) processAddActor(pk *packet.AddActor) {
|
|
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
|
if !ok {
|
|
e = &entityState{
|
|
RuntimeID: pk.EntityRuntimeID,
|
|
UniqueID: pk.EntityUniqueID,
|
|
EntityType: pk.EntityType,
|
|
Inventory: make(map[byte]map[byte]protocol.ItemInstance),
|
|
Metadata: make(map[uint32]any),
|
|
}
|
|
w.worldState.entities[pk.EntityRuntimeID] = e
|
|
|
|
w.bp.AddEntity(behaviourpack.EntityIn{
|
|
Identifier: pk.EntityType,
|
|
Attr: pk.Attributes,
|
|
Meta: pk.EntityMetadata,
|
|
})
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
var flagNames = map[uint8]string{
|
|
protocol.EntityDataFlagSheared: "Sheared",
|
|
protocol.EntityDataFlagCaptain: "IsIllagerCaptain",
|
|
protocol.EntityDataFlagSitting: "Sitting",
|
|
protocol.EntityDataFlagBaby: "IsBaby",
|
|
protocol.EntityDataFlagTamed: "IsTamed",
|
|
protocol.EntityDataFlagTrusting: "IsTrusting",
|
|
protocol.EntityDataFlagOrphaned: "IsOrphaned",
|
|
protocol.EntityDataFlagAngry: "IsAngry",
|
|
protocol.EntityDataFlagOutOfControl: "IsOutOfControl",
|
|
protocol.EntityDataFlagSaddled: "Saddled",
|
|
protocol.EntityDataFlagChested: "Chested",
|
|
protocol.EntityDataFlagShowBottom: "ShowBottom",
|
|
protocol.EntityDataFlagGliding: "IsGliding",
|
|
protocol.EntityDataFlagSwimming: "IsSwimming",
|
|
protocol.EntityDataFlagEating: "IsEating",
|
|
protocol.EntityDataFlagScared: "IsScared",
|
|
protocol.EntityDataFlagStunned: "IsStunned",
|
|
protocol.EntityDataFlagRoaring: "IsRoaring",
|
|
}
|
|
|
|
func entityMetadataToNBT(metadata protocol.EntityMetadata, nbt map[string]any) {
|
|
if variant, ok := metadata[protocol.EntityDataKeyVariant]; ok {
|
|
nbt["Variant"] = variant
|
|
}
|
|
if markVariant, ok := metadata[protocol.EntityDataKeyMarkVariant]; ok {
|
|
nbt["MarkVariant"] = markVariant
|
|
}
|
|
if color, ok := metadata[protocol.EntityDataKeyColorIndex]; ok {
|
|
nbt["Color"] = color
|
|
}
|
|
if color2, ok := metadata[protocol.EntityDataKeyColorTwoIndex]; ok {
|
|
nbt["Color2"] = color2
|
|
}
|
|
if skinID, ok := metadata[protocol.EntityDataKeySkinID]; ok {
|
|
nbt["SkinID"] = int32(skinID.(int32))
|
|
}
|
|
|
|
if name, ok := metadata[protocol.EntityDataKeyName]; ok {
|
|
nbt["CustomName"] = name
|
|
}
|
|
if ShowNameTag, ok := metadata[protocol.EntityDataKeyAlwaysShowNameTag]; ok {
|
|
if ShowNameTag != 0 {
|
|
nbt["CustomNameVisible"] = true
|
|
} else {
|
|
nbt["CustomNameVisible"] = false
|
|
}
|
|
}
|
|
|
|
if _, ok := metadata[protocol.EntityDataKeyFlags]; ok {
|
|
if metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagNoAI) {
|
|
nbt["IsAutonomous"] = false
|
|
}
|
|
for k, v := range flagNames {
|
|
nbt[v] = metadata.Flag(protocol.EntityDataKeyFlags, k)
|
|
}
|
|
|
|
AlwaysShowName := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagAlwaysShowName)
|
|
if AlwaysShowName {
|
|
nbt["CustomNameVisible"] = true
|
|
}
|
|
|
|
type effect struct {
|
|
Id byte
|
|
Amplifier byte
|
|
Duration int32
|
|
DurationEasy int32
|
|
DurationNormal int32
|
|
DurationHard int32
|
|
Ambient bool
|
|
ShowParticles bool
|
|
DisplayOnScreenTextureAnimation bool
|
|
}
|
|
|
|
activeEffects := []effect{}
|
|
addEffect := func(id int, showParticles bool) {
|
|
activeEffects = append(activeEffects, effect{
|
|
Id: byte(id),
|
|
Amplifier: 1,
|
|
Duration: 10000000,
|
|
ShowParticles: false,
|
|
})
|
|
}
|
|
|
|
invisible := metadata.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagInvisible)
|
|
if invisible {
|
|
addEffect(packet.EffectInvisibility, false)
|
|
}
|
|
|
|
if len(activeEffects) > 0 {
|
|
nbt["ActiveEffects"] = activeEffects
|
|
}
|
|
}
|
|
}
|
|
|
|
func vec3float32(x mgl32.Vec3) []float32 {
|
|
return []float32{float32(x[0]), float32(x[1]), float32(x[2])}
|
|
}
|
|
|
|
func (s *entityState) ToServerEntity() serverEntity {
|
|
e := serverEntity{
|
|
EntityType: serverEntityType{
|
|
Encoded: s.EntityType,
|
|
NBT: map[string]any{
|
|
"Pos": vec3float32(s.Position),
|
|
"Rotation": []float32{s.Yaw, s.Pitch},
|
|
"Motion": vec3float32(s.Velocity),
|
|
"UniqueID": int64(s.UniqueID),
|
|
},
|
|
},
|
|
}
|
|
entityMetadataToNBT(s.Metadata, e.EntityType.NBT)
|
|
|
|
if s.Helmet != nil || s.Chestplate != nil || s.Leggings != nil || s.Boots != nil {
|
|
e.EntityType.NBT["Armor"] = []map[string]any{
|
|
nbtconv.WriteItem(stackToItem(s.Helmet.Stack), true),
|
|
nbtconv.WriteItem(stackToItem(s.Chestplate.Stack), true),
|
|
nbtconv.WriteItem(stackToItem(s.Leggings.Stack), true),
|
|
nbtconv.WriteItem(stackToItem(s.Boots.Stack), true),
|
|
}
|
|
}
|
|
return e
|
|
}
|
|
|
|
func (w *worldsHandler) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
|
if !w.settings.SaveEntities {
|
|
return pk
|
|
}
|
|
|
|
switch pk := pk.(type) {
|
|
case *packet.AddActor:
|
|
w.processAddActor(pk)
|
|
case *packet.RemoveActor:
|
|
case *packet.SetActorData:
|
|
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
|
if ok {
|
|
e.Metadata = pk.EntityMetadata
|
|
w.bp.AddEntity(behaviourpack.EntityIn{
|
|
Identifier: e.EntityType,
|
|
Attr: nil,
|
|
Meta: pk.EntityMetadata,
|
|
})
|
|
}
|
|
case *packet.SetActorMotion:
|
|
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
|
if ok {
|
|
e.Velocity = pk.Velocity
|
|
}
|
|
case *packet.MoveActorDelta:
|
|
e, ok := w.worldState.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.worldState.entities[pk.EntityRuntimeID]
|
|
if ok {
|
|
e.Position = pk.Position
|
|
e.Pitch = pk.Rotation.X()
|
|
e.Yaw = pk.Rotation.Y()
|
|
}
|
|
case *packet.MobEquipment:
|
|
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
|
if ok {
|
|
w, ok := e.Inventory[pk.WindowID]
|
|
if !ok {
|
|
w = make(map[byte]protocol.ItemInstance)
|
|
e.Inventory[pk.WindowID] = w
|
|
}
|
|
w[pk.HotBarSlot] = pk.NewItem
|
|
}
|
|
case *packet.MobArmourEquipment:
|
|
e, ok := w.worldState.entities[pk.EntityRuntimeID]
|
|
if ok {
|
|
e.Helmet = &pk.Helmet
|
|
e.Chestplate = &pk.Chestplate
|
|
e.Leggings = &pk.Chestplate
|
|
e.Boots = &pk.Boots
|
|
}
|
|
}
|
|
return pk
|
|
}
|