86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
package feature
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
"slices"
|
|
|
|
"bd2server/internal/server/gamedata"
|
|
"bd2server/internal/server/player"
|
|
"bd2server/internal/server/wire"
|
|
)
|
|
|
|
type RecipeItems interface{ All() []player.Item }
|
|
|
|
type RecipeService struct {
|
|
design *gamedata.CookingRecipeDesign
|
|
initial []uint64
|
|
items RecipeItems
|
|
}
|
|
|
|
func (s *RecipeService) Knows(id uint64) bool {
|
|
if !s.design.IDs[id] {
|
|
return false
|
|
}
|
|
if slices.Contains(s.initial, id) {
|
|
return true
|
|
}
|
|
for _, item := range s.items.All() {
|
|
if item.Type == 7 && item.ID == id && item.Count > 0 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func NewRecipeService(design *gamedata.CookingRecipeDesign, initial []uint64, items RecipeItems) (*RecipeService, error) {
|
|
if design == nil || len(design.IDs) == 0 || items == nil {
|
|
return nil, fmt.Errorf("recipes: missing design or inventory")
|
|
}
|
|
for _, id := range initial {
|
|
if !design.IDs[id] {
|
|
return nil, fmt.Errorf("recipes: initial recipe %d is absent from GameData", id)
|
|
}
|
|
}
|
|
return &RecipeService{design: design, initial: append([]uint64(nil), initial...), items: items}, nil
|
|
}
|
|
|
|
func (s *RecipeService) Handle(path string, request []byte) (int, []byte, bool, error) {
|
|
if path != "/RecipeInfo" {
|
|
return 0, nil, false, nil
|
|
}
|
|
seq, found, err := wire.Varint(request, 1)
|
|
if err != nil || !found || seq == 0 || seq > math.MaxInt32 {
|
|
return 0, nil, true, ErrInvalidRequest
|
|
}
|
|
known := map[uint64]bool{}
|
|
for _, id := range s.initial {
|
|
known[id] = true
|
|
}
|
|
for _, item := range s.items.All() {
|
|
// EElementType.CookingRecipe is protocol value 7. Ownership comes from
|
|
// seed state or real reward grants, never from every row in CookingTable.
|
|
if item.Type != 7 || item.Count == 0 {
|
|
continue
|
|
}
|
|
if !s.design.IDs[item.ID] {
|
|
return 0, nil, true, fmt.Errorf("recipes: owned recipe %d is absent from GameData", item.ID)
|
|
}
|
|
known[item.ID] = true
|
|
}
|
|
ids := make([]uint64, 0, len(known))
|
|
for id := range known {
|
|
ids = append(ids, id)
|
|
}
|
|
slices.Sort(ids)
|
|
var packed []byte
|
|
for _, id := range ids {
|
|
packed = binary.AppendUvarint(packed, id)
|
|
}
|
|
if len(packed) == 0 {
|
|
return 46, nil, true, nil
|
|
}
|
|
return 46, wire.AppendBytes(nil, 2, packed), true, nil
|
|
}
|