github.com/df-mc/dragonfly@v0.9.13/server/session/entity_metadata.go (about) 1 package session 2 3 import ( 4 "github.com/df-mc/dragonfly/server/entity" 5 "github.com/df-mc/dragonfly/server/entity/effect" 6 "github.com/df-mc/dragonfly/server/internal/nbtconv" 7 "github.com/df-mc/dragonfly/server/item" 8 "github.com/df-mc/dragonfly/server/item/potion" 9 "github.com/df-mc/dragonfly/server/world" 10 "github.com/go-gl/mathgl/mgl64" 11 "github.com/sandertv/gophertunnel/minecraft/protocol" 12 "math" 13 "time" 14 ) 15 16 // parseEntityMetadata returns an entity metadata object with default values. It is equivalent to setting 17 // all properties to their default values and disabling all flags. 18 func (s *Session) parseEntityMetadata(e world.Entity) protocol.EntityMetadata { 19 bb := e.Type().BBox(e) 20 m := protocol.NewEntityMetadata() 21 22 m[protocol.EntityDataKeyWidth] = float32(bb.Width()) 23 m[protocol.EntityDataKeyHeight] = float32(bb.Height()) 24 m[protocol.EntityDataKeyEffectColor] = int32(0) 25 m[protocol.EntityDataKeyEffectAmbience] = byte(0) 26 m[protocol.EntityDataKeyColorIndex] = byte(0) 27 28 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagHasGravity) 29 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagClimb) 30 if g, ok := e.Type().(glint); ok && g.Glint() { 31 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagEnchanted) 32 } 33 if _, ok := e.Type().(entity.LingeringPotionType); ok { 34 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagLingering) 35 } 36 s.addSpecificMetadata(e, m) 37 if ent, ok := e.(*entity.Ent); ok { 38 s.addSpecificMetadata(ent.Behaviour(), m) 39 } 40 return m 41 } 42 43 func (s *Session) addSpecificMetadata(e any, m protocol.EntityMetadata) { 44 if sn, ok := e.(sneaker); ok && sn.Sneaking() { 45 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagSneaking) 46 } 47 if sp, ok := e.(sprinter); ok && sp.Sprinting() { 48 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagSprinting) 49 } 50 if sw, ok := e.(swimmer); ok && sw.Swimming() { 51 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagSwimming) 52 } 53 if gl, ok := e.(glider); ok && gl.Gliding() { 54 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagGliding) 55 } 56 if b, ok := e.(breather); ok { 57 m[protocol.EntityDataKeyAirSupply] = int16(b.AirSupply().Milliseconds() / 50) 58 m[protocol.EntityDataKeyAirSupplyMax] = int16(b.MaxAirSupply().Milliseconds() / 50) 59 if b.Breathing() { 60 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagBreathing) 61 } 62 } 63 if i, ok := e.(invisible); ok && i.Invisible() { 64 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagInvisible) 65 } 66 if i, ok := e.(immobile); ok && i.Immobile() { 67 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagNoAI) 68 } 69 if o, ok := e.(onFire); ok && o.OnFireDuration() > 0 { 70 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagOnFire) 71 } 72 if u, ok := e.(using); ok && u.UsingItem() { 73 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagUsingItem) 74 } 75 if c, ok := e.(arrow); ok && c.Critical() { 76 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagCritical) 77 } 78 if g, ok := e.(gameMode); ok { 79 if g.GameMode().HasCollision() { 80 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagHasCollision) 81 } 82 if !g.GameMode().Visible() { 83 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagInvisible) 84 } 85 } 86 if o, ok := e.(orb); ok { 87 m[protocol.EntityDataKeyValue] = int32(o.Experience()) 88 } 89 if f, ok := e.(firework); ok { 90 m[protocol.EntityDataKeyDisplayTileRuntimeID] = nbtconv.WriteItem(item.NewStack(f.Firework(), 1), false) 91 if o, ok := e.(owned); ok && f.Attached() { 92 m[protocol.EntityDataKeyCustomDisplay] = int64(s.entityRuntimeID(o.Owner())) 93 } 94 } else if o, ok := e.(owned); ok { 95 m[protocol.EntityDataKeyOwner] = int64(s.entityRuntimeID(o.Owner())) 96 } 97 if sc, ok := e.(scaled); ok { 98 m[protocol.EntityDataKeyScale] = float32(sc.Scale()) 99 } 100 if t, ok := e.(tnt); ok { 101 m[protocol.EntityDataKeyFuseTime] = int32(t.Fuse().Milliseconds() / 50) 102 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagIgnited) 103 } 104 if n, ok := e.(named); ok { 105 m[protocol.EntityDataKeyName] = n.NameTag() 106 m[protocol.EntityDataKeyAlwaysShowNameTag] = uint8(1) 107 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagAlwaysShowName) 108 m.SetFlag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagShowName) 109 } 110 if sc, ok := e.(scoreTag); ok { 111 m[protocol.EntityDataKeyScore] = sc.ScoreTag() 112 } 113 if c, ok := e.(areaEffectCloud); ok { 114 m[protocol.EntityDataKeyDataRadius] = float32(c.Radius()) 115 116 // We purposely fill these in with invalid values to disable the client-sided shrinking of the cloud. 117 m[protocol.EntityDataKeyDataDuration] = int32(math.MaxInt32) 118 m[protocol.EntityDataKeyDataChangeOnPickup] = float32(math.SmallestNonzeroFloat32) 119 m[protocol.EntityDataKeyDataChangeRate] = float32(math.SmallestNonzeroFloat32) 120 121 colour, am := effect.ResultingColour(c.Effects()) 122 m[protocol.EntityDataKeyEffectColor] = nbtconv.Int32FromRGBA(colour) 123 if am { 124 m[protocol.EntityDataKeyEffectAmbience] = byte(1) 125 } else { 126 m[protocol.EntityDataKeyEffectAmbience] = byte(0) 127 } 128 } 129 if l, ok := e.(living); ok && s.c == e { 130 deathPos, deathDimension, died := l.DeathPosition() 131 if died { 132 dim, _ := world.DimensionID(deathDimension) 133 m[protocol.EntityDataKeyPlayerLastDeathPosition] = vec64To32(deathPos) 134 m[protocol.EntityDataKeyPlayerLastDeathDimension] = int32(dim) 135 } 136 m[protocol.EntityDataKeyPlayerHasDied] = boolByte(died) 137 } 138 if p, ok := e.(splash); ok { 139 m[protocol.EntityDataKeyAuxValueData] = int16(p.Potion().Uint8()) 140 if tip := p.Potion().Uint8(); tip > 4 { 141 m[protocol.EntityDataKeyCustomDisplay] = tip + 1 142 } 143 } 144 if eff, ok := e.(effectBearer); ok && len(eff.Effects()) > 0 { 145 visibleEffects := make([]effect.Effect, 0, len(eff.Effects())) 146 for _, ef := range eff.Effects() { 147 if !ef.ParticlesHidden() { 148 visibleEffects = append(visibleEffects, ef) 149 } 150 } 151 if len(visibleEffects) > 0 { 152 colour, am := effect.ResultingColour(visibleEffects) 153 m[protocol.EntityDataKeyEffectColor] = nbtconv.Int32FromRGBA(colour) 154 if am { 155 m[protocol.EntityDataKeyEffectAmbience] = byte(1) 156 } else { 157 m[protocol.EntityDataKeyEffectAmbience] = byte(0) 158 } 159 } 160 } 161 if v, ok := e.(variable); ok { 162 m[protocol.EntityDataKeyVariant] = v.Variant() 163 } 164 if mv, ok := e.(markVariable); ok { 165 m[protocol.EntityDataKeyMarkVariant] = mv.MarkVariant() 166 } 167 } 168 169 type sneaker interface { 170 Sneaking() bool 171 } 172 173 type sprinter interface { 174 Sprinting() bool 175 } 176 177 type swimmer interface { 178 Swimming() bool 179 } 180 181 type glider interface { 182 Gliding() bool 183 } 184 185 type breather interface { 186 Breathing() bool 187 AirSupply() time.Duration 188 MaxAirSupply() time.Duration 189 } 190 191 type immobile interface { 192 Immobile() bool 193 } 194 195 type invisible interface { 196 Invisible() bool 197 } 198 199 type scaled interface { 200 Scale() float64 201 } 202 203 type owned interface { 204 Owner() world.Entity 205 } 206 207 type named interface { 208 NameTag() string 209 } 210 211 type scoreTag interface { 212 ScoreTag() string 213 } 214 215 type splash interface { 216 Potion() potion.Potion 217 } 218 219 type glint interface { 220 Glint() bool 221 } 222 223 type areaEffectCloud interface { 224 effectBearer 225 Radius() float64 226 } 227 228 type onFire interface { 229 OnFireDuration() time.Duration 230 } 231 232 type effectBearer interface { 233 Effects() []effect.Effect 234 } 235 236 type using interface { 237 UsingItem() bool 238 } 239 240 type arrow interface { 241 Critical() bool 242 } 243 244 type orb interface { 245 Experience() int 246 } 247 248 type firework interface { 249 Firework() item.Firework 250 Attached() bool 251 } 252 253 type gameMode interface { 254 GameMode() world.GameMode 255 } 256 257 type tnt interface { 258 Fuse() time.Duration 259 } 260 261 type living interface { 262 DeathPosition() (mgl64.Vec3, world.Dimension, bool) 263 } 264 265 type variable interface { 266 Variant() int32 267 } 268 269 type markVariable interface { 270 MarkVariant() int32 271 }