Skip to content

Commit

Permalink
item/stack.go: Add new WithItem method to replace session/handler_cra…
Browse files Browse the repository at this point in the history
…fting.go duplicateStack function.
  • Loading branch information
Sandertv committed Dec 24, 2024
1 parent 689724a commit 055377b
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 45 deletions.
46 changes: 20 additions & 26 deletions server/item/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package item

import (
"fmt"
"maps"
"reflect"
"slices"
"sort"
Expand Down Expand Up @@ -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 {
Expand All @@ -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.
Expand All @@ -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)
}
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
}
4 changes: 2 additions & 2 deletions server/session/handler_book_edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
14 changes: 0 additions & 14 deletions server/session/handler_crafting.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion server/session/handler_loom.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
4 changes: 2 additions & 2 deletions server/session/handler_smithing.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
}

0 comments on commit 055377b

Please sign in to comment.