Add daily runs and seed completions
This commit is contained in:
1 parent
23eb0bbbe8
commit
2e964b007d
11 files changed
+316
-54
No files matched your search
@@ -0,0 +1,36 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/Flashfyre/pokerogue-server/db"
|
||||
)
|
||||
|
||||
var (
|
||||
dailyRunSeed string
|
||||
)
|
||||
|
||||
func ScheduleDailyRunRefresh() {
|
||||
scheduler.Every(1).Day().At("00:00").Do(func() {
|
||||
InitDailyRun()
|
||||
})
|
||||
}
|
||||
|
||||
func InitDailyRun() {
|
||||
dailyRunSeed = base64.StdEncoding.EncodeToString(SeedFromTime(time.Now().UTC()))
|
||||
err := db.TryAddDailyRun(dailyRunSeed)
|
||||
if err != nil {
|
||||
log.Print(err.Error())
|
||||
} else {
|
||||
log.Printf("Daily Run Seed: %s", dailyRunSeed)
|
||||
}
|
||||
}
|
||||
|
||||
// /daily/seed - get daily run seed
|
||||
|
||||
func (s *Server) HandleSeed(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(dailyRunSeed))
|
||||
}
|
||||
@@ -3,12 +3,19 @@ package api
|
||||
import (
|
||||
"encoding/gob"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-co-op/gocron"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Debug bool
|
||||
}
|
||||
|
||||
var (
|
||||
scheduler = gocron.NewScheduler(time.UTC)
|
||||
)
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if s.Debug {
|
||||
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||
@@ -40,6 +47,11 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.HandleSavedataUpdate(w, r)
|
||||
case "/savedata/delete":
|
||||
s.HandleSavedataDelete(w, r)
|
||||
case "/savedata/clear":
|
||||
s.HandleSavedataClear(w, r)
|
||||
|
||||
case "/daily/seed":
|
||||
s.HandleSeed(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
func GetSystemSaveData(uuid []byte) (SystemSaveData, error) {
|
||||
var system SystemSaveData
|
||||
|
||||
save, err := os.ReadFile("userdata/" + hex.EncodeToString(uuid) + "/system.pzs")
|
||||
if err != nil {
|
||||
return system, fmt.Errorf("failed to read save file: %s", err)
|
||||
}
|
||||
|
||||
zstdReader, err := zstd.NewReader(nil)
|
||||
if err != nil {
|
||||
return system, fmt.Errorf("failed to create zstd reader: %s", err)
|
||||
}
|
||||
|
||||
decompressed, err := zstdReader.DecodeAll(save, nil)
|
||||
if err != nil {
|
||||
return system, fmt.Errorf("failed to decompress save file: %s", err)
|
||||
}
|
||||
|
||||
gobDecoderBuf := bytes.NewBuffer(decompressed)
|
||||
|
||||
err = gob.NewDecoder(gobDecoderBuf).Decode(&system)
|
||||
if err != nil {
|
||||
return system, fmt.Errorf("failed to deserialize save: %s", err)
|
||||
}
|
||||
|
||||
return system, nil
|
||||
}
|
||||
|
||||
func GetSessionSaveData(uuid []byte, slotId int) (SessionSaveData, error) {
|
||||
var session SessionSaveData
|
||||
|
||||
fileName := "session"
|
||||
if slotId != 0 {
|
||||
fileName += strconv.Itoa(slotId)
|
||||
}
|
||||
|
||||
save, err := os.ReadFile(fmt.Sprintf("userdata/%s/%s.pzs", hex.EncodeToString(uuid), fileName))
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("failed to read save file: %s", err)
|
||||
}
|
||||
|
||||
zstdReader, err := zstd.NewReader(nil)
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("failed to create zstd reader: %s", err)
|
||||
}
|
||||
|
||||
decompressed, err := zstdReader.DecodeAll(save, nil)
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("failed to decompress save file: %s", err)
|
||||
}
|
||||
|
||||
gobDecoderBuf := bytes.NewBuffer(decompressed)
|
||||
|
||||
err = gob.NewDecoder(gobDecoderBuf).Decode(&session)
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("failed to deserialize save: %s", err)
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func ValidateSessionCompleted(session SessionSaveData) bool {
|
||||
switch session.GameMode {
|
||||
case 0:
|
||||
return session.WaveIndex == 200
|
||||
case 3:
|
||||
return session.WaveIndex == 50
|
||||
}
|
||||
return false
|
||||
}
|
||||
+71
-53
@@ -26,34 +26,11 @@ func (s *Server) HandleSavedataGet(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
hexUuid := hex.EncodeToString(uuid)
|
||||
|
||||
switch r.URL.Query().Get("datatype") {
|
||||
case "0": // System
|
||||
save, err := os.ReadFile("userdata/" + hexUuid + "/system.pzs")
|
||||
system, err := GetSystemSaveData(uuid)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to read save file: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
zstdReader, err := zstd.NewReader(nil)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to create zstd reader: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
decompressed, err := zstdReader.DecodeAll(save, nil)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to decompress save file: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
gobDecoderBuf := bytes.NewBuffer(decompressed)
|
||||
|
||||
var system SystemSaveData
|
||||
err = gob.NewDecoder(gobDecoderBuf).Decode(&system)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to deserialize save: %s", err), http.StatusInternalServerError)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -76,35 +53,9 @@ func (s *Server) HandleSavedataGet(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
fileName := "session"
|
||||
if slotId != 0 {
|
||||
fileName += strconv.Itoa(slotId)
|
||||
}
|
||||
|
||||
save, err := os.ReadFile(fmt.Sprintf("userdata/%s/%s.pzs", hexUuid, fileName))
|
||||
session, err := GetSessionSaveData(uuid, slotId)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to read save file: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
zstdReader, err := zstd.NewReader(nil)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to create zstd reader: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
decompressed, err := zstdReader.DecodeAll(save, nil)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to decompress save file: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
gobDecoderBuf := bytes.NewBuffer(decompressed)
|
||||
|
||||
var session SessionSaveData
|
||||
err = gob.NewDecoder(gobDecoderBuf).Decode(&session)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to deserialize save: %s", err), http.StatusInternalServerError)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -287,3 +238,70 @@ func (s *Server) HandleSavedataDelete(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
type SavedataClearResponse struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
// /savedata/clear - mark session save data as cleared and delete
|
||||
|
||||
func (s *Server) HandleSavedataClear(w http.ResponseWriter, r *http.Request) {
|
||||
uuid, err := GetUuidFromRequest(r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = db.UpdateAccountLastActivity(uuid)
|
||||
if err != nil {
|
||||
log.Print("failed to update account last activity")
|
||||
}
|
||||
|
||||
slotId, err := strconv.Atoi(r.URL.Query().Get("slot"))
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to convert slot id: %s", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if slotId < 0 || slotId >= sessionSlotCount {
|
||||
http.Error(w, fmt.Sprintf("slot id %d out of range", slotId), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
session, err := GetSessionSaveData(uuid, slotId)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
sessionCompleted := ValidateSessionCompleted(session)
|
||||
newCompletion := false
|
||||
|
||||
if sessionCompleted {
|
||||
newCompletion, err = db.TryAddSeedCompletion(uuid, session.Seed)
|
||||
if err != nil {
|
||||
log.Print("failed to mark seed as completed")
|
||||
}
|
||||
}
|
||||
|
||||
response, err := json.Marshal(SavedataClearResponse{Success: newCompletion})
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("failed to marshal response json: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if sessionCompleted {
|
||||
fileName := "session"
|
||||
if slotId != 0 {
|
||||
fileName += strconv.Itoa(slotId)
|
||||
}
|
||||
|
||||
err = os.Remove(fmt.Sprintf("userdata/%s/%s.pzs", hex.EncodeToString(uuid), fileName))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
http.Error(w, fmt.Sprintf("failed to delete save file: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
w.Write(response)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
var seedKey []byte // 32 bytes
|
||||
|
||||
func SetSeedKey(key []byte) {
|
||||
seedKey = key
|
||||
}
|
||||
|
||||
func SeedFromTime(seedTime time.Time) []byte {
|
||||
day := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(day, uint64(math.Floor(float64(seedTime.Unix())/float64(time.Hour*24))))
|
||||
|
||||
sum := md5.Sum(append(seedKey, day...))
|
||||
|
||||
return sum[:]
|
||||
}
|
||||
Reference in new issue
Block a user