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 }