github.com/df-mc/dragonfly@v0.9.13/server/internal/iteminternal/components.go (about) 1 package iteminternal 2 3 import ( 4 "github.com/df-mc/dragonfly/server/item" 5 "github.com/df-mc/dragonfly/server/world" 6 "strings" 7 ) 8 9 // Components returns all the components of the given custom item. If the item has no components, a nil map and false 10 // are returned. 11 func Components(it world.CustomItem) map[string]any { 12 category := it.Category() 13 identifier, _ := it.EncodeItem() 14 name := strings.Split(identifier, ":")[1] 15 16 builder := NewComponentBuilder(it.Name(), identifier, category) 17 18 if x, ok := it.(item.Armour); ok { 19 builder.AddComponent("minecraft:armor", map[string]any{ 20 "protection": int32(x.DefencePoints()), 21 }) 22 23 var slot string 24 switch it.(type) { 25 case item.HelmetType: 26 slot = "slot.armor.head" 27 case item.ChestplateType: 28 slot = "slot.armor.chest" 29 case item.LeggingsType: 30 slot = "slot.armor.legs" 31 case item.BootsType: 32 slot = "slot.armor.feet" 33 } 34 builder.AddComponent("minecraft:wearable", map[string]any{ 35 "slot": slot, 36 }) 37 } 38 if x, ok := it.(item.Consumable); ok { 39 builder.AddProperty("use_duration", int32(x.ConsumeDuration().Seconds()*20)) 40 builder.AddComponent("minecraft:food", map[string]any{ 41 "can_always_eat": x.AlwaysConsumable(), 42 }) 43 44 if y, ok := it.(item.Drinkable); ok && y.Drinkable() { 45 builder.AddProperty("use_animation", int32(2)) 46 } else { 47 builder.AddProperty("use_animation", int32(1)) 48 } 49 } 50 if x, ok := it.(item.Cooldown); ok { 51 builder.AddComponent("minecraft:cooldown", map[string]any{ 52 "category": name, 53 "duration": float32(x.Cooldown().Seconds()), 54 }) 55 } 56 if x, ok := it.(item.Durable); ok { 57 builder.AddComponent("minecraft:durability", map[string]any{ 58 "max_durability": int32(x.DurabilityInfo().MaxDurability), 59 }) 60 } 61 if x, ok := it.(item.MaxCounter); ok { 62 builder.AddProperty("max_stack_size", int32(x.MaxCount())) 63 } 64 if x, ok := it.(item.OffHand); ok { 65 builder.AddProperty("allow_off_hand", x.OffHand()) 66 } 67 if x, ok := it.(item.Throwable); ok { 68 // The data in minecraft:projectile is only used by vanilla server-side, but we must send at least an empty map 69 // so the client will play the throwing animation. 70 builder.AddComponent("minecraft:projectile", map[string]any{}) 71 builder.AddComponent("minecraft:throwable", map[string]any{ 72 "do_swing_animation": x.SwingAnimation(), 73 }) 74 } 75 if x, ok := it.(item.Glinted); ok { 76 builder.AddProperty("foil", x.Glinted()) 77 } 78 if x, ok := it.(item.HandEquipped); ok { 79 builder.AddProperty("hand_equipped", x.HandEquipped()) 80 } 81 itemScale := calculateItemScale(it) 82 builder.AddComponent("minecraft:render_offsets", map[string]any{ 83 "main_hand": map[string]any{ 84 "first_person": map[string]any{ 85 "scale": itemScale, 86 }, 87 "third_person": map[string]any{ 88 "scale": itemScale, 89 }, 90 }, 91 "off_hand": map[string]any{ 92 "first_person": map[string]any{ 93 "scale": itemScale, 94 }, 95 "third_person": map[string]any{ 96 "scale": itemScale, 97 }, 98 }, 99 }) 100 101 return builder.Construct() 102 } 103 104 // calculateItemScale calculates the scale of the item to be rendered to the player according to the given size. 105 func calculateItemScale(it world.CustomItem) []float32 { 106 width := float32(it.Texture().Bounds().Dx()) 107 height := float32(it.Texture().Bounds().Dy()) 108 var x, y, z float32 = 0.1, 0.1, 0.1 109 if _, ok := it.(item.HandEquipped); ok { 110 x, y, z = 0.075, 0.125, 0.075 111 } 112 newX := x / (width / 16) 113 newY := y / (height / 16) 114 newZ := z / (width / 16) 115 return []float32{newX, newY, newZ} 116 }