github.com/df-mc/dragonfly@v0.9.13/server/item/item.go (about) 1 package item 2 3 import ( 4 "encoding/binary" 5 "github.com/df-mc/dragonfly/server/block/cube" 6 "github.com/df-mc/dragonfly/server/entity/effect" 7 "github.com/df-mc/dragonfly/server/internal/lang" 8 "github.com/df-mc/dragonfly/server/world" 9 "github.com/go-gl/mathgl/mgl64" 10 "golang.org/x/text/language" 11 "image/color" 12 "time" 13 ) 14 15 // MaxCounter represents an item that has a specific max count. By default, each item will be expected to have 16 // a maximum count of 64. MaxCounter may be implemented to change this behaviour. 17 type MaxCounter interface { 18 // MaxCount returns the maximum number of items that a stack may be composed of. The number returned must 19 // be positive. 20 MaxCount() int 21 } 22 23 // UsableOnBlock represents an item that may be used on a block. If an item implements this interface, the 24 // UseOnBlock method is called whenever the item is used on a block. 25 type UsableOnBlock interface { 26 // UseOnBlock is called when an item is used on a block. The world passed is the world that the item was 27 // used in. The user passed is the entity that used the item. Usually this entity is a player. 28 // The position of the block that was clicked, along with the clicked face and the position clicked 29 // relative to the corner of the block are passed. 30 // UseOnBlock returns a bool indicating if the item was used successfully. 31 UseOnBlock(pos cube.Pos, face cube.Face, clickPos mgl64.Vec3, w *world.World, user User, ctx *UseContext) bool 32 } 33 34 // UsableOnEntity represents an item that may be used on an entity. If an item implements this interface, the 35 // UseOnEntity method is called whenever the item is used on an entity. 36 type UsableOnEntity interface { 37 // UseOnEntity is called when an item is used on an entity. The world passed is the world that the item is 38 // used in, and the entity clicked and the user of the item are also passed. 39 // UseOnEntity returns a bool indicating if the item was used successfully. 40 UseOnEntity(e world.Entity, w *world.World, user User, ctx *UseContext) bool 41 } 42 43 // Usable represents an item that may be used 'in the air'. If an item implements this interface, the Use 44 // method is called whenever the item is used while pointing at the air. (For example, when throwing an egg.) 45 type Usable interface { 46 // Use is called when the item is used in the air. The user that used the item and the world that the item 47 // was used in are passed to the method. 48 // Use returns a bool indicating if the item was used successfully. 49 Use(w *world.World, user User, ctx *UseContext) bool 50 } 51 52 // Throwable represents a custom item that can be thrown such as a projectile. This will only have an effect on 53 // non-vanilla items. 54 type Throwable interface { 55 // SwingAnimation returns true if the client should cause the player's arm to swing when the item is thrown. 56 SwingAnimation() bool 57 } 58 59 // OffHand represents an item that can be held in the off hand. 60 type OffHand interface { 61 // OffHand returns true if the item can be held in the off hand. 62 OffHand() bool 63 } 64 65 // Consumable represents an item that may be consumed by a player. If an item implements this interface, a player 66 // may use and hold the item to consume it. 67 type Consumable interface { 68 // AlwaysConsumable specifies if the item is always consumable. Normal food can generally only be consumed 69 // when the food bar is not full or when in creative mode. Returning true here means the item can always 70 // be consumed, like golden apples or potions. 71 AlwaysConsumable() bool 72 // ConsumeDuration is the duration consuming the item takes. If the player is using the item for at least 73 // this duration, the item will be consumed and have its Consume method called. 74 ConsumeDuration() time.Duration 75 // Consume consumes one item of the Stack that the Consumable is in. The Stack returned is added back to 76 // the inventory after consuming the item. For potions, for example, an empty bottle is returned. 77 Consume(w *world.World, c Consumer) Stack 78 } 79 80 // Consumer represents a User that is able to consume Consumable items. 81 type Consumer interface { 82 User 83 // Saturate saturates the Consumer's food bar by the amount of food points passed and the saturation by 84 // up to as many saturation points as passed. The final saturation will never exceed the final food level. 85 Saturate(food int, saturation float64) 86 // AddEffect adds an effect.Effect to the Consumer. If the effect is instant, it is applied to the Consumer 87 // immediately. If not, the effect is applied to the consumer every time the Tick method is called. 88 // AddEffect will overwrite any effects present if the level of the effect is higher than the existing one, or 89 // if the effects' levels are equal and the new effect has a longer duration. 90 AddEffect(e effect.Effect) 91 // RemoveEffect removes any effect that might currently be active on the Consumer. 92 RemoveEffect(e effect.Type) 93 // Effects returns any effect currently applied to the Consumer. The returned effects are guaranteed not to have 94 // expired when returned. 95 Effects() []effect.Effect 96 } 97 98 // DefaultConsumeDuration is the default duration that consuming an item takes. Dried kelp takes half this 99 // time to be consumed. 100 const DefaultConsumeDuration = (time.Second * 161) / 100 101 102 // Drinkable represents a custom item that can be drunk. It is used to make the client show the correct drinking 103 // animation when a player is using an item. This will only have an effect on non-vanilla items. 104 type Drinkable interface { 105 // Drinkable returns if the item can be drunk or not. 106 Drinkable() bool 107 } 108 109 // Glinted represents a custom item that can have a permanent enchantment glint, this glint is purely cosmetic and 110 // will show regardless of whether it is actually enchanted. An example of this is the enchanted golden apple. 111 type Glinted interface { 112 // Glinted returns whether the item has an enchantment glint. 113 Glinted() bool 114 } 115 116 // HandEquipped represents an item that can be 'hand equipped'. This means the item will show up in third person like 117 // a tool, sword or stick would, giving them a different orientation in the hand and making them slightly bigger. 118 type HandEquipped interface { 119 // HandEquipped returns whether the item is hand equipped. 120 HandEquipped() bool 121 } 122 123 // Weapon is an item that may be used as a weapon. It has an attack damage which may be different to the 2 124 // damage that attacking with an empty hand deals. 125 type Weapon interface { 126 // AttackDamage returns the custom attack damage to the weapon. The damage returned must not be negative. 127 AttackDamage() float64 128 } 129 130 // Cooldown represents an item that has a cooldown. 131 type Cooldown interface { 132 // Cooldown is the duration of the cooldown. 133 Cooldown() time.Duration 134 } 135 136 // nameable represents a block that may be named. These are often containers such as chests, which have a 137 // name displayed in their interface. 138 type nameable interface { 139 // WithName returns the block itself, except with a custom name applied to it. 140 WithName(a ...any) world.Item 141 } 142 143 // Releaser represents an entity that can release items, such as bows. 144 type Releaser interface { 145 User 146 // GameMode returns the gamemode of the releaser. 147 GameMode() world.GameMode 148 // PlaySound plays a world.Sound that only this Releaser can hear. 149 PlaySound(sound world.Sound) 150 } 151 152 // Releasable represents an item that can be released. 153 type Releasable interface { 154 // Release is called when an item is released. 155 Release(releaser Releaser, duration time.Duration, ctx *UseContext) 156 // Requirements returns the required items to release this item. 157 Requirements() []Stack 158 } 159 160 // User represents an entity that is able to use an item in the world, typically entities such as players, 161 // which interact with the world using an item. 162 type User interface { 163 Carrier 164 SetHeldItems(mainHand, offHand Stack) 165 166 UsingItem() bool 167 ReleaseItem() 168 UseItem() 169 } 170 171 // Carrier represents an entity that is able to carry an item. 172 type Carrier interface { 173 world.Entity 174 // HeldItems returns the items currently held by the entity. Viewers of the entity will be able to see 175 // these items. 176 HeldItems() (mainHand, offHand Stack) 177 } 178 179 // BeaconPayment represents an item that may be used as payment for a beacon to select effects to be broadcast 180 // to surrounding players. 181 type BeaconPayment interface { 182 PayableForBeacon() bool 183 } 184 185 // Compostable represents an item that may be used to fill up a composter. 186 type Compostable interface { 187 // CompostChance returns the chance the item will produce a layer of compost in the range of 0-1. 188 CompostChance() float64 189 } 190 191 // nopReleasable represents a releasable item that does nothing. 192 type nopReleasable struct{} 193 194 func (nopReleasable) Release(Releaser, time.Duration, *UseContext) {} 195 func (nopReleasable) Requirements() []Stack { 196 return []Stack{} 197 } 198 199 // defaultFood represents a consumable item with a default consumption duration. 200 type defaultFood struct{} 201 202 // AlwaysConsumable ... 203 func (defaultFood) AlwaysConsumable() bool { 204 return false 205 } 206 207 // ConsumeDuration ... 208 func (d defaultFood) ConsumeDuration() time.Duration { 209 return DefaultConsumeDuration 210 } 211 212 // DisplayName returns the display name of the item as shown in game in the language passed. It panics if an unknown 213 // item is passed in. 214 func DisplayName(item world.Item, locale language.Tag) string { 215 if c, ok := item.(world.CustomItem); ok { 216 return c.Name() 217 } 218 name, ok := lang.DisplayName(item, locale) 219 if !ok { 220 panic("should never happen") 221 } 222 return name 223 } 224 225 // eyePosition returns the position of the eyes of the entity if the entity implements entity.Eyed, or the 226 // actual position if it doesn't. 227 func eyePosition(e world.Entity) mgl64.Vec3 { 228 pos := e.Position() 229 if eyed, ok := e.(interface{ EyeHeight() float64 }); ok { 230 pos = pos.Add(mgl64.Vec3{0, eyed.EyeHeight()}) 231 } 232 return pos 233 } 234 235 // Int32FromRGBA converts a color.RGBA into an int32. These int32s are present in things such as signs and dyed leather armour. 236 func int32FromRGBA(x color.RGBA) int32 { 237 if x.R == 0 && x.G == 0 && x.B == 0 { 238 // Default to black colour. The default (0x000000) is a transparent colour. Text with this colour will not show 239 // up on the sign. 240 return int32(-0x1000000) 241 } 242 return int32(binary.BigEndian.Uint32([]byte{x.A, x.R, x.G, x.B})) 243 } 244 245 // rgbaFromInt32 converts an int32 into a color.RGBA. These int32s are present in things such as signs and dyed leather armour. 246 func rgbaFromInt32(x int32) color.RGBA { 247 b := make([]byte, 4) 248 binary.BigEndian.PutUint32(b, uint32(x)) 249 250 return color.RGBA{A: b[0], R: b[1], G: b[2], B: b[3]} 251 } 252 253 // boolByte returns 1 if the bool passed is true, or 0 if it is false. 254 func boolByte(b bool) uint8 { 255 if b { 256 return 1 257 } 258 return 0 259 }