Implement hunting AP and progress, event tasks, exchanges, games, stories and actions; connect battle and reward handling. Add CashShop plugin and installation, server purchases and entitlements, recharge rules and plugin version metadata. Distribute binary calendars independently; cache GameData in memory and fix single-connection query deadlocks. Improve automatic login and recovery diagnostics; document configuration and release flows.
77 lines
2.0 KiB
Go
77 lines
2.0 KiB
Go
package player
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
// GrantCommerceOnce preserves the exact item expiry supplied by the commerce
|
|
// entitlement policy. It shares the existing atomic inventory layout.
|
|
func (s *Inventory) GrantCommerceOnce(identity string, rewards []Item) ([]Item, error) {
|
|
if identity == "" {
|
|
return nil, fmt.Errorf("player: missing commerce reward identity")
|
|
}
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.owned.Granted[identity] {
|
|
var out []Item
|
|
for _, idx := range s.owned.GrantItems[identity] {
|
|
for _, item := range s.owned.Items {
|
|
if item.InvenIndex == idx {
|
|
out = append(out, item)
|
|
}
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
next := cloneOwnedSnapshot(s.owned)
|
|
var out []Item
|
|
for _, r := range rewards {
|
|
if r.ID == 0 || (r.Type != 62 && r.Type != 19) || r.Count == 0 || r.Count > math.MaxInt32 || r.Type == 19 && r.ExpiryTime == 0 || next.NextIndex == math.MaxUint64 {
|
|
return nil, fmt.Errorf("player: invalid commerce item")
|
|
}
|
|
if r.Type == 19 {
|
|
found := false
|
|
for i, current := range next.Items {
|
|
if current.Type == 19 && current.ID == r.ID {
|
|
r.InvenIndex = current.InvenIndex
|
|
r.Count = 1
|
|
next.Items[i] = r
|
|
next.GrantItems[identity] = append(next.GrantItems[identity], r.InvenIndex)
|
|
out = append(out, r)
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if found {
|
|
continue
|
|
}
|
|
r.Count = 1
|
|
}
|
|
r.InvenIndex = next.NextIndex
|
|
next.NextIndex++
|
|
next.Items = append(next.Items, r)
|
|
next.GrantItems[identity] = append(next.GrantItems[identity], r.InvenIndex)
|
|
out = append(out, r)
|
|
}
|
|
next.Granted[identity] = true
|
|
if err := s.commitOwned(next); err != nil {
|
|
return nil, err
|
|
}
|
|
s.owned = next
|
|
return out, nil
|
|
}
|
|
func (s *Inventory) ContentTicketExpiry(id uint64) uint64 {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
var expiry uint64
|
|
for _, items := range [][]Item{s.starter.Items, s.owned.Items} {
|
|
for _, i := range items {
|
|
if i.Type == 19 && i.ID == id && i.Count > 0 && i.ExpiryTime > expiry {
|
|
expiry = i.ExpiryTime
|
|
}
|
|
}
|
|
}
|
|
return expiry
|
|
}
|