68 lines
1.6 KiB
Go
68 lines
1.6 KiB
Go
package hunting
|
|
|
|
import (
|
|
"bd2server/internal/server/design/gamedata"
|
|
"bd2server/internal/server/domain/command"
|
|
"bd2server/internal/server/platform/versionconfig"
|
|
"bd2server/internal/server/storage/stateio"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
type apClock struct {
|
|
Version string `json:"version"`
|
|
Next int64 `json:"next"`
|
|
}
|
|
|
|
func (s *Service) AttachAPRefresh(design gamedata.HuntingAPDesign) error {
|
|
|
|
if design.Max == 0 || design.Max > 2147483647 || design.ResetSeconds < 0 || design.ResetSeconds >= 86400 {
|
|
return fmt.Errorf("hunting: invalid AP refresh design")
|
|
}
|
|
s.apDesign = &design
|
|
s.now = time.Now
|
|
return nil
|
|
}
|
|
|
|
// The client clock is UTC+9. DailyResetTime is expressed in that clock.
|
|
func (s *Service) refreshAP(ctx command.Context) error {
|
|
if s.apDesign == nil {
|
|
return nil
|
|
}
|
|
now := s.now().UnixMilli()
|
|
offset := (s.apDesign.ResetSeconds - 9*3600) * 1000
|
|
day := (now - offset) / 86400000
|
|
nextTime := (day+1)*86400000 + offset
|
|
b, e := s.storage.Load(ctx.State, "huntingapclock")
|
|
if e != nil {
|
|
return e
|
|
}
|
|
clock := apClock{versionconfig.State(), nextTime}
|
|
if b != nil {
|
|
if e = stateio.RequireExactJSONObject(b, "version", "next"); e != nil {
|
|
return e
|
|
}
|
|
if e = json.Unmarshal(b, &clock); e != nil {
|
|
return e
|
|
}
|
|
if clock.Version != versionconfig.State() || clock.Next <= 0 {
|
|
return fmt.Errorf("hunting: invalid AP clock")
|
|
}
|
|
if now < clock.Next {
|
|
return nil
|
|
}
|
|
next := s.clone()
|
|
next.Free = s.apDesign.Max
|
|
if e = s.persist(ctx, next); e != nil {
|
|
return e
|
|
}
|
|
clock.Next = nextTime
|
|
}
|
|
raw, e := json.Marshal(clock)
|
|
if e != nil {
|
|
return e
|
|
}
|
|
return s.storage.Save(ctx.State, "huntingapclock", raw)
|
|
}
|