From 40a9777ca88a2feca8a1032f19369a4106ab3598 Mon Sep 17 00:00:00 2001 From: Borengar Date: Fri, 24 Sep 2021 21:28:50 +0200 Subject: [PATCH] add new unsafe-predict-replay flag that prefetches 3 random replays (#61) * add new unsafe-predict-replay flag that prefetches 3 random replays instead of recommended ones * Add -unsafe-cache-env and -unsafe-predict-replay to docs --- UNSAFE_SPEEDUPS.md | 25 +++++++++++++++++++++++++ main.go | 5 ++++- proxy/proxy.go | 8 ++++++++ proxy/stats_get_prediction.go | 21 +++++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/UNSAFE_SPEEDUPS.md b/UNSAFE_SPEEDUPS.md index 24d16c1..b4e467f 100644 --- a/UNSAFE_SPEEDUPS.md +++ b/UNSAFE_SPEEDUPS.md @@ -72,3 +72,28 @@ GGST will display some default news instead of the latest ones. Since this returns a completely empty body, it might break the game in future versions. If that happens this would have to be expanded to return some skeleton news entries. Right now GGST seems to handle the empty body gracefully. + +## `-unsafe-cache-env` ([@Borengar](https://github.com/Borengar)) + +(v1.6.0+) + +Totsugeki returns a hard-coded response for `/api/sys/get_env` calls. + +This request gets called before every `/api/user/login` one. (Initial loading on title screen; replays; ranking; entering tower; etc). + +### Speedup + +Up to 1 second every time when you enter the tower, open replays, open the ranking list, etc. +2 seconds on the initial title screen loading if you start fast enough. + +## `-unsafe-predict-replay` ([@Borengar](https://github.com/Borengar)) + +(v1.7.0+) + +Totsugeki prefetches random celestial floor replays for the loading screen `/api/catalog/get_replay` calls. + +The first batch of recommended replays will contain random replays when you open the replays dialog. A refresh will load actual replays that are recommended for you. + +### Speedup + +2-3 seconds saved on the initial loading on title screen. diff --git a/main.go b/main.go index ad5c1d7..47c577b 100755 --- a/main.go +++ b/main.go @@ -283,6 +283,7 @@ func main() { var unsafePredictStatsGet = flag.Bool("unsafe-predict-stats-get", false, "UNSAFE: Asynchronously precache expected statistics/get calls.") var unsafeCacheNews = flag.Bool("unsafe-cache-news", false, "UNSAFE: Cache first news call and return cached version on subsequent calls.") var unsafeNoNews = flag.Bool("unsafe-no-news", false, "UNSAFE: Return an empty response for news.") + var unsafePredictReplay = flag.Bool("unsafe-predict-replay", false, "UNSAFE: Asynchronously precache expected get_replay calls. Needs unsafe-predict-stats-get to work.") var unsafeCacheEnv = flag.Bool("unsafe-cache-env", false, "UNSAFE: Cache first get_env call and return cached version on subsequent calls.") var ungaBunga = flag.Bool("unga-bunga", UngaBungaMode != "", "UNSAFE: Enable all unsafe speedups for maximum speed. Please read https://github.com/optix2000/totsugeki/blob/master/UNSAFE_SPEEDUPS.md") var iKnowWhatImDoing = flag.Bool("i-know-what-im-doing", false, "UNSAFE: Suppress any UNSAFE warnings. I hope you know what you're doing...") @@ -324,6 +325,7 @@ func main() { *unsafeAsyncStatsSet = true *unsafePredictStatsGet = true *unsafeNoNews = true + *unsafePredictReplay = true *unsafeCacheEnv = true } @@ -401,6 +403,7 @@ func main() { PredictStatsGet: *unsafePredictStatsGet, CacheNews: *unsafeCacheNews, NoNews: *unsafeNoNews, + PredictReplay: *unsafePredictReplay, CacheEnv: *unsafeCacheEnv, }) @@ -414,7 +417,7 @@ func main() { }() } - if !*iKnowWhatImDoing && (*unsafeAsyncStatsSet || *unsafePredictStatsGet || *unsafeCacheNews || *unsafeNoNews || *unsafeCacheEnv) { + if !*iKnowWhatImDoing && (*unsafeAsyncStatsSet || *unsafePredictStatsGet || *unsafeCacheNews || *unsafeNoNews || *unsafeCacheEnv || *unsafePredictReplay) { fmt.Println("WARNING: Unsafe feature used. Make sure you understand the implications: https://github.com/optix2000/totsugeki/blob/master/UNSAFE_SPEEDUPS.md") } diff --git a/proxy/proxy.go b/proxy/proxy.go index 0e44259..d6cd728 100755 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -34,6 +34,7 @@ type StriveAPIProxyOptions struct { PredictStatsGet bool CacheNews bool NoNews bool + PredictReplay bool CacheEnv bool } @@ -169,6 +170,7 @@ func CreateStriveProxy(listen string, GGStriveAPIURL string, PatchedAPIURL strin statsSet := proxy.HandleCatchall statsGet := proxy.HandleCatchall getNews := proxy.HandleCatchall + getReplay := proxy.HandleCatchall r := chi.NewRouter() r.Use(middleware.Logger) @@ -192,6 +194,11 @@ func CreateStriveProxy(listen string, GGStriveAPIURL string, PatchedAPIURL strin proxy.HandleCatchall(w, r) } } + + if options.PredictReplay { + getReplay = statsGet + proxy.prediction.PredictReplay = true + } } if options.NoNews { getNews = func(w http.ResponseWriter, r *http.Request) { @@ -225,6 +232,7 @@ func CreateStriveProxy(listen string, GGStriveAPIURL string, PatchedAPIURL strin r.HandleFunc("/sys/get_news", getNews) r.HandleFunc("/catalog/get_follow", statsGet) r.HandleFunc("/catalog/get_block", statsGet) + r.HandleFunc("/catalog/get_replay", getReplay) r.HandleFunc("/lobby/get_vip_status", statsGet) r.HandleFunc("/item/get_item", statsGet) r.HandleFunc("/*", proxy.HandleCatchall) diff --git a/proxy/stats_get_prediction.go b/proxy/stats_get_prediction.go index ad2b8ab..32e3753 100755 --- a/proxy/stats_get_prediction.go +++ b/proxy/stats_get_prediction.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "net/http" "net/url" + "regexp" "strings" ) @@ -26,6 +27,7 @@ type StatsGetPrediction struct { predictionState PredictionState statsGetTasks map[string]*StatsGetTask client *http.Client + PredictReplay bool skipNext bool } @@ -95,6 +97,16 @@ func (s *StatsGetPrediction) HandleGetStats(w http.ResponseWriter, r *http.Reque r.Body.Close() // must close r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) // Reset Body as the request gets reused by catchall if this has an error. req := string(bodyBytes) + if strings.HasSuffix(r.RequestURI, "catalog/get_replay") { + regex := regexp.MustCompile(`940100059aff00.*$`) + for _, data := range []string{"940100059aff00636390ffff000001\x00", "940100059aff00636390ffff010001\x00", "940100059aff00636390ffff020001\x00"} { + possibleReq := regex.ReplaceAllString(req, data) + if _, ok := s.statsGetTasks[possibleReq]; ok { + req = possibleReq + break + } + } + } if task, ok := s.statsGetTasks[req]; ok { resp := <-task.response if resp == nil { @@ -194,6 +206,11 @@ func (s *StatsGetPrediction) AsyncGetStats(body []byte, reqType StatsGetType) { queue := make(chan *StatsGetTask, len(reqs)+1) for i := range reqs { task := reqs[i] + + if task.path == "catalog/get_replay" && !s.PredictReplay { + continue + } + id := bodyConst + task.data + "\x00" task.request = id task.response = make(chan *http.Response) @@ -215,6 +232,7 @@ func CreateStatsGetPrediction(GGStriveAPIURL string, client *http.Client) StatsG predictionState: ready, statsGetTasks: make(map[string]*StatsGetTask), client: client, + PredictReplay: false, skipNext: false, } } @@ -316,6 +334,9 @@ func ExpectedTitleScreenCalls() []StatsGetTask { {data: "96a00101ffffff", path: "statistics/get"}, {data: "93000101", path: "catalog/get_follow"}, {data: "920101", path: "catalog/get_block"}, + {data: "940100059aff00636390ffff000001", path: "catalog/get_replay"}, // these 3 only get used if unsafe-predict-replay is set + {data: "940100059aff00636390ffff010001", path: "catalog/get_replay"}, + {data: "940100059aff00636390ffff020001", path: "catalog/get_replay"}, {data: "91a0", path: "lobby/get_vip_status"}, {data: "9105", path: "item/get_item"}, }