fix(server): support dynamic hidden event pack purchase and entry
why the f^^kkkkkk does sh^t AI love writing useless tests so much just to clutter up my repo, looks like I’ll have to find some time to clean this s^^t up later.
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package world
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"bd2server/internal/server/gamedata"
|
||||
"bd2server/internal/server/wire"
|
||||
)
|
||||
|
||||
// EventFieldPackSource binds installed hidden packs to the server's current
|
||||
// calendars. A purchase receipt alone never authorizes an expired event.
|
||||
type EventFieldPackSource interface {
|
||||
ResolveEventFieldPack(int) (gamedata.EventFieldPack, bool, error)
|
||||
ListEventFieldPacks() ([]gamedata.EventFieldPack, error)
|
||||
}
|
||||
|
||||
func (s *Service) AttachEventFieldPacks(source EventFieldPackSource) error {
|
||||
if source == nil {
|
||||
return fmt.Errorf("world: nil event field pack source")
|
||||
}
|
||||
s.eventFieldPacks = source
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) resolveEventFieldPack(id int) (gamedata.EventFieldPack, bool, error) {
|
||||
if s.eventFieldPacks == nil {
|
||||
return gamedata.EventFieldPack{}, false, nil
|
||||
}
|
||||
return s.eventFieldPacks.ResolveEventFieldPack(id)
|
||||
}
|
||||
|
||||
func (s *Service) eventPackPurchased(id int) bool {
|
||||
if s.collection == nil {
|
||||
return false
|
||||
}
|
||||
_, found := s.collection.Grant(packPurchaseIdentity(id))
|
||||
return found
|
||||
}
|
||||
|
||||
func (s *Service) eventPackDBInfo(pack gamedata.EventFieldPack) []byte {
|
||||
row := wire.AppendVarint(nil, 1, uint64(pack.ID))
|
||||
if s.eventPackPurchased(pack.ID) {
|
||||
row = wire.AppendVarint(row, 8, 1)
|
||||
}
|
||||
return row
|
||||
}
|
||||
|
||||
func (s *Service) eventPackInfoRows() ([][]byte, error) {
|
||||
if s.eventFieldPacks == nil {
|
||||
return nil, nil
|
||||
}
|
||||
packs, err := s.eventFieldPacks.ListEventFieldPacks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var rows [][]byte
|
||||
for _, pack := range packs {
|
||||
// PackManager buys a hidden pack only when PackInfo has no row for it.
|
||||
if s.eventPackPurchased(pack.ID) {
|
||||
rows = append(rows, s.eventPackDBInfo(pack))
|
||||
}
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (s *Service) enterEventFieldPack(pack gamedata.EventFieldPack) (int, []byte, bool, error) {
|
||||
if !s.eventPackPurchased(pack.ID) {
|
||||
return 0, nil, true, fmt.Errorf("%w: event pack %d is not purchased", ErrInvalidRequest, pack.ID)
|
||||
}
|
||||
position := pack.InitialPosition
|
||||
if position == "" {
|
||||
return 0, nil, true, fmt.Errorf("world: missing event pack initial position")
|
||||
}
|
||||
if saved, found := s.state.Position(); found && saved.PackID == pack.ID {
|
||||
if !slices.Contains(pack.MapIDs, saved.Position.MapID) {
|
||||
return 0, nil, true, fmt.Errorf("%w: map outside event pack", ErrInvalidRequest)
|
||||
}
|
||||
position = saved.RawJSON
|
||||
}
|
||||
response := wire.AppendString(nil, 4, position)
|
||||
// The common callback dereferences HuntingGroundInfo even in hidden packs.
|
||||
// Use the domain-generated empty/current snapshot; never borrow the outside
|
||||
// map's monsters or story progress.
|
||||
var hunting []byte
|
||||
if s.huntingGround != nil {
|
||||
var err error
|
||||
hunting, err = s.huntingGround.EnsureForPack(pack.ID)
|
||||
if err != nil {
|
||||
return 0, nil, true, err
|
||||
}
|
||||
}
|
||||
response = wire.AppendBytes(response, 12, hunting)
|
||||
// Hidden-pack entry must retain the outside field position: the client
|
||||
// intentionally suppresses SaveUserPosition while playing these packs. The
|
||||
// persistent active pack also stays outside, so relogin cannot be stranded
|
||||
// in a hidden scene after its calendar closes.
|
||||
s.setCurrentPack(pack.ID)
|
||||
return 5, response, true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user