github.com/df-mc/dragonfly@v0.9.13/server/player/hunger.go (about) 1 package player 2 3 import ( 4 "sync" 5 ) 6 7 // hungerManager handles the changes in hunger, exhaustion and saturation of a player. 8 type hungerManager struct { 9 mu sync.RWMutex 10 foodLevel int 11 saturationLevel float64 12 exhaustionLevel float64 13 foodTick int 14 } 15 16 // newHungerManager returns a new hunger manager with the default values for food level, saturation level and 17 // exhaustion level. 18 func newHungerManager() *hungerManager { 19 return &hungerManager{foodLevel: 20, saturationLevel: 5} 20 } 21 22 // Food returns the current food level of a player. The level returned is guaranteed to always be between 0 23 // and 20. 24 func (m *hungerManager) Food() int { 25 m.mu.RLock() 26 defer m.mu.RUnlock() 27 return m.foodLevel 28 } 29 30 // SetFood sets the food level of a player. The level passed must be in a range of 0-20. If the level passed 31 // is negative, the food level will be set to 0. If the level exceeds 20, the food level will be set to 20. 32 func (m *hungerManager) SetFood(level int) { 33 if level < 0 { 34 level = 0 35 } else if level > 20 { 36 level = 20 37 } 38 m.mu.Lock() 39 defer m.mu.Unlock() 40 m.foodLevel = level 41 } 42 43 // AddFood adds a number of food points to the current food level of a player. 44 func (m *hungerManager) AddFood(points int) { 45 m.mu.Lock() 46 defer m.mu.Unlock() 47 48 level := m.foodLevel + points 49 if level < 0 { 50 level = 0 51 } else if level > 20 { 52 level = 20 53 } 54 m.foodLevel = level 55 } 56 57 // Reset resets the hunger manager to its default values, identical to those set when creating a new manager 58 // using newHungerManager. 59 func (m *hungerManager) Reset() { 60 m.mu.Lock() 61 m.foodLevel = 20 62 m.saturationLevel = 5 63 m.exhaustionLevel = 0 64 m.foodTick = 0 65 m.mu.Unlock() 66 } 67 68 // exhaust exhausts the player by the amount of points passed. If the total exhaustion level exceeds 4, a 69 // saturation point, or food point, if saturation is 0, will be subtracted. 70 func (m *hungerManager) exhaust(points float64) { 71 m.mu.Lock() 72 defer m.mu.Unlock() 73 74 m.exhaustionLevel += points 75 for { 76 if m.exhaustionLevel < 4 { 77 break 78 } 79 // Maximum exhaustion value is 4, so keep removing one saturation point until the exhaustion level 80 // is below 4. 81 m.exhaustionLevel -= 4 82 m.desaturate() 83 } 84 } 85 86 // saturate saturates the player's food and saturation by the amount of points passed. Note that the total 87 // saturation will never exceed the total food value. 88 func (m *hungerManager) saturate(food int, saturation float64) { 89 m.mu.Lock() 90 91 level := m.foodLevel + food 92 if level < 0 { 93 level = 0 94 } else if level > 20 { 95 level = 20 96 } 97 m.foodLevel = level 98 99 sat := m.saturationLevel + saturation 100 if sat < 0 { 101 sat = 0 102 } else if sat > 20 { 103 sat = 20 104 } 105 if sat > float64(m.foodLevel) { 106 sat = float64(m.foodLevel) 107 } 108 m.saturationLevel = sat 109 m.mu.Unlock() 110 } 111 112 // desaturate removes one saturation point from the player. If the saturation level of the player is already 113 // 0, a point will be subtracted from the food level instead. If that level, too, is already 0, nothing will 114 // happen. 115 func (m *hungerManager) desaturate() { 116 if m.saturationLevel <= 0 && m.foodLevel != 0 { 117 m.foodLevel-- 118 } else if m.saturationLevel > 0 { 119 m.saturationLevel-- 120 if m.saturationLevel < 0 { 121 // Some foods provide saturation with decimals, so we have to account for an overcompensation. 122 m.saturationLevel = 0 123 } 124 } 125 } 126 127 // canQuicklyRegenerate checks if the player can quickly regenerate. The function returns true if Food() returns 20 128 // and the player still has saturation left. 129 // The rate of regeneration is 1/0.5 seconds. 130 func (m *hungerManager) canQuicklyRegenerate() bool { 131 m.mu.RLock() 132 defer m.mu.RUnlock() 133 134 return m.foodLevel == 20 && m.saturationLevel > 0 135 } 136 137 // canRegenerate checks if the player with the amount of food levels in the hunger manager can regenerate. 138 // The function returns true if Food() returns either 18-20. 139 // The rate of regeneration is 1/4 seconds. 140 func (m *hungerManager) canRegenerate() bool { 141 return m.Food() >= 18 142 } 143 144 // canSprint returns true if the food level of the player is 7 or higher. 145 func (m *hungerManager) canSprint() bool { 146 return m.Food() > 6 147 } 148 149 // starving checks if the player is currently considered to be starving. True is returned if Food() returns 0. 150 func (m *hungerManager) starving() bool { 151 return m.Food() == 0 152 } 153 154 // StarvationDamageSource is the world.DamageSource passed when a player is 155 // dealt damage from an empty food bar. 156 type StarvationDamageSource struct{} 157 158 func (StarvationDamageSource) ReducedByArmour() bool { return false } 159 func (StarvationDamageSource) ReducedByResistance() bool { return false } 160 func (StarvationDamageSource) Fire() bool { return false }