Files
bd2/go/internal/server/eventplay/projection.go
T
Flechazo d8771caef2 feat(all): add hunting and events, commerce and rewards, binary calendars, GameData caching and login diagnostics
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.
2026-10-05 11:50:31 +08:00

163 lines
4.1 KiB
Go

package eventplay
import (
"bd2server/internal/server/wire"
"fmt"
"sort"
"strings"
)
func specializedInfo(st *snapshot, uid uint64, f string) []byte {
var out []byte
if f == "Action" || f == "Survival" || f == "Defense" {
out = wire.AppendVarint(out, 1, uid)
}
for _, r := range st.Records {
if r.UID != uid || r.Family != f {
continue
}
switch f {
case "Sichuan":
v := wire.AppendVarint(nil, 1, uid)
v = wire.AppendVarint(v, 6, r.Best)
out = wire.AppendBytes(out, 1, v)
case "Rhythm":
v := wire.AppendVarint(nil, 1, r.Stage)
v = wire.AppendVarint(v, 2, r.Mode)
v = wire.AppendVarint(v, 3, r.Best)
out = wire.AppendBytes(out, 1, v)
case "Action":
v := wire.AppendVarint(nil, 1, r.Stage)
v = wire.AppendVarint(v, 2, r.Best)
out = wire.AppendBytes(out, 2, v)
case "Hopscotch":
v := wire.AppendVarint(nil, 1, r.Stage)
if r.Best > 0 {
v = wire.AppendVarint(v, 2, 1)
}
out = wire.AppendBytes(out, 2, v)
case "Survival":
out = wire.AppendVarint(out, 4, r.Best)
for stage, clear := range r.Clears {
if !clear {
continue
}
var group, id uint64
if _, e := fmt.Sscanf(stage, "map:%d:%d", &group, &id); e == nil {
v := wire.AppendVarint(nil, 1, group)
v = wire.AppendVarint(v, 2, id)
out = wire.AppendBytes(out, 8, v)
}
}
}
}
if f == "Survival" {
prefix := fmt.Sprintf("%d:", uid)
for key, level := range st.Upgrades {
if !strings.HasPrefix(key, prefix) {
continue
}
var id uint64
_, _ = fmt.Sscanf(key[len(prefix):], "%d", &id)
v := wire.AppendVarint(nil, 1, id)
v = wire.AppendVarint(v, 2, level)
out = wire.AppendBytes(out, 10, v)
}
}
return out
}
func rankingWire(st *snapshot, uid uint64, f string, record bool) []byte {
keys := []string{}
for k, r := range st.Records {
if r.UID == uid && r.Family == f && r.Best > 0 {
keys = append(keys, k)
}
}
sort.Strings(keys)
var out []byte
for _, k := range keys {
r := st.Records[k]
var b []byte
switch f {
case "Survival":
b = wire.AppendVarint(nil, 1, 1)
b = wire.AppendVarint(b, 4, r.Best)
if record {
b = wire.AppendVarint(nil, 1, r.Best)
b = wire.AppendDouble(b, 2, 100)
}
case "Hopscotch":
b = wire.AppendVarint(nil, 1, 1)
b = wire.AppendVarint(b, 4, r.Best)
if record {
b = wire.AppendVarint(nil, 1, r.Stage)
b = wire.AppendVarint(b, 2, r.Best)
b = wire.AppendDouble(b, 4, 100)
}
case "Action":
b = wire.AppendVarint(nil, 3, 1)
b = wire.AppendVarint(b, 4, r.Best)
if record {
b = wire.AppendVarint(nil, 1, r.Stage)
b = wire.AppendVarint(b, 2, r.Best)
b = wire.AppendDouble(b, 3, 100)
}
case "Sichuan":
b = wire.AppendVarint(nil, 7, 1)
b = wire.AppendVarint(b, 8, r.Best)
if record {
b = wire.AppendVarint(nil, 1, r.Best)
b = wire.AppendDouble(b, 2, 100)
}
case "Rhythm":
b = wire.AppendVarint(nil, 1, 1)
b = wire.AppendVarint(b, 4, r.Best)
if record {
b = wire.AppendVarint(nil, 1, r.Best)
b = wire.AppendVarint(b, 2, r.Stage)
b = wire.AppendDouble(b, 3, 100)
}
default:
b = wire.AppendVarint(nil, 1, 1)
b = wire.AppendVarint(b, 4, r.Best)
}
out = wire.AppendBytes(out, 1, b)
}
return out
}
func (s *Service) claimScore(path string, uid uint64, f string, next *snapshot, key string) ([]byte, error) {
for k, r := range next.Records {
if r.UID != uid || r.Family != f || r.Best == 0 {
continue
}
point, rewards, e := s.scoreRewards(r.Game, r.Best)
if e != nil {
return nil, e
}
day := uint64(s.now().UnixMilli()) / 86400000
if r.Date != day {
r.Paid = 0
}
if point <= r.Paid {
return nil, fmt.Errorf("eventplay: daily best reward already paid")
}
_, old, e := s.scoreRewards(r.Game, r.Paid)
if e != nil {
return nil, e
}
bundle, e := s.grant("eventplay:"+key, rewardDifference(old, rewards))
if e != nil {
return nil, e
}
r.Paid = point
r.Date = day
next.Records[k] = r
if strings.HasSuffix(path, "QuickReward") {
return wire.AppendBytes(nil, 1, bundle), nil
}
out := wire.AppendVarint(nil, 1, point)
return wire.AppendBytes(out, 2, bundle), nil
}
return nil, fmt.Errorf("eventplay: no completed score to reward")
}