From 055377bd3af2a818e2d4ce8f72609ba8f2caccf2 Mon Sep 17 00:00:00 2001 From: Sandertv Date: Tue, 24 Dec 2024 13:46:20 +0100 Subject: [PATCH] item/stack.go: Add new WithItem method to replace session/handler_crafting.go duplicateStack function. --- server/item/stack.go | 46 +++++++++++++---------------- server/session/handler_book_edit.go | 4 +-- server/session/handler_crafting.go | 14 --------- server/session/handler_loom.go | 2 +- server/session/handler_smithing.go | 4 +-- 5 files changed, 25 insertions(+), 45 deletions(-) diff --git a/server/item/stack.go b/server/item/stack.go index b399f998a..ee1681172 100644 --- a/server/item/stack.go +++ b/server/item/stack.go @@ -2,6 +2,7 @@ package item import ( "fmt" + "maps" "reflect" "slices" "sort" @@ -210,7 +211,7 @@ func (s Stack) Lore() []string { // WithValue stores Values by encoding them using the encoding/gob package. Users of WithValue must ensure // that their value is valid for encoding with this package. func (s Stack) WithValue(key string, val any) Stack { - s.data = copyMap(s.data) + s.data = maps.Clone(s.data) if val != nil { s.data[key] = val } else { @@ -232,7 +233,7 @@ func (s Stack) WithEnchantments(enchants ...Enchantment) Stack { if _, ok := s.item.(Book); ok { s.item = EnchantedBook{} } - s.enchantments = copyEnchantments(s.enchantments) + s.enchantments = maps.Clone(s.enchantments) for _, enchant := range enchants { if _, ok := s.Item().(EnchantedBook); !ok && !enchant.t.CompatibleWithItem(s.item) { // Enchantment is not compatible with the item. @@ -245,7 +246,7 @@ func (s Stack) WithEnchantments(enchants ...Enchantment) Stack { // WithoutEnchantments returns the current stack but with the passed enchantments removed. func (s Stack) WithoutEnchantments(enchants ...EnchantmentType) Stack { - s.enchantments = copyEnchantments(s.enchantments) + s.enchantments = maps.Clone(s.enchantments) for _, enchant := range enchants { delete(s.enchantments, enchant) } @@ -265,10 +266,7 @@ func (s Stack) Enchantment(enchant EnchantmentType) (Enchantment, bool) { // Enchantments returns an array of all Enchantments on the item. Enchantments returns the enchantments of a Stack in a // deterministic order. func (s Stack) Enchantments() []Enchantment { - e := make([]Enchantment, 0, len(s.enchantments)) - for _, ench := range s.enchantments { - e = append(e, ench) - } + e := slices.Collect(maps.Values(s.enchantments)) sort.Slice(e, func(i, j int) bool { id1, _ := EnchantmentID(e[i].t) id2, _ := EnchantmentID(e[j].t) @@ -296,6 +294,20 @@ func (s Stack) WithAnvilCost(anvilCost int) Stack { return s } +// WithItem returns a Stack with the item type passed, copying all the +// properties from s to the new stack. Damage to an item, enchantments and anvil +// costs are only copied if they are still applicable to the new item type. +func (s Stack) WithItem(t world.Item) Stack { + cp := NewStack(t, s.count). + Damage(s.damage). + WithCustomName(s.customName). + WithLore(s.lore...). + WithEnchantments(s.Enchantments()...). + WithAnvilCost(s.anvilCost) + cp.data = s.data + return cp +} + // AddStack adds another stack to the stack and returns both stacks. The first stack returned will have as // many items in it as possible to fit in the stack, according to a max count of either 64 or otherwise as // returned by Item.MaxCount(). The second stack will have the leftover items: It may be empty if the count of @@ -371,7 +383,7 @@ func (s Stack) String() string { // Values returns all values associated with the stack by users. The map returned is a copy of the original: // Modifying it will not modify the item stack. func (s Stack) Values() map[string]any { - return copyMap(s.data) + return maps.Clone(s.data) } // stackID is a counter for unique stack IDs. @@ -398,21 +410,3 @@ func id(s Stack) int32 { func format(a []any) string { return strings.TrimSuffix(fmt.Sprintln(a...), "\n") } - -// copyMap makes a copy of the map passed. It does not recursively copy the map. -func copyMap(m map[string]any) map[string]any { - cp := make(map[string]any, len(m)) - for k, v := range m { - cp[k] = v - } - return cp -} - -// copyEnchantments makes a copy of the enchantments map passed. It does not recursively copy the map. -func copyEnchantments(m map[EnchantmentType]Enchantment) map[EnchantmentType]Enchantment { - cp := make(map[EnchantmentType]Enchantment, len(m)) - for k, v := range m { - cp[k] = v - } - return cp -} diff --git a/server/session/handler_book_edit.go b/server/session/handler_book_edit.go index 6d1577623..31df5e901 100644 --- a/server/session/handler_book_edit.go +++ b/server/session/handler_book_edit.go @@ -68,9 +68,9 @@ func (b BookEditHandler) Handle(p packet.Packet, s *Session, _ *world.Tx, _ Cont } book = book.SwapPages(page, int(pk.SecondaryPageNumber)) case packet.BookActionSign: - _ = s.inv.SetItem(slot, duplicateStack(it, item.WrittenBook{Title: pk.Title, Author: pk.Author, Pages: book.Pages, Generation: item.OriginalGeneration()})) + _ = s.inv.SetItem(slot, it.WithItem(item.WrittenBook{Title: pk.Title, Author: pk.Author, Pages: book.Pages, Generation: item.OriginalGeneration()})) return nil } - _ = s.inv.SetItem(slot, duplicateStack(it, book)) + _ = s.inv.SetItem(slot, it.WithItem(book)) return nil } diff --git a/server/session/handler_crafting.go b/server/session/handler_crafting.go index cfee0a0d2..79c4f43c5 100644 --- a/server/session/handler_crafting.go +++ b/server/session/handler_crafting.go @@ -184,20 +184,6 @@ func (s *Session) craftingOffset() uint32 { return craftingGridSmallOffset } -// duplicateStack duplicates an item.Stack with the new item type given. -func duplicateStack(input item.Stack, newType world.Item) item.Stack { - outputStack := item.NewStack(newType, input.Count()). - Damage(input.MaxDurability() - input.Durability()). - WithCustomName(input.CustomName()). - WithLore(input.Lore()...). - WithEnchantments(input.Enchantments()...). - WithAnvilCost(input.AnvilCost()) - for k, v := range input.Values() { - outputStack = outputStack.WithValue(k, v) - } - return outputStack -} - // matchingStacks returns true if the two stacks are the same in a crafting scenario. func matchingStacks(has, expected recipe.Item) bool { switch expected := expected.(type) { diff --git a/server/session/handler_loom.go b/server/session/handler_loom.go index 179c3eb53..7ad41921a 100644 --- a/server/session/handler_loom.go +++ b/server/session/handler_loom.go @@ -93,5 +93,5 @@ func (h *ItemStackRequestHandler) handleLoomCraft(a *protocol.CraftLoomRecipeSta Container: protocol.FullContainerName{ContainerID: protocol.ContainerLoomDye}, Slot: loomDyeSlot, }, dye.Grow(-timesCrafted), s, tx) - return h.createResults(s, tx, duplicateStack(input, b)) + return h.createResults(s, tx, input.WithItem(b)) } diff --git a/server/session/handler_smithing.go b/server/session/handler_smithing.go index 11fbc1317..e9f26cd88 100644 --- a/server/session/handler_smithing.go +++ b/server/session/handler_smithing.go @@ -85,7 +85,7 @@ func (h *ItemStackRequestHandler) handleSmithing(a *protocol.CraftRecipeStackReq if !ok { return fmt.Errorf("input item is not trimmable") } - return h.createResults(s, tx, duplicateStack(input, trimmable.WithTrim(trim))) + return h.createResults(s, tx, input.WithItem(trimmable.WithTrim(trim))) } - return h.createResults(s, tx, duplicateStack(input, craft.Output()[0].Item())) + return h.createResults(s, tx, input.WithItem(craft.Output()[0].Item())) }