github.com/df-mc/dragonfly@v0.9.13/server/entity/effect.go (about)

     1  package entity
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/df-mc/dragonfly/server/entity/effect"
     6  	"reflect"
     7  	"sync"
     8  )
     9  
    10  // EffectManager manages the effects of an entity. The effect manager will only store effects that last for
    11  // a specific duration. Instant effects are applied instantly and not stored.
    12  type EffectManager struct {
    13  	mu      sync.Mutex
    14  	effects map[reflect.Type]effect.Effect
    15  }
    16  
    17  // NewEffectManager creates and returns a new initialised EffectManager.
    18  func NewEffectManager() *EffectManager {
    19  	return &EffectManager{effects: map[reflect.Type]effect.Effect{}}
    20  }
    21  
    22  // Add adds an effect to the manager. If the effect is instant, it is applied to the Living entity passed
    23  // immediately. If not, the effect is added to the EffectManager and is applied to the entity every time the
    24  // Tick method is called.
    25  // Effect levels of 0 or below will not do anything.
    26  // Effect returns the final effect it added to the entity. That might be the effect passed or an effect with
    27  // a higher level/duration than the one passed. Add panics if the effect has a negative duration or level.
    28  func (m *EffectManager) Add(e effect.Effect, entity Living) effect.Effect {
    29  	lvl, dur := e.Level(), e.Duration()
    30  	if lvl <= 0 {
    31  		panic(fmt.Sprintf("(*EffectManager).Add: effect cannot have level of 0 or below: %v", lvl))
    32  	}
    33  	if dur < 0 {
    34  		panic(fmt.Sprintf("(*EffectManager).Add: effect cannot have negative duration: %v", dur))
    35  	}
    36  	t, ok := e.Type().(effect.LastingType)
    37  	if !ok {
    38  		e.Type().Apply(entity, lvl, 0)
    39  		return e
    40  	}
    41  	typ := reflect.TypeOf(e.Type())
    42  
    43  	m.mu.Lock()
    44  	existing, ok := m.effects[typ]
    45  	if !ok {
    46  		m.effects[typ] = e
    47  		m.mu.Unlock()
    48  
    49  		t.Start(entity, lvl)
    50  		return e
    51  	}
    52  	if existing.Level() > lvl || (existing.Level() == lvl && existing.Duration() > dur) {
    53  		m.mu.Unlock()
    54  		return existing
    55  	}
    56  	m.effects[typ] = e
    57  	m.mu.Unlock()
    58  
    59  	existing.Type().(effect.LastingType).End(entity, existing.Level())
    60  	t.Start(entity, lvl)
    61  	return e
    62  }
    63  
    64  // Remove removes any Effect present in the EffectManager with the type of the effect passed.
    65  func (m *EffectManager) Remove(e effect.Type, entity Living) {
    66  	t := reflect.TypeOf(e)
    67  
    68  	m.mu.Lock()
    69  	existing, ok := m.effects[t]
    70  	delete(m.effects, t)
    71  	m.mu.Unlock()
    72  
    73  	if ok {
    74  		existing.Type().(effect.LastingType).End(entity, existing.Level())
    75  	}
    76  }
    77  
    78  // Effect returns the effect instance and true if the entity has the effect. If not found, it will return an empty
    79  // effect instance and false.
    80  func (m *EffectManager) Effect(e effect.Type) (effect.Effect, bool) {
    81  	m.mu.Lock()
    82  	existing, ok := m.effects[reflect.TypeOf(e)]
    83  	m.mu.Unlock()
    84  	return existing, ok
    85  }
    86  
    87  // Effects returns a list of all effects currently present in the effect manager. This will never include
    88  // effects that have expired.
    89  func (m *EffectManager) Effects() []effect.Effect {
    90  	m.mu.Lock()
    91  	defer m.mu.Unlock()
    92  
    93  	e := make([]effect.Effect, 0, len(m.effects))
    94  	for _, eff := range m.effects {
    95  		e = append(e, eff)
    96  	}
    97  	return e
    98  }
    99  
   100  // Tick ticks the EffectManager, applying all of its effects to the Living entity passed when applicable and
   101  // removing expired effects.
   102  func (m *EffectManager) Tick(entity Living) {
   103  	m.mu.Lock()
   104  	e := make([]effect.Effect, 0, len(m.effects))
   105  	var toEnd []effect.Effect
   106  
   107  	for i, eff := range m.effects {
   108  		if m.expired(eff) {
   109  			delete(m.effects, i)
   110  			toEnd = append(toEnd, eff)
   111  			continue
   112  		}
   113  		eff = eff.TickDuration()
   114  		e = append(e, eff)
   115  		m.effects[i] = eff
   116  	}
   117  	m.mu.Unlock()
   118  
   119  	for _, eff := range e {
   120  		eff.Type().Apply(entity, eff.Level(), eff.Duration())
   121  	}
   122  	for _, eff := range toEnd {
   123  		eff.Type().(effect.LastingType).End(entity, eff.Level())
   124  	}
   125  
   126  	if len(toEnd) > 0 {
   127  		for _, v := range entity.World().Viewers(entity.Position()) {
   128  			v.ViewEntityState(entity)
   129  		}
   130  	}
   131  }
   132  
   133  // expired checks if an Effect has expired.
   134  func (m *EffectManager) expired(e effect.Effect) bool {
   135  	return e.Duration() <= 0
   136  }