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  }