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

     1  package creative
     2  
     3  import (
     4  	_ "embed"
     5  	"github.com/df-mc/dragonfly/server/internal/nbtconv"
     6  	// The following three imports are essential for this package: They make sure this package is loaded after
     7  	// all these imports. This ensures that all items are registered before the creative items are registered
     8  	// in the init function in this package.
     9  	"github.com/df-mc/dragonfly/server/item"
    10  	"github.com/df-mc/dragonfly/server/world"
    11  	"github.com/sandertv/gophertunnel/minecraft/nbt"
    12  )
    13  
    14  // Items returns a list with all items that have been registered as a creative item. These items will
    15  // be accessible by players in-game who have creative mode enabled.
    16  func Items() []item.Stack {
    17  	return creativeItemStacks
    18  }
    19  
    20  // RegisterItem registers an item as a creative item, exposing it in the creative inventory.
    21  func RegisterItem(item item.Stack) {
    22  	creativeItemStacks = append(creativeItemStacks, item)
    23  }
    24  
    25  var (
    26  	//go:embed creative_items.nbt
    27  	creativeItemData []byte
    28  	// creativeItemStacks holds a list of all item stacks that were registered to the creative inventory using
    29  	// RegisterItem.
    30  	creativeItemStacks []item.Stack
    31  )
    32  
    33  // creativeItemEntry holds data of a creative item as present in the creative inventory.
    34  type creativeItemEntry struct {
    35  	Name            string         `nbt:"name"`
    36  	Meta            int16          `nbt:"meta"`
    37  	NBT             map[string]any `nbt:"nbt,omitempty"`
    38  	BlockProperties map[string]any `nbt:"block_properties,omitempty"`
    39  }
    40  
    41  // init initialises the creative items, registering all creative items that have also been registered as
    42  // normal items and are present in vanilla.
    43  func init() {
    44  	var m []creativeItemEntry
    45  	if err := nbt.Unmarshal(creativeItemData, &m); err != nil {
    46  		panic(err)
    47  	}
    48  	for _, data := range m {
    49  		var (
    50  			it world.Item
    51  			ok bool
    52  		)
    53  		if len(data.BlockProperties) > 0 {
    54  			// Item with a block, try parsing the block, then try asserting that to an item. Blocks no longer
    55  			// have their metadata sent, but we still need to get that metadata in order to be able to register
    56  			// different block states as different items.
    57  			if b, ok := world.BlockByName(data.Name, data.BlockProperties); ok {
    58  				if it, ok = b.(world.Item); !ok {
    59  					continue
    60  				}
    61  			}
    62  		} else {
    63  			if it, ok = world.ItemByName(data.Name, data.Meta); !ok {
    64  				// The item wasn't registered, so don't register it as a creative item.
    65  				continue
    66  			}
    67  			if _, resultingMeta := it.EncodeItem(); resultingMeta != data.Meta {
    68  				// We found an item registered with that ID and a meta of 0, but we only need items with strictly
    69  				// the same meta here.
    70  				continue
    71  			}
    72  		}
    73  
    74  		if n, ok := it.(world.NBTer); ok {
    75  			if len(data.NBT) > 0 {
    76  				it = n.DecodeNBT(data.NBT).(world.Item)
    77  			}
    78  		}
    79  
    80  		st := item.NewStack(it, 1)
    81  		if len(data.NBT) > 0 {
    82  			var invalid bool
    83  			for _, e := range nbtconv.Slice(data.NBT, "ench") {
    84  				if v, ok := e.(map[string]any); ok {
    85  					t, ok := item.EnchantmentByID(int(nbtconv.Int16(v, "id")))
    86  					if !ok {
    87  						invalid = true
    88  						break
    89  					}
    90  					st = st.WithEnchantments(item.NewEnchantment(t, int(nbtconv.Int16(v, "lvl"))))
    91  				}
    92  			}
    93  			if invalid {
    94  				// Invalid enchantment, skip this item.
    95  				continue
    96  			}
    97  		}
    98  		RegisterItem(st)
    99  	}
   100  }