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" "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 } type serverEntityType struct { world.SaveableEntityType 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 } func (t serverEntityType) UniqueID() int64 { return t.NBT["UniqueID"].(int64) } type serverEntity struct { world.Entity EntityType serverEntityType } 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 entityMetadataToNBT(metadata protocol.EntityMetadata, nbt map[string]any) { if variant, ok := metadata[protocol.EntityDataKeyVariant].(int32); ok { block, ok := world.BlockByRuntimeID(uint32(variant)) if ok { nbt["name"], _ = block.EncodeBlock() } } if name, ok := metadata[protocol.EntityDataKeyName].(string); ok { nbt["CustomName"] = name } if ShowNameTag, ok := metadata[protocol.EntityDataKeyAlwaysShowNameTag].(uint8); ok { if ShowNameTag != 0 { nbt["CustomNameVisible"] = true } else { nbt["CustomNameVisible"] = false } } if scale, ok := metadata[protocol.EntityDataKeyScale].(float32); ok { nbt["Scale"] = scale } } 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) return e } 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 }