Compare commits

...

22 Commits

Author SHA1 Message Date
c4154581a6 fixed incorrect type when changing character costume 2026-09-14 18:28:44 +08:00
000b498f0e fixed put music field 2026-09-14 11:58:29 +08:00
09f5079370 fix msk style 2026-09-14 11:29:32 +08:00
20f10260e6 fix msk style 2026-09-13 23:07:14 +08:00
d8badacdf1 fix msk style 2026-09-13 23:02:28 +08:00
53a93469be updated JP proto to 10.2.0 2026-09-10 18:34:23 +08:00
cfe85762f7 fix Ctrl+C 2026-09-08 17:26:35 +08:00
4cf2863286 catch Ctrl+C 2026-09-08 17:24:31 +08:00
a4f1212d7b fix liveboost 2026-09-07 21:36:42 +08:00
063fe05920 fixed deck member type issue 2026-09-07 21:25:55 +08:00
d0f0120271 fixed lots of bugs 2026-09-07 20:44:56 +08:00
66235cf663 fixed NewSituationIntroduction 2026-09-06 22:41:29 +08:00
caff3bfb69 fixed NewMusicIntroduction 2026-09-06 22:40:16 +08:00
8415b821fc fixed MainStoryList 2026-09-06 22:36:39 +08:00
b03f3a53a8 fix: GetMaster mutex unlock 2026-09-06 22:34:34 +08:00
35f0ba6133 fixed timestamp bug 2026-09-06 22:32:43 +08:00
60f1d942cd some changes 2026-09-06 22:28:12 +08:00
5743a36f51 add more routes 2026-09-06 21:57:03 +08:00
4688c10585 add user routes 2026-09-04 23:03:50 +08:00
fe8ba74c5f changed param logic & add more routes 2026-09-04 18:08:20 +08:00
a1569590bc add some routes 2026-09-03 18:48:23 +08:00
3004676239 write base server 2026-09-02 18:16:35 +08:00
92 changed files with 727449 additions and 0 deletions

1
.env.example Normal file
View File

@@ -0,0 +1 @@
SERVER=TW

68
db/db.go Normal file
View File

@@ -0,0 +1,68 @@
package db
import (
"encoding/json"
"fmt"
"os"
"sync"
)
type Database struct {
Users map[string][]map[string]any `json:"Users"`
}
type UserIdType string
const (
UserId UserIdType = "userId"
Bid UserIdType = "bid"
)
var (
DB Database
mu sync.Mutex
path = "db.json"
)
func Init(servers []string) {
data, err := os.ReadFile(path)
if err == nil {
json.Unmarshal(data, &DB)
}
if DB.Users == nil {
DB.Users = make(map[string][]map[string]any)
}
for _, s := range servers {
if DB.Users[s] == nil {
DB.Users[s] = []map[string]any{}
}
}
Save()
}
func Save() {
mu.Lock()
defer mu.Unlock()
data, _ := json.MarshalIndent(DB, "", " ")
tmp := path + ".tmp"
os.WriteFile(tmp, data, 0644)
os.Rename(tmp, path)
}
func FindUser(id string, idType ...UserIdType) map[string]any {
key := UserId
if len(idType) > 0 {
key = idType[0]
}
for _, user := range DB.Users[os.Getenv("SERVER")] {
if fmt.Sprintf("%v", user[string(key)]) == id {
return user
}
}
return nil
}

50
gen/gen.go Normal file
View File

@@ -0,0 +1,50 @@
//go:build ignore
package main
import (
"os"
"path/filepath"
"strings"
"text/template"
)
const tmpl = `// Code generated by gen/gen.go — DO NOT EDIT
package main
import (
{{- range .}}
_ "{{.}}"
{{- end}}
)
`
func main() {
var packages []string
moduleName := "bdgrp_go"
filepath.WalkDir("routes", func(path string, d os.DirEntry, err error) error {
if err != nil || d.IsDir() {
return nil
}
if !strings.HasSuffix(d.Name(), ".go") {
return nil
}
pkg := moduleName + "/" + filepath.ToSlash(filepath.Dir(path))
for _, p := range packages {
if p == pkg {
return nil
}
}
packages = append(packages, pkg)
return nil
})
f, _ := os.Create("routes_gen.go")
defer f.Close()
template.Must(template.New("").Parse(tmpl)).Execute(f, packages)
}

25
go.mod Normal file
View File

@@ -0,0 +1,25 @@
module bdgrp_go
go 1.27.1
require (
github.com/gofiber/fiber/v2 v2.52.15
github.com/gookit/color v1.6.1
github.com/joho/godotenv v1.5.1
google.golang.org/protobuf v1.36.12
)
require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/sys v0.30.0 // indirect
)

41
go.sum Normal file
View File

@@ -0,0 +1,41 @@
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/gofiber/fiber/v2 v2.52.15 h1:Cov1uKeVPyu9q0jSrN60W+A8XNX+/WK8J7cy5osHLIk=
github.com/gofiber/fiber/v2 v2.52.15/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0=
github.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E=
github.com/gookit/color v1.6.1 h1:KoTnDxJPRgrL0SoX0f8rCFg2zI0t4E3GZZBMo2nN8LU=
github.com/gookit/color v1.6.1/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=

86
main.go
View File

@@ -1 +1,87 @@
//go:generate go run gen/gen.go
package main
import (
"bdgrp_go/master"
"fmt"
"log"
"os"
"regexp"
"slices"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gookit/color"
"github.com/joho/godotenv"
"bdgrp_go/db"
"bdgrp_go/routes"
"os/signal"
"syscall"
)
const PORT = ":8482"
var servers = []string{"TW", "JP", "GL", "CN"}
func main() {
if _, err := os.Stat(".env"); os.IsNotExist(err) {
log.Fatal("Error: .env not found.")
}
godotenv.Load()
server := os.Getenv("SERVER")
valid := slices.Contains(servers, server)
if !valid {
log.Fatal("Error: Unknown Server.")
}
for _, s := range servers {
os.MkdirAll("resp/"+s, 0755)
}
db.Init(servers)
app := fiber.New(fiber.Config{
StrictRouting: true,
ETag: false,
})
app.Use(logger.New())
re := regexp.MustCompile(`/+`)
app.Use(func(c *fiber.Ctx) error {
c.Path(re.ReplaceAllString(c.Path(), "/"))
return c.Next()
})
routes.LoadAll(app)
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString(os.Getenv("SERVER"))
})
log.Printf("Running on %s", PORT)
color.HEX("#00AABB").Printf("Server: %s\n", server)
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
for {
<-quit
fmt.Print("\nProceed to exit? (y/n): ")
var input string
fmt.Scanln(&input)
if input == "y" {
db.Save()
app.Shutdown()
return
}
}
}()
go master.ReloadMaster()
app.Listen(PORT)
}

58
master/master.go Normal file
View File

@@ -0,0 +1,58 @@
package master
import (
"bdgrp_go/pbutil"
"bdgrp_go/utils"
"bytes"
"compress/bzip2"
"io"
"os"
"path/filepath"
"sync"
)
var (
cache map[string]any
mu sync.RWMutex
)
func GetMaster() map[string]any {
mu.RLock()
if cache != nil {
mu.RUnlock()
return cache
}
mu.RUnlock()
return ReloadMaster()
}
func ReloadMaster() map[string]any {
server := os.Getenv("SERVER")
filePath := filepath.Join("resp", server, "suitemaster.bz2")
fileBuffer, err := os.ReadFile(filePath)
if err != nil {
return cache
}
decrypted, err := utils.Decrypt(fileBuffer)
if err != nil {
return cache
}
decompressed, err := io.ReadAll(bzip2.NewReader(bytes.NewReader(decrypted)))
if err != nil {
return cache
}
result, err := pbutil.Decode("SuiteMasterGetResponse", decompressed)
if err != nil {
return cache
}
mu.Lock()
cache = result
mu.Unlock()
return cache
}

4681
mission.json Normal file

File diff suppressed because it is too large Load Diff

48485
pastEvents/CN.json Normal file

File diff suppressed because it is too large Load Diff

47043
pastEvents/GL.json Normal file

File diff suppressed because it is too large Load Diff

50993
pastEvents/JP.json Normal file

File diff suppressed because it is too large Load Diff

48623
pastEvents/TW.json Normal file

File diff suppressed because it is too large Load Diff

65
pbutil/pbutil.go Normal file
View File

@@ -0,0 +1,65 @@
package pbutil
import (
"encoding/json"
"fmt"
"os"
"strings"
_ "bdgrp_go/proto/cn"
_ "bdgrp_go/proto/gl"
_ "bdgrp_go/proto/jp"
_ "bdgrp_go/proto/tw"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
func fullName(message string) protoreflect.FullName {
server := strings.ToLower(os.Getenv("SERVER"))
// twdori.proto.ce.UserLogin
return protoreflect.FullName(fmt.Sprintf("%sdori.proto.ce.%s", server, message))
}
func Decode(message string, data []byte) (map[string]any, error) {
mt, err := protoregistry.GlobalTypes.FindMessageByName(fullName(message))
if err != nil {
return nil, fmt.Errorf("message %s not found", message)
}
msg := mt.New().Interface()
if err := proto.Unmarshal(data, msg); err != nil {
return nil, err
}
return ToMap(msg)
}
func Encode(message string, data map[string]any) ([]byte, error) {
mt, err := protoregistry.GlobalTypes.FindMessageByName(fullName(message))
if err != nil {
return nil, fmt.Errorf("message %s not found", message)
}
msg := mt.New().Interface()
// map → json → proto
jsonBytes, _ := json.MarshalIndent(data, "", " ")
if err := protojson.Unmarshal(jsonBytes, msg); err != nil {
return nil, err
}
return proto.Marshal(msg)
}
func ToMap(msg proto.Message) (map[string]any, error) {
jsonBytes, err := protojson.Marshal(msg)
if err != nil {
return nil, err
}
var result map[string]any
json.Unmarshal(jsonBytes, &result)
return result, nil
}

135797
proto/cn/cn.go Normal file

File diff suppressed because it is too large Load Diff

125786
proto/gl/gl.go Normal file

File diff suppressed because it is too large Load Diff

130318
proto/jp/jp.go Normal file

File diff suppressed because it is too large Load Diff

129280
proto/tw/tw.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
package acdm
import (
"fmt"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, acdm)
fmt.Println("Loaded:", path)
})
}
func acdm(c *fiber.Ctx) error {
return c.SendString("")
}

53
routes/api/application.go Normal file
View File

@@ -0,0 +1,53 @@
package api
import (
"fmt"
"os"
"path/filepath"
"bdgrp_go/routes"
"bdgrp_go/routes/upstream"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, application)
fmt.Println("Loaded:", path)
})
}
func application(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
cachePath := filepath.Join("resp", server, "application.binpb")
headers := map[string]string{
"User-Agent": c.Get("User-Agent"),
"Content-Type": c.Get("Content-Type"),
"Accept": c.Get("Accept"),
"Accept-Encoding": c.Get("Accept-Encoding"),
"x-clientversion": c.Get("x-clientversion"),
}
if server == "CN" {
headers["x-platformid"] = c.Get("x-platformid")
headers["x-deviceid"] = c.Get("x-deviceid")
headers["x-channelid"] = c.Get("x-channelid")
headers["x-clientplatform"] = c.Get("x-clientplatform")
}
url := fmt.Sprintf("%s/api/application", upstream.BaseUrl())
data, err := upstream.Fetch(url, headers)
if err != nil {
data, err = os.ReadFile(cachePath)
if err != nil {
return c.Status(500).SendString("no cache available")
}
} else {
os.WriteFile(cachePath, data, 0644)
}
return c.Send(data)
}

53
routes/api/cleanupinfo.go Normal file
View File

@@ -0,0 +1,53 @@
package api
import (
"bdgrp_go/routes/upstream"
"fmt"
"os"
"path/filepath"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, cleanupinfo)
fmt.Println("Loaded:", path)
})
}
func cleanupinfo(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
cachePath := filepath.Join("resp", server, "cleanupinfo.binpb")
headers := map[string]string{
"User-Agent": c.Get("User-Agent"),
"Content-Type": c.Get("Content-Type"),
"Accept": c.Get("Accept"),
"Accept-Encoding": c.Get("Accept-Encoding"),
"x-clientversion": c.Get("x-clientversion"),
}
if server == "CN" {
headers["x-platformid"] = c.Get("x-platformid")
headers["x-deviceid"] = c.Get("x-deviceid")
headers["x-channelid"] = c.Get("x-channelid")
headers["x-clientplatform"] = c.Get("x-clientplatform")
}
url := fmt.Sprintf("%s/api/application", upstream.BaseUrl())
data, err := upstream.Fetch(url, headers)
if err != nil {
data, err = os.ReadFile(cachePath)
if err != nil {
return c.Status(500).SendString("no cache available")
}
} else {
os.WriteFile(cachePath, data, 0644)
}
return c.Send(data)
}

View File

@@ -0,0 +1,53 @@
package information
import (
"fmt"
"os"
"path/filepath"
"bdgrp_go/routes"
"bdgrp_go/routes/upstream"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, application)
fmt.Println("Loaded:", path)
})
}
func application(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
cachePath := filepath.Join("resp", server, "overview.binpb")
headers := map[string]string{
"User-Agent": c.Get("User-Agent"),
"Content-Type": c.Get("Content-Type"),
"Accept": c.Get("Accept"),
"Accept-Encoding": c.Get("Accept-Encoding"),
"x-clientversion": c.Get("x-clientversion"),
}
if server == "CN" {
headers["x-platformid"] = c.Get("x-platformid")
headers["x-deviceid"] = c.Get("x-deviceid")
headers["x-channelid"] = c.Get("x-channelid")
headers["x-clientplatform"] = c.Get("x-clientplatform")
}
url := fmt.Sprintf("%s/api/information/overview", upstream.BaseUrl())
data, err := upstream.Fetch(url, headers)
if err != nil {
data, err = os.ReadFile(cachePath)
if err != nil {
return c.Status(500).SendString("no cache available")
}
} else {
os.WriteFile(cachePath, data, 0644)
}
return c.Send(data)
}

View File

@@ -0,0 +1,49 @@
package api
import (
"fmt"
"os"
"path/filepath"
"bdgrp_go/routes"
"bdgrp_go/routes/upstream"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, rewardmap)
fmt.Println("Loaded:", path)
})
}
func rewardmap(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
cachePath := filepath.Join("resp", server, "config.binpb")
headers := map[string]string{
"User-Agent": c.Get("User-Agent"),
"Content-Type": c.Get("Content-Type"),
"Accept": c.Get("Accept"),
"Accept-Encoding": c.Get("Accept-Encoding"),
"x-clientversion": c.Get("x-clientversion"),
"x-platformid": c.Get("x-platformid"),
"x-deviceid": c.Get("x-deviceid"),
"x-channelid": c.Get("x-channelid"),
"x-clientplatform": c.Get("x-clientplatform"),
}
data, err := upstream.Fetch("https://l3-prod-all-bd.bilibiligame.net/api/missionreward.map", headers)
if err != nil {
data, err = os.ReadFile(cachePath)
if err != nil {
return c.Status(500).SendString("no cache available")
}
} else {
os.WriteFile(cachePath, data, 0644)
}
return c.Send(data)
}

21
routes/api/multiroom.go Normal file
View File

@@ -0,0 +1,21 @@
package api
import (
"fmt"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, multiroom)
fmt.Println("Loaded:", path)
})
}
func multiroom(c *fiber.Ctx) error {
return c.SendString("")
}

View File

@@ -0,0 +1,21 @@
package create
import (
"fmt"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, multiroom)
fmt.Println("Loaded:", path)
})
}
func multiroom(c *fiber.Ctx) error {
return c.SendString("")
}

View File

@@ -0,0 +1,58 @@
package suite
import (
mastermanager "bdgrp_go/master"
"fmt"
"os"
"path/filepath"
"bdgrp_go/routes"
"bdgrp_go/routes/upstream"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, master)
fmt.Println("Loaded:", path)
})
}
func master(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
cachePath := filepath.Join("resp", server, "suitemaster.bz2")
headers := map[string]string{
"User-Agent": c.Get("User-Agent"),
"Content-Type": c.Get("Content-Type"),
"Accept": c.Get("Accept"),
"Accept-Encoding": c.Get("Accept-Encoding"),
"x-clientversion": c.Get("x-clientversion"),
}
if server == "CN" {
headers["x-platformid"] = c.Get("x-platformid")
headers["x-deviceid"] = c.Get("x-deviceid")
headers["x-channelid"] = c.Get("x-channelid")
headers["x-clientplatform"] = c.Get("x-clientplatform")
}
url := fmt.Sprintf("%s/api/suite/master", upstream.BaseUrl())
data, err := upstream.Fetch(url, headers)
if err != nil {
data, err = os.ReadFile(cachePath)
if err != nil {
return c.Status(500).SendString("no cache available")
}
} else {
os.WriteFile(cachePath, data, 0644)
go mastermanager.ReloadMaster()
}
c.Set("Content-Length", fmt.Sprintf("%d", len(data)))
c.Set("Content-Type", "application/octet-stream")
c.Set("X-Encoding", "bzip2")
return c.Send(data)
}

View File

@@ -0,0 +1,969 @@
package user
import (
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"encoding/json"
"fmt"
"math/rand"
"os"
"path/filepath"
"slices"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
)
var decoMotionMap = buildDecoMotionMap()
func buildDecoMotionMap() map[string][]int {
m := map[string][]int{}
for i := 1; i <= 35; i++ {
base := 217 + (i-1)*5
m[fmt.Sprintf("%d", i)] = []int{base, base + 1, base + 2}
}
m["601"] = []int{392, 393, 394}
for i := 36; i <= 40; i++ {
base := 462 + (i-36)*5
m[fmt.Sprintf("%d", i)] = []int{base, base + 1, base + 2}
}
return m
}
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, get)
fmt.Println("Loaded:", path)
})
}
func storyList(userid string, storyMap map[string]any) map[string]any {
entries := storyMap["entries"].(map[string]any)
var result []any
for _, v := range entries {
story := v.(map[string]any)
result = append(result, map[string]any{
"userId": userid,
"bandStoryId": story["bandStoryId"],
"bandId": story["bandId"],
"status": "already_read",
"seq": story["seq"],
})
}
return map[string]any{"entries": result}
}
func get(c *fiber.Ctx) error {
userid := c.Params("userid")
server := os.Getenv("SERVER")
user := db.FindUser(userid)
if user == nil {
return c.Status(404).SendStatus(404)
}
m := master.GetMaster()
// pastEvents
pastPath := filepath.Join("pastEvents", server+".json")
pastData, _ := os.ReadFile(pastPath)
var past map[string]any
json.Unmarshal(pastData, &past)
// mission.json
missionData, _ := os.ReadFile("mission.json")
var missionsBase map[string]any
json.Unmarshal(missionData, &missionsBase)
missions := deepCopy(missionsBase)
for _, v := range missions {
group := v.(map[string]any)
if entries, ok := group["entries"].([]any); ok {
for _, e := range entries {
entry := e.(map[string]any)
entry["userId"] = userid
}
}
}
deckName := map[string]string{
"TW": "樂團1", "JP": "バンド1", "GL": "Band 1", "CN": "乐队1",
}[server]
changed := false
if user["situationIllust"] == nil {
user["situationIllust"] = map[string]any{}
changed = true
}
if user["decks"] == nil {
user["decks"] = []any{map[string]any{
"deckId": 1, "deckName": deckName,
"leader": 947, "member1": 1765, "member2": 1730, "member3": 2193, "member4": 2018,
"deckType": "normal",
}}
changed = true
}
if user["musicScore"] == nil {
user["musicScore"] = map[string]any{}
changed = true
}
if user["wearingCostume"] == nil {
costumeDefaults := map[int]map[string]any{
36: {"dressId": 12854, "hairstyleId": 502, "costumeId": 1786},
37: {"dressId": 12855, "hairstyleId": 503, "costumeId": 1787},
38: {"dressId": 12856, "hairstyleId": 504, "costumeId": 1788},
39: {"dressId": 12857, "hairstyleId": 505, "costumeId": 1789},
40: {"dressId": 12858, "hairstyleId": 506, "costumeId": 1790},
601: {"dressId": 36, "hairstyleId": 36, "costumeId": 1643},
}
wc := map[string]any{}
charIds := append(rangeInts(1, 40), 601)
for _, charId := range charIds {
key := fmt.Sprintf("%d", charId)
if def, ok := costumeDefaults[charId]; ok {
wc[key] = def
} else {
wc[key] = map[string]any{
"dressId": charId, "hairstyleId": charId, "costumeId": 1332 + charId,
}
}
}
user["wearingCostume"] = wc
changed = true
}
if user["decos"] == nil {
user["decos"] = map[string]any{}
changed = true
}
if user["areaItems"] == nil {
user["areaItems"] = map[string]any{}
changed = true
}
if changed {
db.Save()
}
charIds := append(rangeInts(1, 40), 601)
userCharacterMap := map[string]any{}
wc := user["wearingCostume"].(map[string]any)
for _, id := range charIds {
key := fmt.Sprintf("%d", id)
costume := wc[key].(map[string]any)
userCharacterMap[key] = map[string]any{
"userId": userid, "characterId": id,
"costumeId": costume["costumeId"],
}
}
userSituations := utils.BuildUserSituations(userid, m, user)
situationMap := map[string]any{}
for _, sit := range userSituations {
s := sit.(map[string]any)
situationMap[fmt.Sprintf("%v", s["situationId"])] = s
}
decks := user["decks"].([]any)
mainDeckIdx := 1
if md, ok := user["mainDeck"].(float64); ok {
mainDeckIdx = int(md)
}
mainDeck := decks[mainDeckIdx-1].(map[string]any)
situationIdFields := []string{"leader", "member1", "member2", "member3", "member4"}
charSituationMap := m["masterCharacterSituationMap"].(map[string]any)["entries"].(map[string]any)
seen := map[int]bool{}
var deckMembers []int
for _, field := range situationIdFields {
if sid, ok := mainDeck[field]; ok && sid != nil {
sidStr := fmt.Sprintf("%v", sid)
if entry, ok := charSituationMap[sidStr].(map[string]any); ok {
if charId, ok := entry["characterId"].(float64); ok {
cid := int(charId)
if !seen[cid] {
seen[cid] = true
deckMembers = append(deckMembers, cid)
}
}
}
}
}
commonsLive2d := map[string]map[int][]int{}
if cl2dMap, ok := m["masterCommonsLive2dMap"].(map[string]any); ok {
for _, v := range cl2dMap["entries"].(map[string]any) {
entry := v.(map[string]any)
cat := fmt.Sprintf("%v", entry["live2dCategory"])
cid := int(entry["characterId"].(float64))
lid := int(entry["live2dId"].(float64))
if commonsLive2d[cat] == nil {
commonsLive2d[cat] = map[int][]int{}
}
commonsLive2d[cat][cid] = append(commonsLive2d[cat][cid], lid)
}
}
aggregated := map[string][]int{}
for cat, charMap := range commonsLive2d {
for charId, ids := range charMap {
if slices.Contains(deckMembers, charId) {
aggregated[cat] = append(aggregated[cat], ids...)
}
}
}
userCommonsLive2dEntries := map[string]any{}
for cat, idArray := range aggregated {
entries := make([]any, len(idArray))
for i, lid := range idArray {
entries[i] = map[string]any{"live2dId": lid, "live2dCategory": cat}
}
userCommonsLive2dEntries[cat] = map[string]any{"entries": entries}
}
userProfileDegree := utils.BuildUserProfileDegree(userid, user)
decoDegree := map[string]any{}
for k, v := range userProfileDegree {
entry := v.(map[string]any)
decoDegree[k] = map[string]any{
"decoFrameId": entry["userId"],
"profileDegreeType": entry["profileDegreeType"],
"degreeId": entry["degreeId"],
}
}
charProfileL2d := map[string][]int{}
if cpMap, ok := m["masterCharacterProfileLive2dMap"].(map[string]any); ok {
for _, v := range cpMap["entries"].(map[string]any) {
entry := v.(map[string]any)
cid := fmt.Sprintf("%v", entry["characterId"])
lid := int(entry["characterProfileLive2dId"].(float64))
charProfileL2d[cid] = append(charProfileL2d[cid], lid)
}
}
charProfileL2dEntries := map[string]any{}
for cid, ids := range charProfileL2d {
entries := make([]any, len(ids))
for i, id := range ids {
entries[i] = map[string]any{"characterId": cid, "live2dId": id}
}
charProfileL2dEntries[cid] = map[string]any{"entries": entries}
}
purchaseIds := []string{}
if pm, ok := m["masterPurchaseMap"].(map[string]any); ok {
for id := range pm["entries"].(map[string]any) {
purchaseIds = append(purchaseIds, id)
}
}
userEpisodeMap := map[string]any{}
for _, v := range charSituationMap {
card := v.(map[string]any)
rel := fmt.Sprintf("%v", card["releasedAt"])
if rel == "4128645600000" || rel == "4131237600000" {
continue
}
eps, ok := card["episodes"].(map[string]any)
if !ok {
continue
}
entries, ok := eps["entries"].([]any)
if !ok {
continue
}
for _, e := range entries {
ep := e.(map[string]any)
epId := fmt.Sprintf("%v", ep["episodeId"])
userEpisodeMap[epId] = map[string]any{
"userId": userid, "episodeId": ep["episodeId"], "episodeStatus": "already_read",
}
}
}
validSpawnPoints := map[string]bool{}
if spMap, ok := m["masterAreaItemSpawnMap"].(map[string]any); ok {
for k := range spMap["entries"].(map[string]any) {
validSpawnPoints[k] = true
}
}
now := time.Now().UnixMilli()
var seasonId any
if sbMap, ok := m["masterSeasonBasicMap"].(map[string]any); ok {
for _, v := range sbMap["entries"].(map[string]any) {
s := v.(map[string]any)
startAt, _ := strconv.ParseInt(s["startAt"].(string), 10, 64)
endAt, _ := strconv.ParseInt(s["endAt"].(string), 10, 64)
if startAt <= now && now < endAt {
seasonId = s["seasonId"]
break
}
}
}
eventStoryEntries := map[string]any{}
if escMap, ok := m["masterEventStoryMemorialConfigMap"].(map[string]any); ok {
pastStoryEntries := map[string]any{}
if pse, ok := past["pastEventStoryMap"].(map[string]any); ok {
if entries, ok := pse["entries"].(map[string]any); ok {
pastStoryEntries = entries
}
}
for eventId := range escMap["entries"].(map[string]any) {
length := 0
if pe, ok := pastStoryEntries[eventId].(map[string]any); ok {
if en, ok := pe["entries"].([]any); ok {
length = len(en)
}
}
storyEntries := make([]any, length)
for i := range storyEntries {
storyEntries[i] = map[string]any{
"userId": userid, "eventId": eventId, "seq": i, "status": "already_read",
}
}
eventStoryEntries[eventId] = map[string]any{
"eventId": eventId,
"userEventStoryList": map[string]any{"entries": storyEntries},
"isExistUnReadStory": false,
"isLocked": false,
}
}
}
areaStatusEntries := map[string]any{}
if areaMap, ok := m["masterAreaMap"].(map[string]any); ok {
for areaId, v := range areaMap["entries"].(map[string]any) {
area := v.(map[string]any)
if area["areaType"] == "common" {
areaStatusEntries[areaId] = map[string]any{"userId": userid, "areaId": areaId}
}
}
}
areaItemEntries := map[string]any{}
if aiMap, ok := m["masterAreaItemMap"].(map[string]any); ok {
for id, v := range aiMap["entries"].(map[string]any) {
areaItem := v.(map[string]any)
sp := fmt.Sprintf("%v", areaItem["spawnPoint"])
if validSpawnPoints[sp] {
areaItemEntries[id] = map[string]any{
"userId": userid, "areaItemId": areaItem["areaItemId"],
"areaItemCategory": areaItem["categoryId"], "level": 8,
}
}
}
}
musicScore, _ := user["musicScore"].(map[string]any)
if musicScore == nil {
musicScore = map[string]any{}
}
musicScoreEntries := map[string]any{}
for musicId, v := range musicScore {
sd := v.(map[string]any)
entries, _ := sd["entries"].([]any)
mapped := make([]any, len(entries))
for i, e := range entries {
score := e.(map[string]any)
mapped[i] = map[string]any{
"userId": fmt.Sprintf("%v", user["userId"]),
"musicId": musicId,
"musicDifficulty": score["musicDifficulty"],
"soloHighScore": score["soloHighScore"],
"maxCombo": score["maxCombo"],
"soloScoreRank": score["soloScoreRank"],
"clearStatus": score["clearStatus"],
}
}
musicScoreEntries[musicId] = map[string]any{"entries": mapped}
}
decoEffectEntries := map[string]any{}
if deMap, ok := m["masterDecoEffectList"].(map[string]any); ok {
if entries, ok := deMap["entries"].([]any); ok {
for _, v := range entries {
e := v.(map[string]any)
startAt, _ := strconv.ParseInt(e["startAt"].(string), 10, 64)
endAt, _ := strconv.ParseInt(e["endAt"].(string), 10, 64)
if startAt <= now && now >= endAt {
id := fmt.Sprintf("%v", e["decoEffectId"])
decoEffectEntries[id] = map[string]any{"userId": userid, "decoEffectId": e["decoEffectId"]}
}
}
}
}
digestSeen := map[any]bool{}
var digestEntries []any
if dsList, ok := m["masterDigestStoryDetailList"].(map[string]any); ok {
if entries, ok := dsList["entries"].([]any); ok {
for _, v := range entries {
story := v.(map[string]any)
id := story["digestStoryId"]
if !digestSeen[id] {
digestSeen[id] = true
digestEntries = append(digestEntries, map[string]any{
"userId": userid, "digestStoryId": id, "status": "already_read",
})
}
}
}
}
decoFrameEntries := map[string]any{}
if dfMap, ok := m["masterDecoFrameMap"].(map[string]any); ok {
for _, v := range dfMap["entries"].(map[string]any) {
f := v.(map[string]any)
id := fmt.Sprintf("%v", f["decoFrameId"])
decoFrameEntries[id] = map[string]any{"userId": userid, "decoFrameId": f["decoFrameId"], "level": 5}
}
}
decoPinsEntries := map[string]any{}
if dpMap, ok := m["masterDecoPinsMap"].(map[string]any); ok {
for _, v := range dpMap["entries"].(map[string]any) {
p := v.(map[string]any)
id := fmt.Sprintf("%v", p["decoPinsId"])
decoPinsEntries[id] = map[string]any{"userId": userid, "decoPinsId": p["decoPinsId"], "quantity": 5}
}
}
_ = rand.Intn
userId := fmt.Sprintf("%v", user["userId"])
data := map[string]any{
"user": map[string]any{
"userRegistration": map[string]any{
"userId": userId, "hash": user["hash"], "userName": user["userName"],
"clientVersion": user["clientVersion"], "platform": user["platform"],
"deviceModel": user["deviceModel"], "operatingSystem": user["operatingSystem"],
"birthMonth": user["birthMonth"], "tutorialStatus": user["tutorialStatus"],
"introduction": user["introduction"], "tutorialEndedAt": fmt.Sprintf("%v", user["tutorialEndedAt"]),
},
"userGamedata": map[string]any{
"userId": userId,
"rank": user["rank"],
"exp": user["exp"],
"coin": fmt.Sprintf("%v", user["coin"]), "mainDeck": user["mainDeck"],
"paidStar": user["paidStar"], "freeStar": user["freeStar"], "seal": user["seal"],
"degree": user["degree"].([]any)[0],
"publishTotalDeckPowerFlg": user["publishTotalDeckPowerFlg"],
"publishBandRankFlg": user["publishBandRankFlg"],
"publishMusicClearedFlg": user["publishMusicClearedFlg"],
"publishMusicFullComboFlg": user["publishMusicFullComboFlg"],
"publishHighScoreRatingFlg": user["publishHighScoreRatingFlg"],
"pooledExp": fmt.Sprintf("%v", user["pooledExp"]),
"totalExp": fmt.Sprintf("%v", user["totalExp"]),
"nextExp": user["nextExp"], "publishUpdatedAtFlg": user["publishUpdatedAtFlg"],
"userPaidStarRecallResponse": nil,
"startDashLoginBonusReceiveFlg": user["startDashLoginBonusReceiveFlg"],
"publishMusicAllPerfectFlg": user["publishMusicAllPerfectFlg"],
"publishDeckRankFlg": user["publishDeckRankFlg"],
"publishStageAchievementConditionsFlg": user["publishStageAchievementConditionsFlg"],
"publishStageFriendRankingFlg": user["publishStageFriendRankingFlg"],
"publishCharacterRankFlg": user["publishCharacterRankFlg"],
"loginDays": user["loginDays"],
},
},
"userCharacterMap": map[string]any{"entries": userCharacterMap},
"userSituationMap": map[string]any{"entries": situationMap},
"userMainStoryList": func() map[string]any {
var entries []any
if msMap, ok := m["masterMainStoryMap"].(map[string]any); ok {
list := msMap["entries"].(map[string]any)
for _, l := range list {
story := l.(map[string]any)
entries = append(entries, map[string]any{
"userId": userid, "storyId": story["mainStoryId"], "status": "already_read",
})
}
}
return map[string]any{"entries": entries}
}(),
"userPracticeTicketList": nil,
"userBondsList": map[string]any{
"entries": func() []any {
result := make([]any, 9)
for i := range result {
result[i] = map[string]any{
"userId": userid, "bondsId": i + 1, "level": 1, "bonds": 5 * (i + 2),
}
}
return result
}(),
},
"userBandRankMap": map[string]any{
"entries": func() map[string]any {
result := map[string]any{}
for _, bandId := range []int{1, 2, 3, 4, 5, 18, 21, 45} {
result[fmt.Sprintf("%d", bandId)] = map[string]any{
"userId": userid, "bandId": bandId, "bandRank": 50,
"exp": 0, "totalExp": 0, "nextExp": 0,
}
}
return result
}(),
},
"userPoppinPartyStoryList": storyList(userid, m["masterPoppinPartyStoryMap"].(map[string]any)),
"userAfterglowStoryList": storyList(userid, m["masterAfterglowStoryMap"].(map[string]any)),
"userPastelPalettesStoryList": storyList(userid, m["masterPastelPalettesStoryMap"].(map[string]any)),
"userHelloHappyWorldStoryList": storyList(userid, m["masterHelloHappyWorldStoryMap"].(map[string]any)),
"userRoseliaStoryList": storyList(userid, m["masterRoseliaStoryMap"].(map[string]any)),
"userItemList": func() map[string]any {
var entries []any
if itemMap, ok := m["masterItemMap"].(map[string]any); ok {
for _, v := range itemMap["entries"].(map[string]any) {
item := v.(map[string]any)
entries = append(entries, map[string]any{
"userId": userid, "itemId": item["itemId"], "quantity": 6767,
})
}
}
return map[string]any{"entries": entries}
}(),
"userCommonsLive2dMap": map[string]any{"entries": userCommonsLive2dEntries},
"userEpisodeMap": map[string]any{"entries": userEpisodeMap},
"userAppendParameterMap": nil,
"userMusicInventoryList": func() map[string]any {
var entries []any
if ml, ok := m["masterMusicList"].(map[string]any); ok {
if songs, ok := ml["entries"].([]any); ok {
mvMap := map[string]any{}
if mvl, ok := m["masterMusicVideoListMap"].(map[string]any); ok {
mvMap = mvl["entries"].(map[string]any)
}
for _, v := range songs {
song := v.(map[string]any)
musicId := song["musicId"]
_, hasMv := mvMap[fmt.Sprintf("%v", musicId)]
entries = append(entries, map[string]any{
"userId": userid, "musicId": musicId, "seq": 1,
"hasMv": hasMv, "createdAt": fmt.Sprintf("%d", now),
})
}
}
}
return map[string]any{"entries": entries}
}(),
"userCostumeMap": func() map[string]any {
result := map[string]any{}
if cm, ok := m["masterCostumeMap"].(map[string]any); ok {
for _, v := range cm["entries"].(map[string]any) {
costume := v.(map[string]any)
id := fmt.Sprintf("%v", costume["costumeId"])
result[id] = map[string]any{
"userId": userid, "costumeId": costume["costumeId"], "characterId": costume["characterId"],
}
}
}
return map[string]any{"entries": result}
}(),
"userAfterLiveTalkListMap": nil,
"userAreaItemMap": map[string]any{
"entries": areaItemEntries,
"newlyOpenedContents": map[string]any{"entries": []any{}},
},
"userResourceCount": nil,
"userLiveBoost": map[string]any{
"userId": userid, "liveBoost": 67,
"serverDate": fmt.Sprintf("%d", now), "liveBoostBonusType": "default",
},
"userExchangesList": map[string]any{
"entries": []any{map[string]any{"userId": userid, "exchangesId": 1563, "resetAt": "1779155725000"}},
},
"userGachaTicketList": nil,
"userGachaStatusMap": nil,
"userAreaStatusMap": map[string]any{"entries": areaStatusEntries},
"userLoginBonusMap": map[string]any{"entries": map[string]any{}},
"userHomeBannerList": nil,
"userStampMap": func() map[string]any {
result := map[string]any{}
if sm, ok := m["masterStampMap"].(map[string]any); ok {
for stampId, v := range sm["entries"].(map[string]any) {
stamp := v.(map[string]any)
_, withVoice := stamp["withVoice"]
result[stampId] = map[string]any{
"userId": userid, "stampId": stamp["stampId"],
"seq": 1, "isUnlockVoice": withVoice,
}
}
}
return map[string]any{"entries": result}
}(),
"userDegreeMap": func() map[string]any {
result := map[string]any{}
if dm, ok := m["masterDegreeMap"].(map[string]any); ok {
for degreeId := range dm["entries"].(map[string]any) {
result[degreeId] = map[string]any{"userId": userid, "degreeId": degreeId}
}
}
return map[string]any{"entries": result}
}(),
"userBadPenalty": nil,
"userCharacterProfileLive2dMap": map[string]any{"entries": charProfileL2dEntries},
"userEventExchangesList": map[string]any{"entries": []any{}},
"userEventItemList": func() map[string]any {
var entries []any
if eim, ok := m["masterEventItemMap"].(map[string]any); ok {
for _, v := range eim["entries"].(map[string]any) {
item := v.(map[string]any)
entries = append(entries, map[string]any{
"userId": userid, "eventItemId": item["eventItemId"], "quantity": 1,
})
}
}
return map[string]any{"entries": entries}
}(),
"userPurchaseMap": func() map[string]any {
result := map[string]any{}
for _, id := range purchaseIds {
result[id] = map[string]any{"userId": userid, "purchaseId": id, "count": 0}
}
return map[string]any{"entries": result}
}(),
"userMissionMap": map[string]any{"entries": missions},
"userGenericStoryMap": func() map[string]any {
result := map[string]any{}
if gsm, ok := m["masterGenericStoryMap"].(map[string]any); ok {
for id, v := range gsm["entries"].(map[string]any) {
story := v.(map[string]any)
result[id] = map[string]any{
"userId": userid, "genericStoryId": story["genericStoryId"], "status": "already_read",
}
}
}
return map[string]any{"entries": result}
}(),
"userLiveBoostRecoveryItemList": nil,
"userHighScoreRating": nil,
"userHighScoreMusicRatingMap": nil,
"userSeason": map[string]any{"seasonId": seasonId},
"userQualifyTournamentMusicScoreMap": nil,
"userEventStoryMemorialMap": map[string]any{"entries": eventStoryEntries},
"userReleasedBondsIdList": func() map[string]any {
var entries []any
if bm, ok := m["masterBondsMap"].(map[string]any); ok {
for k := range bm["entries"].(map[string]any) {
entries = append(entries, k)
}
}
return map[string]any{"entries": entries}
}(),
"userMiracleTicketMap": map[string]any{"entries": map[string]any{}},
"userMiracleTicketExchangesMap": map[string]any{"entries": map[string]any{}},
"userMultiDisconnectionBadPenalty": nil,
"userSpecialLotteryDrawResultMap": nil,
"userMusicScoreMap": map[string]any{"entries": musicScoreEntries},
"userMusicAchievementMap": nil,
"userBirthdayStoryMap": func() map[string]any {
result := map[string]any{}
if bpm, ok := m["masterBirthdayPageMap"].(map[string]any); ok {
for _, v := range bpm["entries"].(map[string]any) {
item := v.(map[string]any)
if item["birthdayStoryId"] == nil {
continue
}
id := fmt.Sprintf("%v", item["birthdayStoryId"])
result[id] = map[string]any{
"userId": userid, "birthdayStoryId": item["birthdayStoryId"], "status": "already_read",
}
}
}
return map[string]any{"entries": result}
}(),
"userGenericAnimationMap": func() map[string]any {
result := map[string]any{}
if gam, ok := m["masterGenericAnimationMap"].(map[string]any); ok {
for id := range gam["entries"].(map[string]any) {
result[id] = map[string]any{"userId": userid, "genericAnimationId": id, "status": "already_read"}
}
}
return map[string]any{"entries": result}
}(),
"userMusicShopMap": func() map[string]any {
var entries []any
if ml, ok := m["masterMusicList"].(map[string]any); ok {
if songs, ok := ml["entries"].([]any); ok {
for i, v := range songs {
song := v.(map[string]any)
entries = append(entries, map[string]any{
"userId": userid, "musicShopId": i + 1, "shopId": 7,
"shopCategory": "common", "musicId": song["musicId"],
"status": "sold_out", "seq": i + 1, "isInitialDistribution": false,
})
}
}
}
return map[string]any{"entries": map[string]any{"7": map[string]any{"entries": entries}}}
}(),
"userTitleList": nil,
"userPurchaseVoidBadPenaltyStandard": nil,
"userSelectNewYearCardMap": nil,
"userGachaCountCeilingMap": nil,
"userBackstageTalkSetReadHistoryMap": nil,
"userNewMusicIntroductionMap": func() map[string]any {
result := map[string]any{}
if nm, ok := m["masterNewMusicIntroductionMap"].(map[string]any); ok {
if entries, ok := nm["entries"].(map[string]any); ok {
for _, v := range entries {
item := v.(map[string]any)
id := fmt.Sprintf("%v", item["newMusicIntroductionId"])
result[id] = map[string]any{
"userId": userid, "newMusicIntroductionId": item["newMusicIntroductionId"], "status": "already_read",
}
}
}
}
return map[string]any{"entries": result}
}(),
"userNewSituationIntroductionMap": func() map[string]any {
result := map[string]any{}
if nsi, ok := m["masterNewSituationIntroductionList"].(map[string]any); ok {
if entries, ok := nsi["entries"].([]any); ok {
for _, v := range entries {
if item, ok := v.(map[string]any); ok {
id := fmt.Sprintf("%v", item["newSituationIntroductionId"])
result[id] = map[string]any{
"userId": userid, "newSituationIntroductionId": item["newSituationIntroductionId"], "status": "already_read",
}
}
}
}
}
return map[string]any{"entries": result}
}(),
"userFriendRelationDetail": map[string]any{
"applicationMap": nil, "approvalMap": nil, "friendMap": nil,
"friendLimit": 50, "approvalLimit": 50, "applicationLimit": 50,
},
"userNotHaveViewExchangesMiracleTicketIdList": map[string]any{"entries": []any{}},
"userProfileSituation": nil,
"userProfileDegreeMap": map[string]any{"entries": userProfileDegree},
"userDecoFrameInventoryMap": map[string]any{"entries": decoFrameEntries},
"userDecoPinsInventoryMap": map[string]any{"entries": decoPinsEntries},
"userDecoEffectInventoryMap": map[string]any{"entries": decoEffectEntries},
"userDecoEquipment": utils.BuildDecoEquipment(userid, user, m),
"userMusicVideoListMap": func() map[string]any {
result := map[string]any{}
if mvlm, ok := m["masterMusicVideoListMap"].(map[string]any); ok {
for musicId := range mvlm["entries"].(map[string]any) {
result[musicId] = map[string]any{
"entries": []any{map[string]any{"userId": userid, "musicId": musicId, "seq": 1}},
}
}
}
return map[string]any{"userMusicVideoInventoryListMap": map[string]any{"entries": result}}
}(),
"userPurchaseMenuLastVisitMap": map[string]any{"entries": map[string]any{}},
"userSkinLaneMap": nil,
"currentUserEventMusicScoresMap": nil,
"currentUserEventMusicAchievementsMap": nil,
"currentUserEventBoxGachaMap": nil,
"userMonthlyPurchaseMap": nil,
"userSubscriptionList": nil,
"userCommentBannerList": nil,
"userEventBoxGachaSpinSettings": nil,
"userMorfonicaStoryList": storyList(userid, m["masterMorfonicaStoryMap"].(map[string]any)),
"userMatchingBonusList": nil,
"userRaiseASuilenStoryList": storyList(userid, m["masterRaiseASuilenStoryMap"].(map[string]any)),
"userCollaboOriginalMusicScoreMap": nil,
"userDailyLive": map[string]any{
"lastClearedAt": 0, "liveStartedAt": 0, "getDailyLiveRewardId": 6,
},
"userDailyLiveTotalRewardHistory": nil,
"userComebackStatus": nil,
"userGraphicalInformationList": nil,
"userMultiLiveCountRewardList": nil,
"userDigestStoryList": map[string]any{"entries": digestEntries},
"userLiveBoostUseBonusLimitList": nil,
"userReceivablePresentLocationList": nil,
"userPanelMissionList": nil,
"userBirthdayIntroductionMap": nil,
"userFestivalTeamMap": nil,
"userLimitedItemList": nil,
"userLimitedExchangesList": map[string]any{"entries": []any{}},
"userDeckList": map[string]any{"entries": decks},
"userAddMusicDifficultyIntroductionList": nil,
"userGalleryList": nil,
"userBandDeckRatingMap": nil,
"updatedBandDeckRankList": nil,
"userStageChallengeStageNoMap": nil,
"userStageChallengeMap": nil,
"userStageChallengeScoreMap": nil,
"userStarSeal": map[string]any{"amount": user["seal"]},
"userLiveBoostUseFull": map[string]any{"dailyUseFullCount": 67, "resetTime": 0},
"userAutoLive": map[string]any{"resetTime": 0},
"userMonthlyMission": nil,
"userMonthlyMissionRewardList": nil,
"userCharacterRankMap": utils.BuildCharacterRankMap(),
"userCharacterPotentialLevelMap": func() map[string]any {
result := map[string]any{}
for i := 1; i <= 40; i++ {
result[fmt.Sprintf("%d", i)] = map[string]any{
"performanceLevel": 1, "techniqueLevel": 1, "visualLevel": 1,
}
}
return map[string]any{"entries": result}
}(),
"userMusicVideo3dListMap": func() map[string]any {
result := map[string]any{}
if mv3m, ok := m["masterMusicVideo3dMap"].(map[string]any); ok {
for _, v := range mv3m["entries"].(map[string]any) {
mv := v.(map[string]any)
musicId := fmt.Sprintf("%v", mv["musicId"])
result[musicId] = map[string]any{
"entries": []any{map[string]any{
"musicVideo3dId": mv["musicVideo3dId"], "musicId": mv["musicId"], "seq": mv["seq"],
}},
}
}
}
return map[string]any{"userMusicVideo3dInventoryListMap": map[string]any{"entries": result}}
}(),
"userCostume3dDressInventoryMap": func() map[string]any {
result := map[string]any{}
if cdm, ok := m["masterCostume3dDressMap"].(map[string]any); ok {
for id := range cdm["entries"].(map[string]any) {
idInt, _ := strconv.Atoi(id)
result[id] = map[string]any{"costume3dDressId": idInt, "status": "obtained"}
}
}
return map[string]any{"entries": result}
}(),
"userCostume3dHairstyleInventoryMap": func() map[string]any {
result := map[string]any{}
if chm, ok := m["masterCostume3dHairstyleMap"].(map[string]any); ok {
for id := range chm["entries"].(map[string]any) {
idInt, _ := strconv.Atoi(id)
result[id] = map[string]any{"costume3dHairstyleId": idInt, "status": "obtained"}
}
}
return map[string]any{"entries": result}
}(),
"userWearingCostume3dMap": func() map[string]any {
result := map[string]any{}
for charId, v := range wc {
costume := v.(map[string]any)
result[charId] = map[string]any{
"characterId": charId,
"costume3dDressId": costume["dressId"],
"costume3dHairstyleId": costume["hairstyleId"],
}
}
return map[string]any{"entries": result}
}(),
"userMusicClearInfoMap": utils.ComputeMusicClearInfo(musicScore),
"userMusicClearCountInfoMap": utils.ComputeMusicClearCountInfo(musicScore),
"userCharacterSituationCountMap": nil,
"userDecoCharacterBackgroundInventoryMap": func() map[string]any {
result := map[string]any{}
if dcbm, ok := m["masterDecoCharacterBackgroundMap"].(map[string]any); ok {
for backgroundId := range dcbm["entries"].(map[string]any) {
result[backgroundId] = map[string]any{"userId": userid, "backgroundId": backgroundId}
}
}
return map[string]any{"entries": result}
}(),
"userDecoCharacter3dMotionInventoryListMap": func() map[string]any {
result := map[string]any{}
for charId, motionIds := range decoMotionMap {
entries := make([]any, len(motionIds))
for i, motionId := range motionIds {
entries[i] = map[string]any{"userId": userid, "motionId": motionId}
}
result[charId] = map[string]any{"entries": entries}
}
return map[string]any{"entries": result}
}(),
"userMusicVideo3dCustomDeckMap": nil,
"userCostume3dMakingItemInventoryMap": nil,
"userMusicVideo3dOriginalDeckCostumeMap": nil,
"userLimitBreakItemList": nil,
"userDecoAppealInventoryMap": nil,
"userInvitationInfo": nil,
"userCharacterUseStyleMap": func() map[string]any {
useCharacterId := 15
status := "normal"
if user["msk"] != nil {
msk := user["msk"].(map[string]any)
useCharacterId = int(func() float64 {
switch v := msk["useCharacterId"].(type) {
case float64:
return v
case int:
return float64(v)
}
return 0
}())
status = msk["status"].(string)
}
return map[string]any{
"entries": map[string]any{
"15": map[string]any{
"characterId": 15,
"useCharacterId": useCharacterId,
"status": status,
},
},
}
}(),
"userPurchaseStarList": nil,
"userInviteMissionListMap": nil,
"userGachaBonusMap": nil,
"userStampVoiceMap": func() map[string]any {
result := map[string]any{}
if sm, ok := m["masterStampMap"].(map[string]any); ok {
for stampId, v := range sm["entries"].(map[string]any) {
stamp := v.(map[string]any)
if _, ok := stamp["withVoice"]; ok {
result[stampId] = map[string]any{"userId": userid, "stampId": stampId}
}
}
}
return map[string]any{"entries": result}
}(),
"userEventRankedCountAppeal": nil,
"userEventMusicRankedCountAppeal": nil,
"userMyGoStoryList": storyList(userid, m["masterMyGoStoryMap"].(map[string]any)),
"userTerms": map[string]any{"userId": userid},
"userCharacterMissionBonusMap": nil,
"userPhotoStudioMap": nil,
"userGachaSelfPickupSituationList": nil,
"userPhotoBackInventoryMap": nil,
"userLimitedSkinInventoryMap": nil,
"userMusicClearCountDetailMap": nil,
}
encoded, err := pbutil.Encode("SuiteUserGetResponse", data)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString(err.Error())
}
c.Set("Content-Type", "application/octet-stream")
return c.Send(encrypted)
}
// helpers
func rangeInts(from, to int) []int {
result := make([]int, to-from+1)
for i := range result {
result[i] = from + i
}
return result
}
func deepCopy(src map[string]any) map[string]any {
b, _ := json.Marshal(src)
var dst map[string]any
json.Unmarshal(b, &dst)
return dst
}

View File

@@ -0,0 +1,121 @@
package param_userid
import (
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"math/rand"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, get)
app.Put(path, put)
fmt.Println("Loaded:", path)
})
}
func get(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
m := master.GetMaster()
areaMap := m["masterAreaMap"].(map[string]any)["entries"].(map[string]any)
actionSetMap := m["masterActionSetMap"].(map[string]any)["entries"].(map[string]any)
seasonMap := m["masterSeasonBasicMap"].(map[string]any)["entries"].(map[string]any)
// userAreaMap
resultEntries := map[string]any{}
for areaId, v := range areaMap {
area := v.(map[string]any)
if area["areaType"] != "common" {
continue
}
// filter actionSets by areaId
var available []any
for _, a := range actionSetMap {
action := a.(map[string]any)
if fmt.Sprintf("%v", action["areaId"]) == areaId {
available = append(available, action["actionSetId"])
}
}
// shuffle + slice
rand.Shuffle(len(available), func(i, j int) {
available[i], available[j] = available[j], available[i]
})
count := min(rand.Intn(3)+1, len(available))
actionSets := make([]any, 0)
for _, id := range available[:count] {
actionSets = append(actionSets, map[string]any{
"actionSetId": id,
"status": "already_read",
})
}
// areaItems
areaItems := []any{}
if user["areaItems"] != nil {
items := user["areaItems"].(map[string]any)
if v, ok := items[areaId]; ok {
areaItems = v.([]any)
}
}
resultEntries[areaId] = map[string]any{
"areaId": areaId,
"actionSets": actionSets,
"areaItemIds": areaItems,
}
}
// current season
now := time.Now().UnixMilli()
var seasonId any
for _, v := range seasonMap {
s := v.(map[string]any)
startAt, _ := strconv.ParseInt(s["startAt"].(string), 10, 64)
endAt, _ := strconv.ParseInt(s["endAt"].(string), 10, 64)
if startAt <= now && now < endAt {
seasonId = s["seasonId"]
break
}
}
data := map[string]any{
"userAreaMap": map[string]any{
"entries": resultEntries,
},
"backstage": nil,
"userSeason": map[string]any{
"seasonId": seasonId,
},
"userLotterySelectedBackstageTalkSetMap": nil,
}
encoded, err := pbutil.Encode("UserAreaCharacterResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}
func put(c *fiber.Ctx) error {
return c.SendStatus(200)
}

View File

@@ -0,0 +1,121 @@
package item
import (
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"math/rand"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, recommendedAreaItem)
fmt.Println("Loaded:", path)
})
}
func recommendedAreaItem(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("PutAreaItemRequestBody", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
m := master.GetMaster()
areaItemMap := m["masterAreaItemMap"].(map[string]any)["entries"].(map[string]any)
items := map[string]any{}
if idList, ok := decoded["areaItemIdList"].([]any); ok {
for _, id := range idList {
idStr := fmt.Sprintf("%v", id)
if entry, ok := areaItemMap[idStr].(map[string]any); ok {
areaId := fmt.Sprintf("%v", entry["areaId"])
if items[areaId] == nil {
items[areaId] = []any{}
}
items[areaId] = append(items[areaId].([]any), id)
}
}
}
user["areaItems"] = items
db.Save()
areaMap := m["masterAreaMap"].(map[string]any)["entries"].(map[string]any)
actionSetMap := m["masterActionSetMap"].(map[string]any)["entries"].(map[string]any)
var areaList []any
for areaId, v := range areaMap {
area, ok := v.(map[string]any)
if !ok || area["areaType"] != "common" {
continue
}
var available []any
for _, av := range actionSetMap {
a, ok := av.(map[string]any)
if !ok {
continue
}
if fmt.Sprintf("%v", a["areaId"]) == areaId {
available = append(available, a["actionSetId"])
}
}
rand.Shuffle(len(available), func(i, j int) {
available[i], available[j] = available[j], available[i]
})
count := rand.Intn(3) + 1
if count > len(available) {
count = len(available)
}
var actionSets []any
for _, id := range available[:count] {
actionSets = append(actionSets, map[string]any{
"actionSetId": id,
"status": "already_read",
})
}
areaItemIds := []any{}
if ids, ok := items[areaId]; ok {
areaItemIds = ids.([]any)
}
areaList = append(areaList, map[string]any{
"areaId": area["areaId"],
"actionSets": actionSets,
"areaItemIds": areaItemIds,
})
}
data := map[string]any{
"updateResources": map[string]any{},
"userAreaList": map[string]any{"entries": areaList},
}
encoded, err := pbutil.Encode("SuiteUserChangeAreaItemResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,20 @@
package actionset
import (
"bdgrp_go/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, actionSet)
fmt.Println("Loaded:", path)
})
}
func actionSet(c *fiber.Ctx) error {
return c.SendStatus(200)
}

View File

@@ -0,0 +1,69 @@
package style
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, handle)
fmt.Println("Loaded:", path)
})
}
func handle(c *fiber.Ctx) error {
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(500).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserCharacterChangeUseStyleStatusRequest", decrypted)
if err != nil {
return c.Status(500).SendString(err.Error())
}
user := db.FindUser(c.Params("userid"))
if user["msk"] == nil {
user["msk"] = map[string]any{}
}
msk := user["msk"].(map[string]any)
useCharacterId := 15
if decoded["status"] == "another" {
useCharacterId = 601
}
msk["useCharacterId"] = useCharacterId
msk["status"] = decoded["status"]
db.Save()
data := map[string]any{
"userCharacterUseStyleMap": map[string]any{
"entries": map[string]any{
"15": map[string]any{
"characterId": 15,
"useCharacterId": useCharacterId,
"status": msk["status"],
},
},
},
}
encoded, err := pbutil.Encode("SuiteUserGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,67 @@
package costume
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"strconv"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, changeCostume)
fmt.Println("Loaded:", path)
})
}
func changeCostume(c *fiber.Ctx) error {
userid := c.Params("userid")
costumeid := c.Params("costumeid")
characterid := c.Params("characterid")
user := db.FindUser(userid)
wearingCostume := user["wearingCostume"].(map[string]any)
costume := wearingCostume[characterid].(map[string]any)
cid, _ := strconv.Atoi(costumeid)
costume["costumeId"] = cid
db.Save()
charMap := map[string]any{}
for charId, v := range wearingCostume {
c2 := v.(map[string]any)
charMap[charId] = map[string]any{
"userId": userid,
"characterId": charId,
"costumeId": c2["costumeId"],
}
}
data := map[string]any{
"updateResources": map[string]any{
"userCharacterMap": map[string]any{"entries": charMap},
},
"userCharacter": map[string]any{
"userId": userid,
"characterId": characterid,
"costumeId": costumeid,
},
}
encoded, err := pbutil.Encode("SuiteUserCharacter", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,74 @@
package param_characterid
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, changeCostume3d)
fmt.Println("Loaded:", path)
})
}
func changeCostume3d(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserWearingCostume3d", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
charId := fmt.Sprintf("%v", decoded["characterId"])
wearingCostume := user["wearingCostume"].(map[string]any)
costume := wearingCostume[charId].(map[string]any)
costume["dressId"] = decoded["costume3dDressId"]
costume["hairstyleId"] = decoded["costume3dHairstyleId"]
db.Save()
wearingMap := map[string]any{}
for cid, v := range wearingCostume {
c2 := v.(map[string]any)
wearingMap[cid] = map[string]any{
"characterId": cid,
"costume3dDressId": c2["dressId"],
"costume3dHairstyleId": c2["hairstyleId"],
}
}
data := map[string]any{
"updateResources": map[string]any{
"userWearingCostume3dMap": map[string]any{"entries": wearingMap},
},
"userWearingCostume3d": map[string]any{
"characterId": decoded["characterId"],
"costume3dDressId": decoded["costume3dDressId"],
"costume3dHairstyleId": decoded["costume3dHairstyleId"],
},
}
encoded, err := pbutil.Encode("SuiteUserCostume3dChangeResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,66 @@
package param_userid
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, handle)
fmt.Println("Loaded:", path)
})
}
func handle(c *fiber.Ctx) error {
userid := c.Params("userid")
data := map[string]any{
"updateResources": map[string]any{
"updatedBandDeckRankList": map[string]any{},
"userDailyLive": map[string]any{
"lastClearedAt": 1770992661000,
"liveStartedAt": 1770992661000,
"getDailyLiveRewardId": 6,
},
"userDailyLiveTotalRewardHistory": map[string]any{
"userId": userid,
"dailyLiveId": 8,
"status": "STARTED",
"dailyLiveCount": 1,
},
},
"response": map[string]any{
"userDailyLive": map[string]any{
"lastClearedAt": 1770992661000,
"liveStartedAt": 1770992661000,
"getDailyLiveRewardId": 6,
"dailyPresents": []any{
map[string]any{
"resourceId": 43,
"resourceType": "practice_ticket",
"quantity": 1,
"lbBonus": 1,
},
},
},
},
}
encoded, err := pbutil.Encode("SuiteUserDailyLiveClearResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,99 @@
package deck
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, deck)
fmt.Println("Loaded:", path)
})
}
func deck(c *fiber.Ctx) error {
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
fmt.Println(err)
}
decoded, err := pbutil.Decode("EditUserDeckRequest", decrypted)
if err != nil {
fmt.Println(err)
}
userid := c.Params("userid")
user := db.FindUser(userid)
decks := user["decks"].([]any)
isNew := false
var deck map[string]any
for _, d := range decks {
d := d.(map[string]any)
if fmt.Sprintf("%v", d["deckId"]) == c.Params("deckid") {
deck = d
break
}
}
if deck == nil {
deck = map[string]any{
"deckId": c.Params("deckid"),
}
isNew = true
}
if v, ok := decoded["member1"].(float64); ok && v != 0 {
deck["member1"] = v
}
if v, ok := decoded["member2"].(float64); ok && v != 0 {
deck["member2"] = v
}
if v, ok := decoded["member3"].(float64); ok && v != 0 {
deck["member3"] = v
}
if v, ok := decoded["member4"].(float64); ok && v != 0 {
deck["member4"] = v
}
if v, ok := decoded["leader"].(float64); ok && v != 0 {
deck["leader"] = v
}
deck["deckName"] = decoded["deckName"].(string)
deck["deckType"] = decoded["deckType"].(string)
if isNew {
user["decks"] = append(user["decks"].([]any), deck)
}
db.Save()
data := map[string]any{
"updateResources": map[string]any{
"userDeckList": map[string]any{
"entries": user["decks"].([]any),
},
},
}
encoded, err := pbutil.Encode("EditUserDeckResponse", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,70 @@
package deco3d
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, deco3d)
fmt.Println("Loaded:", path)
})
}
func deco3d(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoCharacter3d", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
decos := user["decos"].(map[string]any)
decos["3d"] = map[string]any{
"characterId": decoded["characterId"],
"dressId": decoded["dressId"],
"hairstyleId": decoded["hairstyleId"],
"motionId": decoded["motionId"],
"backgroundId": decoded["backgroundId"],
}
db.Save()
deco3d := decos["3d"].(map[string]any)
data := map[string]any{
"updateResources": map[string]any{
"userDecoEquipment": map[string]any{
"userDecoCharacter3d": map[string]any{
"userId": userid,
"characterId": deco3d["characterId"],
"dressId": deco3d["dressId"],
"hairstyleId": deco3d["hairstyleId"],
"motionId": deco3d["motionId"],
"backgroundId": deco3d["backgroundId"],
},
},
},
}
encoded, err := pbutil.Encode("SuiteUserDecoCharacter3d", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,68 @@
package live2d
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, live2d)
fmt.Println("Loaded:", path)
})
}
func live2d(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoCharacterLive2d", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
decos := user["decos"].(map[string]any)
decos["live2d"] = map[string]any{
"characterId": decoded["characterId"],
"costumeId": decoded["costumeId"],
"motionId": decoded["motionId"],
"backgroundId": decoded["backgroundId"],
}
db.Save()
live2d := decos["live2d"].(map[string]any)
data := map[string]any{
"updateResources": map[string]any{
"userDecoEquipment": map[string]any{
"userDecoCharacterLive2d": map[string]any{
"userId": userid,
"characterId": live2d["characterId"],
"costumeId": live2d["costumeId"],
"motionId": live2d["motionId"],
"backgroundId": live2d["backgroundId"],
},
},
},
}
encoded, err := pbutil.Encode("SuiteUserDecoCharacterLive2d", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,66 @@
package situation
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, situation)
fmt.Println("Loaded:", path)
})
}
func situation(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoCharacterSituation", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
decos := user["decos"].(map[string]any)
decos["situation"] = map[string]any{
"situationId": decoded["situationId"],
"situationStatus": decoded["situationStatus"],
"useProfileSetting": decoded["useProfileSetting"],
}
db.Save()
sit := decos["situation"].(map[string]any)
data := map[string]any{
"updateResources": map[string]any{
"userDecoEquipment": map[string]any{
"userDecoCharacterSituation": map[string]any{
"userId": userid,
"situationId": sit["situationId"],
"situationStatus": sit["situationStatus"],
"useProfileSetting": sit["useProfileSetting"],
},
},
},
}
encoded, err := pbutil.Encode("SuiteUserDecoCharacterSituation", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,73 @@
package deco
import (
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"time"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, getEffect)
fmt.Println("Loaded:", path)
})
}
func getEffect(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
if user == nil {
return c.Status(404).SendStatus(404)
}
m := master.GetMaster()
now := time.Now().UnixMilli()
decoEffectEntries := map[string]any{}
if deMap, ok := m["masterDecoEffectList"].(map[string]any); ok {
if entries, ok := deMap["entries"].([]any); ok {
for _, v := range entries {
e := v.(map[string]any)
startAt := int64(0)
endAt := int64(0)
if s, ok := e["startAt"].(string); ok {
fmt.Sscanf(s, "%d", &startAt)
}
if s, ok := e["endAt"].(string); ok {
fmt.Sscanf(s, "%d", &endAt)
}
if startAt <= now && now <= endAt {
id := fmt.Sprintf("%v", e["decoEffectId"])
decoEffectEntries[id] = map[string]any{
"userId": userid,
"decoEffectId": e["decoEffectId"],
}
}
}
}
}
data := map[string]any{
"updateResources": map[string]any{
"userDecoEffectInventoryMap": map[string]any{"entries": decoEffectEntries},
"userDecoEquipment": utils.BuildDecoEquipment(userid, user, m),
},
}
encoded, err := pbutil.Encode("UserDecoEquipmentGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,59 @@
package effect
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, effect)
fmt.Println("Loaded:", path)
})
}
func effect(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoEffectRequestBody", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
decos := user["decos"].(map[string]any)
decos["effect"] = decoded["decoEffectId"]
db.Save()
data := map[string]any{
"updateResources": map[string]any{
"userDecoEquipment": map[string]any{
"userDecoEffect": map[string]any{
"userId": userid,
"decoEffectId": decos["effect"],
},
},
},
}
encoded, err := pbutil.Encode("SuiteUserDecoCharacterSituation", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,75 @@
package framepins
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, editFramePins)
fmt.Println("Loaded:", path)
})
}
func editFramePins(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoFramePinsRequestBody", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
pins := make([]any, 5)
for i := 0; i < 5; i++ {
key := fmt.Sprintf("decoPinsId%d", i+1)
if v, ok := decoded[key].(float64); ok && v > 0 {
pins[i] = v
} else {
pins[i] = 0
}
}
decos := user["decos"].(map[string]any)
decos["framepins"] = pins
decos["frameId"] = decoded["decoFrameId"]
db.Save()
data := map[string]any{
"updateResources": map[string]any{
"userDecoEquipment": map[string]any{
"userDecoFramePins": map[string]any{
"userId": userid,
"decoFrameId": decos["frameId"],
"decoPinsId1": pins[0],
"decoPinsId2": pins[1],
"decoPinsId3": pins[2],
"decoPinsId4": pins[3],
"decoPinsId5": pins[4],
},
},
},
}
encoded, err := pbutil.Encode("DecoFramePinsResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,59 @@
package character
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, useProfileSetting)
fmt.Println("Loaded:", path)
})
}
func useProfileSetting(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoSituationUseProfileSettingRequest", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
user["useProfileSettingSituation"] = decoded["useProfileSettingSituation"]
db.Save()
data := map[string]any{
"updateResources": map[string]any{
"userDecoEquipment": map[string]any{
"userDecoSetting": map[string]any{
"useProfileSettingDegree": user["useProfileSettingDegree"],
"useProfileSettingSituation": user["useProfileSettingSituation"],
"selectedCharacterType": user["selectedCharacterType"],
},
},
},
}
encoded, err := pbutil.Encode("UserDecoEquipmentGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,59 @@
package degree
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, useProfileSetting)
fmt.Println("Loaded:", path)
})
}
func useProfileSetting(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoDegreeUseProfileSettingRequest", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
user["useProfileSettingDegree"] = decoded["useProfileSettingDegree"]
db.Save()
data := map[string]any{
"updateResources": map[string]any{
"userDecoEquipment": map[string]any{
"userDecoSetting": map[string]any{
"useProfileSettingDegree": user["useProfileSettingDegree"],
"useProfileSettingSituation": user["useProfileSettingSituation"],
"selectedCharacterType": user["selectedCharacterType"],
},
},
},
}
encoded, err := pbutil.Encode("UserDecoEquipmentGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,48 @@
package friend
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, handle)
fmt.Println("Loaded:", path)
})
}
func handle(c *fiber.Ctx) error {
friendDetail := map[string]any{
"applicationMap": map[string]any{},
"approvalMap": map[string]any{},
"friendMap": map[string]any{},
"friendLimit": 60,
"approvalLimit": 50,
"applicationLimit": 50,
}
data := map[string]any{
"updateResources": map[string]any{
"userFriendRelationDetail": friendDetail,
},
"userFriendDetail": friendDetail,
}
encoded, err := pbutil.Encode("SuiteUserFriendTopResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,16 @@
package friend
import (
"bdgrp_go/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, handle)
fmt.Println("Loaded:", path)
})
}

View File

@@ -0,0 +1,16 @@
package friend
import (
"bdgrp_go/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, handle)
fmt.Println("Loaded:", path)
})
}

View File

@@ -0,0 +1,45 @@
package friend
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, relation)
fmt.Println("Loaded:", path)
})
}
func relation(c *fiber.Ctx) error {
data := map[string]any{
"updateResources": map[string]any{
"userFriendRelationDetail": map[string]any{
"applicationMap": nil,
"approvalMap": nil,
"friendMap": nil,
"friendLimit": 50,
"approvalLimit": 50,
"applicationLimit": 50,
},
},
}
encoded, err := pbutil.Encode("SuiteUserFriendRelationResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,92 @@
package gacha
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"math/rand"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, gacha)
fmt.Println("Loaded:", path)
})
}
func gacha(c *fiber.Ctx) error {
gachaid := c.Params("gachaid")
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserGachaRequest", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
m := master.GetMaster()
gachaMap := m["masterGachaMap"].(map[string]any)["entries"].(map[string]any)
gachaEntry, ok := gachaMap[gachaid].(map[string]any)
if !ok {
return c.Status(404).SendString("gacha not found")
}
var list []any
if details, ok := gachaEntry["details"].([]any); ok {
for _, d := range details {
detail := d.(map[string]any)
if detail["rarityIndex"].(float64) == 5 {
list = append(list, detail["situationId"])
}
}
}
paymentMethodId := decoded["paymentMethodId"]
count := 0
if methods, ok := gachaEntry["paymentMethods"].([]any); ok {
for _, pm := range methods {
method := pm.(map[string]any)
if fmt.Sprintf("%v", method["paymentMethodId"]) == fmt.Sprintf("%v", paymentMethodId) {
count = int(method["count"].(float64))
break
}
}
}
entries := make([]any, count)
for i := range entries {
entries[i] = map[string]any{
"situationId": list[rand.Intn(len(list))],
"isFirstGet": true,
}
}
data := map[string]any{
"gachaResults": map[string]any{
"entries": entries,
"extras": map[string]any{},
"beforeGachaSeal": 14,
"afterGachaSeal": 15,
"gachaGuaranteedRarity": "none",
},
"updateResources": map[string]any{},
}
encoded, err := pbutil.Encode("SuiteUserGachaResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,34 @@
package param_id
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, watch)
fmt.Println("Loaded:", path)
})
}
func watch(c *fiber.Ctx) error {
data := map[string]any{
"userGraphicalInformationList": map[string]any{},
}
encoded, err := pbutil.Encode("SuiteUserGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,20 @@
package param_userid
import (
"bdgrp_go/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, index)
fmt.Println("Loaded:", path)
})
}
func index(c *fiber.Ctx) error {
return c.SendStatus(200)
}

View File

@@ -0,0 +1,30 @@
package loginbonus
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, acceptAll)
fmt.Println("Loaded:", path)
})
}
func acceptAll(c *fiber.Ctx) error {
data := map[string]any{
"updateResources": map[string]any{},
}
encoded, _ := pbutil.Encode("SuiteUserLoginBonusAcceptAllResponse", data)
encrypted, _ := utils.Encrypt(encoded)
return c.Send(encrypted)
}

View File

@@ -0,0 +1,63 @@
package param_eventid
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, readStory)
fmt.Println("Loaded:", path)
})
}
func readStory(c *fiber.Ctx) error {
userid := c.Params("userid")
eventid := c.Params("eventid")
seq := c.Params("seq")
m := master.GetMaster()
server := os.Getenv("SERVER")
pastData, _ := os.ReadFile(filepath.Join("pastEvents", server+".json"))
var past map[string]any
json.Unmarshal(pastData, &past)
eventStoryEntries := utils.BuildEventStoryMemorialMap(userid, m, past)
data := map[string]any{
"updateResources": map[string]any{
"userEventStoryMemorialMap": map[string]any{"entries": eventStoryEntries},
},
"userStoryEventReadStoryResponse": map[string]any{
"readUserEventStory": map[string]any{
"userId": userid,
"eventId": eventid,
"seq": seq,
"status": "already_read",
},
"rewards": map[string]any{},
"newlyOpenedContents": map[string]any{},
},
}
encoded, err := pbutil.Encode("SuiteReadStoryResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,331 @@
package multiroom
import (
"fmt"
"strconv"
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, post)
fmt.Println("Loaded:", path)
})
}
var drops = []map[string]any{
{"resourceType": "coin", "quantity": 10000, "lbBonus": 20},
{"resourceId": 1, "resourceType": "practice_ticket", "quantity": 100, "lbBonus": 20},
{"resourceId": 2, "resourceType": "item", "quantity": 240, "lbBonus": 20},
{"resourceId": 1, "resourceType": "item", "quantity": 240, "lbBonus": 20},
{"resourceId": 3, "resourceType": "item", "quantity": 240, "lbBonus": 20},
{"resourceId": 8, "resourceType": "item", "quantity": 160, "lbBonus": 20},
{"resourceId": 7, "resourceType": "item", "quantity": 160, "lbBonus": 20},
{"resourceId": 8, "resourceType": "item", "quantity": 160, "lbBonus": 20},
}
func getMultiScoreRank(
score uint32,
difficultyMaster map[string]any,
multiDifficulty uint32,
) string {
if difficultyMaster == nil {
return "c"
}
multiMap, _ := difficultyMaster["multiLiveScoreMap"].(map[string]any)
target, _ := multiMap[strconv.FormatUint(uint64(multiDifficulty), 10)].(map[string]any)
if target == nil {
return "c"
}
getScore := func(key string) float64 {
switch value := target[key].(type) {
case float64:
return value
case uint32:
return float64(value)
case int:
return float64(value)
default:
return 0
}
}
value := float64(score)
switch {
case value >= getScore("scoreSS"):
return "ss"
case value >= getScore("scoreS"):
return "s"
case value >= getScore("scoreA"):
return "a"
case value >= getScore("scoreB"):
return "b"
default:
return "c"
}
}
func post(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserMultiRoomRequest", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
m := master.GetMaster()
if m == nil {
return c.Status(500).
SendString("master data unavailable")
}
musicId := uint32(decoded["musicId"].(float64))
musicIdString := strconv.FormatUint(uint64(musicId), 10)
difficulty := fmt.Sprintf("%v", decoded["musicDifficulty"])
score := uint32(decoded["score"].(float64))
multiScore := uint32(decoded["multiScore"].(float64))
multiDifficulty := uint32(decoded["multiDifficulty"].(float64))
musicScore, _ := user["musicScore"].(map[string]any)
if musicScore == nil {
musicScore = map[string]any{}
user["musicScore"] = musicScore
}
scoreData, _ := musicScore[musicIdString].(map[string]any)
if scoreData == nil {
scoreData = map[string]any{
"entries": []any{},
}
musicScore[musicIdString] = scoreData
}
entries, _ := scoreData["entries"].([]any)
diffMaster := utils.GetMusicInfo(
m,
musicIdString,
difficulty,
)
scoreInfo := map[string]any{
"userId": userid,
"musicId": musicId,
"musicDifficulty": difficulty,
"soloHighScore": score,
"maxCombo": decoded["combo"],
"soloScoreRank": utils.GetScoreRank(float64(score), diffMaster),
"clearStatus": decoded["clearStatus"],
}
found := false
for i, raw := range entries {
entry, ok := raw.(map[string]any)
if !ok {
continue
}
if fmt.Sprintf("%v", entry["musicDifficulty"]) != difficulty {
continue
}
found = true
oldScore, _ := entry["soloHighScore"].(float64)
if oldScore < float64(score) {
entries[i] = scoreInfo
}
break
}
if !found {
entries = append(entries, scoreInfo)
}
scoreData["entries"] = entries
db.Save()
decks, _ := user["decks"].([]any)
mainDeckIndex := 0
if value, ok := user["mainDeck"].(float64); ok && int(value) > 1 {
mainDeckIndex = int(value) - 1
}
if len(decks) == 0 || mainDeckIndex >= len(decks) {
return c.Status(500).
SendString("main deck unavailable")
}
mainDeck, _ := decks[mainDeckIndex].(map[string]any)
situationFields := []string{
"leader",
"member1",
"member2",
"member3",
"member4",
}
characterSituationMap, _ := m["masterCharacterSituationMap"].(map[string]any)
characterSituationEntries, _ := characterSituationMap["entries"].(map[string]any)
situationIDs := make([]any, 0)
characterIDs := make([]int, 0)
seenCharacters := map[int]bool{}
for _, field := range situationFields {
situationID, ok := mainDeck[field]
if !ok || situationID == nil {
continue
}
situationIDs = append(situationIDs, situationID)
entry, _ := characterSituationEntries[fmt.Sprintf("%v", situationID)].(map[string]any)
if entry == nil {
continue
}
characterID, ok := entry["characterId"].(float64)
if !ok {
continue
}
id := int(characterID)
if !seenCharacters[id] {
seenCharacters[id] = true
characterIDs = append(characterIDs, id)
}
}
userSituations := utils.BuildUserSituations(userid, m, user)
situationList := make([]any, 0)
for _, situationID := range situationIDs {
for _, raw := range userSituations {
situation, _ := raw.(map[string]any)
if fmt.Sprintf("%v", situation["situationId"]) ==
fmt.Sprintf("%v", situationID) {
situationList = append(situationList, situation)
break
}
}
}
characterRankEntries := map[string]any{}
for _, characterID := range characterIDs {
characterRankEntries[strconv.Itoa(characterID)] = map[string]any{
"rank": 100,
"exp": 0,
"addExp": 0,
"nextExp": 0,
"totalExp": 0,
"releasedPotentialLevel": 50,
}
}
data := map[string]any{
"updateResources": map[string]any{
"userMusicScoreMap": utils.BuildMusicScoreMap(user),
"userMusicClearInfoMap": utils.ComputeMusicClearInfo(
musicScore,
),
"userMusicClearCountInfoMap": utils.ComputeMusicClearCountInfo(
musicScore,
),
},
"drops": map[string]any{
"entries": drops,
},
"newlyOpenedContents": map[string]any{},
"userBandRankList": map[string]any{
"entries": []any{
map[string]any{
"userId": userid,
"bandId": 5,
"bandRank": 22,
"exp": 8280,
"addExp": 6000,
"totalExp": 101880,
"nextExp": 7520,
},
},
},
"userSituationList": map[string]any{
"entries": situationList,
},
"achievementRewards": map[string]any{},
"lbBonus": 20,
"lbUseCount": 10,
"soloScoreRank": utils.GetScoreRank(float64(score), diffMaster),
"multiScoreRank": getMultiScoreRank(multiScore, diffMaster, multiDifficulty),
"userMusicAchievementMap": map[string]any{},
"dairyLiveRewardReceive": "REWARDRECEIVE",
"limitedDrops": map[string]any{},
"updatedBandDeckRankList": map[string]any{
"entries": []any{
map[string]any{
"bandId": 5,
"beforeSymbol": "ss",
"beforeLevel": 1,
"afterSymbol": "ss",
"afterLevel": 1,
},
},
},
"livePoint": 114514,
"userCharacterRankMap": map[string]any{
"entries": characterRankEntries,
},
}
encoded, err := pbutil.Encode("SuiteUserMultiRoom", data)
if err != nil {
return c.Status(500).
SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).
SendString(err.Error())
}
c.Set("Content-Type", "application/octet-stream")
return c.Send(encrypted)
}

View File

@@ -0,0 +1,237 @@
package music
import (
"fmt"
"strconv"
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, put)
fmt.Println("Loaded:", path)
})
}
var drops = []map[string]any{
{"resourceType": "coin", "quantity": 10000, "lbBonus": 20},
{"resourceId": 1, "resourceType": "practice_ticket", "quantity": 100, "lbBonus": 20},
{"resourceId": 2, "resourceType": "item", "quantity": 240, "lbBonus": 20},
{"resourceId": 1, "resourceType": "item", "quantity": 240, "lbBonus": 20},
{"resourceId": 3, "resourceType": "item", "quantity": 240, "lbBonus": 20},
{"resourceId": 8, "resourceType": "item", "quantity": 160, "lbBonus": 20},
{"resourceId": 7, "resourceType": "item", "quantity": 160, "lbBonus": 20},
{"resourceId": 8, "resourceType": "item", "quantity": 160, "lbBonus": 20},
}
func put(c *fiber.Ctx) error {
userid := c.Params("userid")
musicid := c.Params("musicid")
user := db.FindUser(userid)
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(400).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserMusicRequest", decrypted)
if err != nil {
return c.Status(400).SendString(err.Error())
}
m := master.GetMaster()
if m == nil {
return c.Status(500).SendString("master data unavailable")
}
musicScore, _ := user["musicScore"].(map[string]any)
if musicScore == nil {
musicScore = map[string]any{}
user["musicScore"] = musicScore
}
scoreData, _ := musicScore[musicid].(map[string]any)
if scoreData == nil {
scoreData = map[string]any{"entries": []any{}}
musicScore[musicid] = scoreData
}
entries, _ := scoreData["entries"].([]any)
difficulty := fmt.Sprintf("%v", decoded["musicDifficulty"])
score := uint32(decoded["score"].(float64))
diffMaster := utils.GetMusicInfo(m, musicid, difficulty)
scoreInfo := map[string]any{
"userId": userid,
"musicId": musicid,
"musicDifficulty": difficulty,
"soloHighScore": score,
"maxCombo": decoded["combo"],
"soloScoreRank": utils.GetScoreRank(float64(score), diffMaster),
"clearStatus": decoded["clearStatus"],
}
first := true
for i, raw := range entries {
entry, ok := raw.(map[string]any)
if !ok || fmt.Sprintf("%v", entry["musicDifficulty"]) != difficulty {
continue
}
first = false
oldScore, _ := entry["soloHighScore"].(float64)
if oldScore < float64(score) {
entries[i] = scoreInfo
}
break
}
if first {
entries = append(entries, scoreInfo)
}
scoreData["entries"] = entries
db.Save()
decks, _ := user["decks"].([]any)
mainDeckIndex := 0
if value, ok := user["mainDeck"].(float64); ok && int(value) > 1 {
mainDeckIndex = int(value) - 1
}
if len(decks) == 0 || mainDeckIndex >= len(decks) {
return c.Status(500).SendString("main deck unavailable")
}
mainDeck, _ := decks[mainDeckIndex].(map[string]any)
situationFields := []string{"leader", "member1", "member2", "member3", "member4"}
characterSituationMap, _ := m["masterCharacterSituationMap"].(map[string]any)
characterSituationEntries, _ := characterSituationMap["entries"].(map[string]any)
situationIDs := make([]any, 0)
seen := map[int]bool{}
characterIDs := make([]int, 0)
for _, field := range situationFields {
sid, ok := mainDeck[field]
if !ok || sid == nil {
continue
}
situationIDs = append(situationIDs, sid)
entry, _ := characterSituationEntries[fmt.Sprintf("%v", sid)].(map[string]any)
if entry == nil {
continue
}
if cid, ok := entry["characterId"].(float64); ok {
id := int(cid)
if !seen[id] {
seen[id] = true
characterIDs = append(characterIDs, id)
}
}
}
userSituations := utils.BuildUserSituations(userid, m, user)
situationList := make([]any, 0)
for _, sid := range situationIDs {
for _, raw := range userSituations {
situation, _ := raw.(map[string]any)
if fmt.Sprintf("%v", situation["situationId"]) == fmt.Sprintf("%v", sid) {
situationList = append(situationList, situation)
break
}
}
}
characterRankEntries := map[string]any{}
for _, characterID := range characterIDs {
characterRankEntries[strconv.Itoa(characterID)] = map[string]any{
"rank": 100, "exp": 0, "addExp": 0,
"nextExp": 0, "totalExp": 0,
"releasedPotentialLevel": 50,
}
}
responseMusicScore := utils.BuildMusicScoreMap(user)
if first {
scoreMap := responseMusicScore["entries"].(map[string]any)
musicResponse := scoreMap[musicid].(map[string]any)
responseEntries := musicResponse["entries"].([]any)
for _, raw := range responseEntries {
entry := raw.(map[string]any)
if fmt.Sprintf("%v", entry["musicDifficulty"]) == difficulty {
entry["soloHighScore"] = uint32(0)
}
}
}
data := map[string]any{
"updateResources": map[string]any{
"userMusicScoreMap": responseMusicScore,
"userMusicClearInfoMap": utils.ComputeMusicClearInfo(musicScore),
"userMusicClearCountInfoMap": utils.ComputeMusicClearCountInfo(musicScore),
},
"drops": map[string]any{"entries": drops},
"newlyOpenedContents": map[string]any{},
"userBandRankList": map[string]any{
"entries": []any{map[string]any{
"userId": userid, "bandId": 5, "bandRank": 22,
"exp": 8280, "addExp": 6000,
"totalExp": 101880, "nextExp": 7520,
}},
},
"userSituationList": map[string]any{"entries": situationList},
"achievementRewards": map[string]any{},
"lbBonus": 20,
"lbUseCount": 10,
"soloScoreRank": utils.GetScoreRank(float64(score), diffMaster),
"userMusicAchievementMap": map[string]any{},
"dairyLiveRewardReceive": "REWARDRECEIVE",
"limitedDrops": map[string]any{},
"updatedBandDeckRankList": map[string]any{
"entries": []any{map[string]any{
"bandId": 5, "beforeSymbol": "ss",
"beforeLevel": 1, "afterSymbol": "ss",
"afterLevel": 1,
}},
},
"livePoint": 114514,
"userCharacterRankMap": map[string]any{
"entries": characterRankEntries,
},
}
encoded, err := pbutil.Encode("SuiteUserMusic", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
c.Set("Content-Type", "application/octet-stream")
return c.Send(encrypted)
}

View File

@@ -0,0 +1,51 @@
package watching
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, watch)
fmt.Println("Loaded:", path)
})
}
func watch(c *fiber.Ctx) error {
userid := c.Params("userid")
m := master.GetMaster()
entries := map[string]any{}
if nm, ok := m["masterNewMusicIntroductionMap"].(map[string]any); ok {
for _, v := range nm["entries"].(map[string]any) {
item := v.(map[string]any)
id := fmt.Sprintf("%v", item["newMusicIntroductionId"])
entries[id] = map[string]any{
"userId": userid,
"newMusicIntroductionId": item["newMusicIntroductionId"],
"status": "already_read",
}
}
}
data := map[string]any{
"userNewMusicIntroductionMap": map[string]any{"entries": entries},
}
encoded, err := pbutil.Encode("SuiteUserGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,53 @@
package watching
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, watch)
fmt.Println("Loaded:", path)
})
}
func watch(c *fiber.Ctx) error {
userid := c.Params("userid")
m := master.GetMaster()
entries := map[string]any{}
if nsi, ok := m["masterNewSituationIntroductionList"].(map[string]any); ok {
if list, ok := nsi["entries"].([]any); ok {
for _, v := range list {
item := v.(map[string]any)
id := fmt.Sprintf("%v", item["newSituationIntroductionId"])
entries[id] = map[string]any{
"userId": userid,
"newSituationIntroductionId": item["newSituationIntroductionId"],
"status": "already_read",
}
}
}
}
data := map[string]any{
"userNewSituationIntroductionMap": map[string]any{"entries": entries},
}
encoded, err := pbutil.Encode("SuiteUserGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,79 @@
package profile
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, handle)
fmt.Println("Loaded:", path)
})
}
func handle(c *fiber.Ctx) error {
userid := c.Params("userid")
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(500).SendString(err.Error())
}
decoded, err := pbutil.Decode("UserDecoDegreeRequest", decrypted)
if err != nil {
return c.Status(500).SendString(err.Error())
}
user := db.FindUser(userid)
degree := user["degree"].([]any)
entries := map[string]any{}
degree[0] = decoded["degreeIdFirst"]
entries["first"] = map[string]any{
"userId": userid,
"profileDegreeType": "first",
"degreeId": degree[0],
}
if v, ok := decoded["degreeIdSecond"]; ok && v != nil && v != "" {
degree[1] = v
entries["second"] = map[string]any{
"userId": userid,
"profileDegreeType": "second",
"degreeId": degree[1],
}
} else {
degree[1] = nil
}
user["degree"] = degree
db.Save()
data := map[string]any{
"updateResources": map[string]any{
"userProfileDegreeMap": map[string]any{
"entries": entries,
},
},
}
encoded, err := pbutil.Encode("SuiteUserDecoDegreeResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,57 @@
package system
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"os"
"strconv"
"time"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, application)
fmt.Println("Loaded:", path)
})
}
func application(c *fiber.Ctx) error {
var offset int
server := os.Getenv("SERVER")
switch server {
case "TW", "CN":
offset = 28800000
break
case "JP":
offset = 32400000
break
case "GL":
offset = 0
break
}
data := map[string]any{
"serverDate": strconv.FormatInt(time.Now().Add(27*time.Hour).UnixMilli(), 10),
"timeZoneRawOffset": offset,
}
encoded, err := pbutil.Encode("ServerSystem", data)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString("")
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,49 @@
package system
import (
"bdgrp_go/routes/upstream"
"fmt"
"os"
"path/filepath"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, config)
fmt.Println("Loaded:", path)
})
}
func config(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
cachePath := filepath.Join("resp", server, "config.binpb")
headers := map[string]string{
"User-Agent": c.Get("User-Agent"),
"Content-Type": c.Get("Content-Type"),
"Accept": c.Get("Accept"),
"Accept-Encoding": c.Get("Accept-Encoding"),
"x-clientversion": c.Get("x-clientversion"),
"x-platformid": c.Get("x-platformid"),
"x-deviceid": c.Get("x-deviceid"),
"x-channelid": c.Get("x-channelid"),
"x-clientplatform": c.Get("x-clientplatform"),
}
data, err := upstream.Fetch("https://l3-prod-all-bd.bilibiligame.net/api/system/config", headers)
if err != nil {
data, err = os.ReadFile(cachePath)
if err != nil {
return c.Status(500).SendString("no cache available")
}
} else {
os.WriteFile(cachePath, data, 0644)
}
return c.Send(data)
}

View File

@@ -0,0 +1,90 @@
package tcpServer
import (
"bdgrp_go/routes"
"crypto/tls"
"fmt"
"io"
"net/http"
"strings"
"github.com/gofiber/fiber/v2"
)
var skipReqHeaders = map[string]bool{
"transfer-encoding": true,
"connection": true,
"keep-alive": true,
"content-encoding": true,
"content-length": true,
"cf-connecting-ip": true,
"cf-ray": true,
"cf-visitor": true,
"cf-ipcountry": true,
"cf-pseudo-ipv4": true,
"x-forwarded-for": true,
"x-forwarded-proto": true,
"x-real-ip": true,
"cdn-loop": true,
}
var skipRespHeaders = map[string]bool{
"transfer-encoding": true,
"connection": true,
"keep-alive": true,
"content-encoding": true,
"content-length": true,
}
var client = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, handle)
fmt.Println("Loaded:", path)
})
}
func handle(c *fiber.Ctx) error {
userid := c.Params("userid")
url := fmt.Sprintf("https://l3-prod-all-bd.bilibiligame.net/api/tcpServer/%s", userid)
req, err := http.NewRequest("POST", url, strings.NewReader(string(c.Body())))
if err != nil {
return c.Status(500).SendString(err.Error())
}
c.Request().Header.VisitAll(func(k, v []byte) {
key := strings.ToLower(string(k))
if !skipReqHeaders[key] {
req.Header.Set(string(k), string(v))
}
})
req.Header.Set("host", "l3-prod-all-bd.bilibiligame.net")
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString(err.Error())
}
defer resp.Body.Close()
for key, values := range resp.Header {
if !skipRespHeaders[strings.ToLower(key)] {
c.Set(key, values[0])
}
}
c.Response().Header.Del("Content-Length")
body, err := io.ReadAll(resp.Body)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(body)
}

21
routes/api/track.go Normal file
View File

@@ -0,0 +1,21 @@
package api
import (
"fmt"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, track)
fmt.Println("Loaded:", path)
})
}
func track(c *fiber.Ctx) error {
return c.SendString("")
}

View File

@@ -0,0 +1,21 @@
package heart
import (
"fmt"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, heart)
fmt.Println("Loaded:", path)
})
}
func heart(c *fiber.Ctx) error {
return c.SendString("")
}

140
routes/api/user/index.go Normal file
View File

@@ -0,0 +1,140 @@
package user
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"maps"
"os"
"time"
"github.com/google/uuid"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, postUser)
fmt.Println("Loaded:", path)
})
}
func postUser(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
fmt.Println(err)
}
decoded, err := pbutil.Decode("UserPostRequest", decrypted)
if err != nil {
fmt.Println(err)
}
var (
userName string
introduction string
)
switch server {
case "TW":
userName = "新人工作人員"
introduction = "你好!"
case "JP":
userName = "新人スタッフ"
introduction = "よろしくお願いします!"
case "GL":
userName = "New Staff"
introduction = "Nice to meet you!"
}
hash := uuid.New().String()
users := db.DB.Users[server]
nextId := 1001
if len(users) > 0 {
last := users[len(users)-1]
if id, ok := last["userId"].(float64); ok {
nextId = int(id) + 1
}
}
newUser := map[string]any{
"userId": nextId,
"hash": hash,
"userName": userName,
"clientVersion": decoded["clientVersion"].(string),
"platform": decoded["platform"].(string),
"deviceModel": decoded["deviceModel"].(string),
"operatingSystem": decoded["operatingSystem"].(string),
"birthMonth": "199001",
"tutorialStatus": "end",
"introduction": introduction,
"unknownString": "standard",
"tutorialEndedAt": time.Now().UnixMilli(),
}
newGamedata := map[string]any{
"rank": 114,
"exp": 67,
"coin": 114514,
"mainDeck": 1,
"paidStar": 0,
"freeStar": 514,
"seal": 0,
"degree": []any{100, nil},
"publishTotalDeckPowerFlg": false,
"publishBandRankFlg": false,
"publishMusicClearedFlg": false,
"publishMusicFullComboFlg": false,
"publishHighScoreRatingFlg": false,
"pooledExp": 0,
"totalExp": 0,
"nextExp": 0,
"publishUpdatedAtFlg": true,
"startDashLoginBonusReceiveFlg": false,
"publishMusicAllPerfectFlg": false,
"publishDeckRankFlg": false,
"publishStageAchievementConditionsFlg": false,
"publishStageFriendRankingFlg": true,
"publishCharacterRankFlg": false,
"loginDays": 0,
"useProfileSettingDegree": true,
"useProfileSettingSituation": true,
"selectedCharacterType": "character_situation",
}
maps.Copy(newUser, newGamedata)
db.DB.Users[server] = append(db.DB.Users[server], newUser)
db.Save()
data := map[string]any{
"userId": fmt.Sprintf("%v", newUser["userId"]),
"hash": newUser["hash"],
"userName": newUser["userName"],
"clientVersion": newUser["clientVersion"],
"platform": newUser["platform"],
"deviceModel": newUser["deviceModel"],
"operatingSystem": newUser["operatingSystem"],
"tutorialStatus": newUser["tutorialStatus"],
"introduction": newUser["introduction"],
"tutorialEndedAt": fmt.Sprintf("%v", newUser["tutorialEndedAt"]),
}
encoded, err := pbutil.Encode("UserRegistration", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

130
routes/api/user/login.go Normal file
View File

@@ -0,0 +1,130 @@
package user
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"maps"
"os"
"time"
"github.com/google/uuid"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, login)
fmt.Println("Loaded:", path)
})
}
func login(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
fmt.Println(err)
}
decoded, err := pbutil.Decode("UserLogin", decrypted)
if err != nil {
fmt.Println(err)
}
user := db.FindUser(fmt.Sprintf("%v", decoded["bid"]), db.Bid)
if user == nil {
hash := uuid.New().String()
users := db.DB.Users[server]
nextId := 1001
if len(users) > 0 {
last := users[len(users)-1]
if id, ok := last["userId"].(float64); ok {
nextId = int(id) + 1
}
}
newUser := map[string]any{
"bid": decoded["bid"].(string),
"userId": nextId,
"hash": hash,
"userName": "新手工作人员",
"clientVersion": decoded["clientVersion"].(string),
"platform": decoded["platform"].(string),
"deviceModel": decoded["deviceModel"].(string),
"operatingSystem": decoded["operatingSystem"].(string),
"birthMonth": "199001",
"tutorialStatus": "end",
"introduction": "请多多关照!",
"unknownString": "standard",
"tutorialEndedAt": time.Now().UnixMilli(),
}
newGamedata := map[string]any{
"rank": 114,
"exp": 67,
"coin": 114514,
"mainDeck": 1,
"paidStar": 0,
"freeStar": 514,
"seal": 0,
"degree": []any{100, nil},
"publishTotalDeckPowerFlg": false,
"publishBandRankFlg": false,
"publishMusicClearedFlg": false,
"publishMusicFullComboFlg": false,
"publishHighScoreRatingFlg": false,
"pooledExp": 0,
"totalExp": 0,
"nextExp": 0,
"publishUpdatedAtFlg": true,
"startDashLoginBonusReceiveFlg": false,
"publishMusicAllPerfectFlg": false,
"publishDeckRankFlg": false,
"publishStageAchievementConditionsFlg": false,
"publishStageFriendRankingFlg": true,
"publishCharacterRankFlg": false,
"loginDays": 0,
"useProfileSettingDegree": true,
"useProfileSettingSituation": true,
"selectedCharacterType": "character_situation",
}
maps.Copy(newUser, newGamedata)
db.DB.Users[server] = append(db.DB.Users[server], newUser)
db.Save()
user = newUser
}
data := map[string]any{
"userId": fmt.Sprintf("%v", user["userId"]),
"hash": user["hash"],
"userName": user["userName"],
"clientVersion": user["clientVersion"],
"platform": user["platform"],
"deviceModel": user["deviceModel"],
"operatingSystem": user["operatingSystem"],
"tutorialStatus": user["tutorialStatus"],
"introduction": user["introduction"],
"tutorialEndedAt": fmt.Sprintf("%v", user["tutorialEndedAt"]),
}
encoded, err := pbutil.Encode("UserRegistration", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,59 @@
package user
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, get)
app.Put(path, putUser)
fmt.Println("Loaded:", path)
})
}
func get(c *fiber.Ctx) error {
return c.SendString("")
}
func putUser(c *fiber.Ctx) error {
decrypted, _ := utils.Decrypt(c.Body())
decoded, err := pbutil.Decode("UserPutRequest", decrypted)
if err != nil {
fmt.Println(err)
}
userId := c.Params("userid")
user := db.FindUser(userId)
if v, ok := decoded["userName"].(string); ok && v != "" {
user["userName"] = v
}
if v, ok := decoded["birthMonth"].(string); ok && v != "" {
user["birthMonth"] = v
}
if v, ok := decoded["introduction"].(string); ok && v != "" {
user["introduction"] = v
}
if v, ok := decoded["tutorialStatus"].(string); ok && v != "" {
user["tutorialStatus"] = v
}
if v, ok := decoded["mainDeck"].(float64); ok && v != 0 {
user["mainDeck"] = uint64(v)
}
if v, ok := decoded["degree"].(float64); ok && v != 0 {
user["degree"] = uint32(v)
}
db.Save()
return c.SendString("")
}

View File

@@ -0,0 +1,64 @@
package album
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"strconv"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, albumMap)
fmt.Println("Loaded:", path)
})
}
func albumMap(c *fiber.Ctx) error {
characterid, _ := strconv.Atoi(c.Params("characterid"))
m := master.GetMaster()
entries := map[string]any{}
if asm, ok := m["masterActionSetMap"].(map[string]any); ok {
for key, v := range asm["entries"].(map[string]any) {
item, ok := v.(map[string]any)
if !ok {
continue
}
charIds, ok := item["characterIds"].([]any)
if !ok {
continue
}
for _, cid := range charIds {
if int(cid.(float64)) == characterid {
entry := map[string]any{
"actionSetId": item["actionSetId"],
"balloonText": item["balloonText"],
}
if _, ok := item["endSeason"]; ok {
entry["isMemorial"] = true
}
entries[key] = entry
break
}
}
}
}
encoded, err := pbutil.Encode("UserActionSetAlbumMap", map[string]any{"entries": entries})
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,59 @@
package area
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, handle)
fmt.Println("Loaded:", path)
})
}
func handle(c *fiber.Ctx) error {
userid := c.Params("userid")
m := master.GetMaster()
areaMap := m["masterAreaMap"].(map[string]any)
entries := areaMap["entries"].(map[string]any)
// .filter(area.areaType === "common").map(...)
resultEntries := map[string]any{}
for areaId, v := range entries {
area := v.(map[string]any)
if area["areaType"] != "common" {
continue
}
resultEntries[areaId] = map[string]any{
"userId": userid,
"areaId": areaId,
}
}
data := map[string]any{
"registerTimeOpenAreaIdList": nil,
"userAreaStatusMap": map[string]any{
"entries": resultEntries,
},
}
encoded, err := pbutil.Encode("RegisterTimeOpenAreaResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,70 @@
package param_userid
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"crypto/sha1"
"fmt"
"os"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, Auth)
fmt.Println("Loaded:", path)
})
}
func Auth(c *fiber.Ctx) error {
server := os.Getenv("SERVER")
userid := c.Params("userid")
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
return c.Status(500).SendString("")
}
decoded, err := pbutil.Decode("UserAuthRequest", decrypted)
if err != nil {
return c.Status(500).SendString("")
}
hash := fmt.Sprintf("%x", sha1.Sum([]byte(userid+":")))
errData := map[string]any{
"httpStatus": 403,
"errorCode": "",
"errorMessage": "signature invalid.",
}
sendErr := func() error {
encoded, _ := pbutil.Encode("ClientErrorResponse", errData)
encrypted, _ := utils.Encrypt(encoded)
return c.Status(403).Send(encrypted)
}
user := db.FindUser(userid)
if hash != decoded["hash1"] || user == nil {
return sendErr()
}
if c.Get("x-signature") != user["hash"] {
return sendErr()
}
// 更新 clientVersion
for i, u := range db.DB.Users[server] {
if fmt.Sprintf("%v", u["userId"]) == userid {
db.DB.Users[server][i]["clientVersion"] = c.Get("x-clientversion")
break
}
}
db.Save()
return c.Send(nil)
}

View File

@@ -0,0 +1,69 @@
package bandstory
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, handle)
fmt.Println("Loaded:", path)
})
}
var bandStoryKeys = map[string]string{
"1": "masterPoppinPartyStoryMap",
"2": "masterAfterglowStoryMap",
"3": "masterHelloHappyWorldStoryMap",
"4": "masterPastelPalettesStoryMap",
"5": "masterRoseliaStoryMap",
"18": "masterRaiseASuilenStoryMap",
"21": "masterMorfonicaStoryMap",
"45": "masterMyGoStoryMap",
}
func handle(c *fiber.Ctx) error {
userid := c.Params("userid")
bandid := c.Params("bandid")
m := master.GetMaster()
key, _ := bandStoryKeys[bandid]
storyMap := m[key].(map[string]any)
entries := storyMap["entries"].(map[string]any)
var result []any
for _, v := range entries {
story := v.(map[string]any)
result = append(result, map[string]any{
"userId": userid,
"bandStoryId": story["bandStoryId"],
"bandId": story["bandId"],
"status": "already_read",
"seq": story["seq"],
})
}
data := map[string]any{
"entries": result,
}
encoded, err := pbutil.Encode("UserBandStoryList", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,55 @@
package device
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, updateDevice)
fmt.Println("Loaded:", path)
})
}
func updateDevice(c *fiber.Ctx) error {
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
fmt.Println(err)
}
decoded, err := pbutil.Decode("DeviceInfoUpdateRequest", decrypted)
userid := c.Params("userid")
user := db.FindUser(userid)
user["deviceModel"] = decoded["deviceModel"]
user["operatingSystem"] = decoded["operatingSystem"]
db.Save()
data := map[string]any{
"deviceModel": user["deviceModel"],
"operatingSystem": user["operatingSystem"],
"clientVersion": user["clientVersion"],
}
encoded, err := pbutil.Encode("UserRegistration", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,21 @@
package param_userid
import (
"fmt"
"bdgrp_go/routes"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, fcm)
fmt.Println("Loaded:", path)
})
}
func fcm(c *fiber.Ctx) error {
return c.SendString("")
}

View File

@@ -0,0 +1,51 @@
package genericanimation
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, animation)
fmt.Println("Loaded:", path)
})
}
func animation(c *fiber.Ctx) error {
userid := c.Params("userid")
m := master.GetMaster()
entries := map[string]any{}
if gam, ok := m["masterGenericAnimationMap"].(map[string]any); ok {
for id := range gam["entries"].(map[string]any) {
entries[id] = map[string]any{
"userId": userid,
"genericAnimationId": id,
"status": "already_read",
}
}
}
data := map[string]any{
"userGenericAnimationMap": map[string]any{"entries": entries},
}
encoded, err := pbutil.Encode("SuiteUserGetResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,87 @@
package param_userid
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, GetUser)
fmt.Println("Loaded:", path)
})
}
func GetUser(c *fiber.Ctx) error {
userid := c.Params("userid")
user := db.FindUser(userid)
if user == nil {
return c.Status(404).SendString("")
}
userId := fmt.Sprintf("%v", user["userId"])
data := map[string]any{
"userRegistration": map[string]any{
"userId": userId,
"hash": user["hash"],
"userName": user["userName"],
"clientVersion": user["clientVersion"],
"platform": user["platform"],
"deviceModel": user["deviceModel"],
"operatingSystem": user["operatingSystem"],
"birthMonth": user["birthMonth"],
"tutorialStatus": user["tutorialStatus"],
"introduction": user["introduction"],
"tutorialEndedAt": fmt.Sprintf("%v", user["tutorialEndedAt"]),
},
"userGamedata": map[string]any{
"userId": userId,
"rank": user["rank"],
"exp": user["exp"],
"coin": fmt.Sprintf("%v", user["coin"]),
"mainDeck": user["mainDeck"],
"paidStar": user["paidStar"],
"freeStar": user["freeStar"],
"seal": user["seal"],
"degree": user["degree"].([]any)[0],
"publishTotalDeckPowerFlg": user["publishTotalDeckPowerFlg"],
"publishBandRankFlg": user["publishBandRankFlg"],
"publishMusicClearedFlg": user["publishMusicClearedFlg"],
"publishMusicFullComboFlg": user["publishMusicFullComboFlg"],
"publishHighScoreRatingFlg": user["publishHighScoreRatingFlg"],
"pooledExp": fmt.Sprintf("%v", user["pooledExp"]),
"totalExp": fmt.Sprintf("%v", user["totalExp"]),
"nextExp": user["nextExp"],
"publishUpdatedAtFlg": user["publishUpdatedAtFlg"],
"userPaidStarRecallResponse": nil,
"startDashLoginBonusReceiveFlg": user["startDashLoginBonusReceiveFlg"],
"publishMusicAllPerfectFlg": user["publishMusicAllPerfectFlg"],
"publishDeckRankFlg": user["publishDeckRankFlg"],
"publishStageAchievementConditionsFlg": user["publishStageAchievementConditionsFlg"],
"publishStageFriendRankingFlg": user["publishStageFriendRankingFlg"],
"publishCharacterRankFlg": user["publishCharacterRankFlg"],
"loginDays": user["loginDays"],
},
}
encoded, err := pbutil.Encode("UserGetResponse", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,40 @@
package param_userid
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"time"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, liveBoost)
fmt.Println("Loaded:", path)
})
}
func liveBoost(c *fiber.Ctx) error {
data := map[string]any{
"userId": c.Params("userId"),
"liveBoost": 67,
"serverDate": time.Now().UnixMilli(),
"liveBoostBonusType": "default",
}
encoded, err := pbutil.Encode("UserLiveBoost", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,39 @@
package param_userid
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, liveFever)
fmt.Println("Loaded:", path)
})
}
func liveFever(c *fiber.Ctx) error {
data := map[string]any {
"userId": c.Params("userId"),
"count": 67,
"inActivity": true,
"limit": 3,
}
encoded, err := pbutil.Encode("UserLiveFeverCount", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,38 @@
package param_userid
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, mainDeck)
fmt.Println("Loaded:", path)
})
}
func mainDeck(c *fiber.Ctx) error {
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
fmt.Println(err)
}
decoded, err := pbutil.Decode("UserPutRequest", decrypted)
userid := c.Params("userid")
user := db.FindUser(userid)
user["mainDeck"] = decoded["mainDeck"]
db.Save()
return c.Send(nil)
}

View File

@@ -0,0 +1,50 @@
package param_userid
import (
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"encoding/json"
"fmt"
"maps"
"os"
"path/filepath"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, getMemorialStory)
fmt.Println("Loaded:", path)
})
}
func getMemorialStory(c *fiber.Ctx) error {
userid := c.Params("userid")
m := master.GetMaster()
server := os.Getenv("SERVER")
pastData, _ := os.ReadFile(filepath.Join("pastEvents", server+".json"))
var past map[string]any
json.Unmarshal(pastData, &past)
data := map[string]any{
"userEventStoryMemorialMap": map[string]any{
"entries": utils.BuildEventStoryMemorialMap(userid, m, past),
},
}
maps.Copy(data, past)
encoded, err := pbutil.Encode("UserEventStoryMemorialResponse", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,20 @@
package param_userid
import (
"bdgrp_go/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, recruitment)
fmt.Println("Loaded:", path)
})
}
func recruitment(c *fiber.Ctx) error {
return c.SendStatus(200)
}

View File

@@ -0,0 +1,20 @@
package music
import (
"bdgrp_go/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, music)
fmt.Println("Loaded:", path)
})
}
func music(c *fiber.Ctx) error {
return c.SendStatus(200)
}

View File

@@ -0,0 +1,82 @@
package param_musicid
import (
"bdgrp_go/db"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"crypto/sha1"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, musicContinue)
fmt.Println("Loaded:", path)
})
}
func musicContinue(c *fiber.Ctx) error {
userid := c.Params("userid")
decrypted, err := utils.Decrypt(c.Body())
if err != nil {
fmt.Println(err)
}
decoded, err := pbutil.Decode("UserMusicContinueRequest", decrypted)
if err != nil {
fmt.Println(err)
}
user := db.FindUser(userid)
str := userid + decoded["continueCount"].(string) + decoded["continueTime"].(string)
data := map[string]any{
"userGamedata": map[string]any{
"userId": userid,
"rank": user["rank"],
"exp": user["exp"],
"coin": user["coin"],
"mainDeck": user["mainDeck"],
"paidStar": user["paidStar"],
"freeStar": user["freeStar"],
"seal": user["seal"],
"degree": user["degree"],
"publishTotalDeckPowerFlg": user["publishTotalDeckPowerFlg"],
"publishBandRankFlg": user["publishBandRankFlg"],
"publishMusicClearedFlg": user["publishMusicClearedFlg"],
"publishMusicFullComboFlg": user["publishMusicFullComboFlg"],
"publishHighScoreRatingFlg": user["publishHighScoreRatingFlg"],
"pooledExp": user["pooledExp"],
"totalExp": user["totalExp"],
"nextExp": user["nextExp"],
"publishUpdatedAtFlg": user["publishUpdatedAtFlg"],
"userPaidStarRecallResponse": nil,
"startDashLoginBonusReceiveFlg": user["startDashLoginBonusReceiveFlg"],
"publishMusicAllPerfectFlg": user["publishMusicAllPerfectFlg"],
"publishDeckRankFlg": user["publishDeckRankFlg"],
"publishStageAchievementConditionsFlg": user["publishStageAchievementConditionsFlg"],
"publishStageFriendRankingFlg": user["publishStageFriendRankingFlg"],
"publishCharacterRankFlg": user["publishCharacterRankFlg"],
"loginDays": user["loginDays"],
},
"continueHash": fmt.Sprintf("%x", sha1.Sum([]byte(str))),
}
encoded, err := pbutil.Encode("UserMusicContinueResponse", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,20 @@
package param_musicid
import (
"bdgrp_go/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, retry)
fmt.Println("Loaded:", path)
})
}
func retry(c *fiber.Ctx) error {
return c.SendStatus(200)
}

View File

@@ -0,0 +1,40 @@
package param_userid
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, present)
fmt.Println("Loaded:", path)
})
}
func present(c *fiber.Ctx) error {
data := map[string]any{
"pagination": map[string]any{
"start": 9223372036854775807,
"limit": c.Query("limit"),
"record": 0,
},
}
encoded, err := pbutil.Encode("UserPresentLimit", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,40 @@
package param_userid
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Get(path, presentHistory)
fmt.Println("Loaded:", path)
})
}
func presentHistory(c *fiber.Ctx) error {
data := map[string]any{
"pagination": map[string]any{
"start": 9223372036854775807,
"limit": c.Query("limit"),
"record": 0,
},
}
encoded, err := pbutil.Encode("UserPresentHistoryList", data)
if err != nil {
fmt.Println(err)
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,99 @@
package profile
import (
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, profile)
fmt.Println("Loaded:", path)
})
}
func profile(c *fiber.Ctx) error {
userid := c.Params("usrid")
user := db.FindUser(userid)
m := master.GetMaster()
userSituations := utils.BuildUserSituations(userid, m, user)
situationMap := map[string]any{}
for _, sit := range userSituations {
s := sit.(map[string]any)
situationMap[fmt.Sprintf("%v", s["situationId"])] = s
}
decks := user["decks"].([]any)
mainDeckIdx := 1
if md, ok := user["mainDeck"].(float64); ok {
mainDeckIdx = int(md)
}
mainDeck := decks[mainDeckIdx-1].(map[string]any)
situationIdFields := []string{"leader", "member1", "member2", "member3", "member4"}
var mainDeckSituations []any
for _, field := range situationIdFields {
if sid, ok := mainDeck[field]; ok && sid != nil {
sidStr := fmt.Sprintf("%v", sid)
if s, ok := situationMap[sidStr]; ok {
mainDeckSituations = append(mainDeckSituations, s)
}
}
}
userProfileDegree := utils.BuildUserProfileDegree(userid, user)
musicScore, _ := user["musicScore"].(map[string]any)
data := map[string]any{
"userName": user["userName"],
"rank": user["rank"],
"degree": 100,
"introduction": user["introduction"],
"searchableFlg": true,
"publishUpdatedAtFlg": true,
"friendApplicableFlg": true,
"publishStageChallengeFriendRankingFlg": true,
"mainDeckUserSituations": map[string]any{"entries": mainDeckSituations},
"enabledUserAreaItems": map[string]any{},
"bandRankMap": map[string]any{"entries": utils.BandRankMap},
"userHighScoreRating": map[string]any{
"userPoppinPartyHighScoreMusicList": map[string]any{},
"userPastelPalettesHighScoreMusicList": map[string]any{},
"userRoseliaHighScoreMusicList": map[string]any{},
"userOtherHighScoreMusicList": map[string]any{},
"userMorfonicaHighScoreMusicList": map[string]any{},
"userRaiseASuilenHighScoreMusicList": map[string]any{},
"userMyGOScoreMusicList": map[string]any{},
},
"mainUserDeck": mainDeck,
"userProfileSituation": map[string]any{},
"userProfileDegreeMap": map[string]any{"entries": userProfileDegree},
"userTwitter": map[string]any{},
"userDeckTotalRatingMap": map[string]any{"entries": utils.DeckRatingMap},
"stageChallengeAchievementConditionsMap": map[string]any{},
"userMusicClearInfoMap": utils.ComputeMusicClearInfo(musicScore),
"userCharacterRankMap": utils.BuildCharacterRankMap(),
}
encoded, err := pbutil.Encode("UserProfile", data)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,109 @@
package search
import (
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, profileSearch)
fmt.Println("Loaded:", path)
})
}
func profileSearch(c *fiber.Ctx) error {
targetid := c.Params("targetid")
user := db.FindUser(targetid)
var data map[string]any
if user == nil {
data = map[string]any{"searchSuccessFlg": false}
} else {
m := master.GetMaster()
userid := fmt.Sprintf("%v", user["userId"])
userSituations := utils.BuildUserSituations(userid, m, user)
situationMap := map[string]any{}
for _, sit := range userSituations {
s := sit.(map[string]any)
situationMap[fmt.Sprintf("%v", s["situationId"])] = s
}
decks := user["decks"].([]any)
mainDeckIdx := 1
if md, ok := user["mainDeck"].(float64); ok {
mainDeckIdx = int(md)
}
mainDeck := decks[mainDeckIdx-1].(map[string]any)
situationIdFields := []string{"leader", "member1", "member2", "member3", "member4"}
var mainDeckSituations []any
for _, field := range situationIdFields {
if sid, ok := mainDeck[field]; ok && sid != nil {
sidStr := fmt.Sprintf("%v", sid)
if s, ok := situationMap[sidStr]; ok {
mainDeckSituations = append(mainDeckSituations, s)
}
}
}
userProfileDegree := utils.BuildUserProfileDegree(userid, user)
musicScore, _ := user["musicScore"].(map[string]any)
data = map[string]any{
"userProfile": map[string]any{
"userName": user["userName"],
"rank": user["rank"],
"degree": 100,
"introduction": user["introduction"],
"searchableFlg": true,
"publishUpdatedAtFlg": true,
"friendApplicableFlg": true,
"publishStageChallengeFriendRankingFlg": true,
"mainDeckUserSituations": map[string]any{"entries": mainDeckSituations},
"enabledUserAreaItems": map[string]any{},
"bandRankMap": map[string]any{"entries": utils.BandRankMap},
"userHighScoreRating": map[string]any{
"userPoppinPartyHighScoreMusicList": map[string]any{},
"userPastelPalettesHighScoreMusicList": map[string]any{},
"userRoseliaHighScoreMusicList": map[string]any{},
"userOtherHighScoreMusicList": map[string]any{},
"userMorfonicaHighScoreMusicList": map[string]any{},
"userRaiseASuilenHighScoreMusicList": map[string]any{},
"userMyGOScoreMusicList": map[string]any{},
},
"mainUserDeck": mainDeck,
"userProfileSituation": map[string]any{},
"userProfileDegreeMap": map[string]any{"entries": userProfileDegree},
"userTwitter": map[string]any{},
"userDeckTotalRatingMap": map[string]any{"entries": utils.DeckRatingMap},
"stageChallengeAchievementConditionsMap": map[string]any{},
"userMusicClearInfoMap": utils.ComputeMusicClearInfo(musicScore),
"userCharacterRankMap": utils.BuildCharacterRankMap(),
},
}
}
encoded, err := pbutil.Encode("UserProfileSearchResponse", data)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,112 @@
package illust
import (
"bdgrp_go/db"
"bdgrp_go/master"
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Put(path, setIllust)
fmt.Println("Loaded:", path)
})
}
func setIllust(c *fiber.Ctx) error {
userid := c.Params("userid")
situationid := c.Params("situationid")
illust := c.Params("illust")
user := db.FindUser(userid)
situationIllust, _ := user["situationIllust"].(map[string]any)
if situationIllust == nil {
situationIllust = map[string]any{}
user["situationIllust"] = situationIllust
}
situationIllust[situationid] = illust
db.Save()
m := master.GetMaster()
charSituationMap := m["masterCharacterSituationMap"].(map[string]any)["entries"].(map[string]any)
var sit map[string]any
for _, v := range charSituationMap {
s := v.(map[string]any)
if fmt.Sprintf("%v", s["situationId"]) == situationid {
sit = s
break
}
}
if sit == nil {
return c.Status(404).SendString("situation not found")
}
maxLevel := 0
if paramMap, ok := sit["parameterMap"].(map[string]any); ok {
for k := range paramMap {
var level int
fmt.Sscanf(k, "%d", &level)
if level > maxLevel {
maxLevel = level
}
}
}
rarity, _ := sit["rarity"].(float64)
hasTraining := rarity >= 3
data := map[string]any{
"userId": userid,
"situationId": sit["situationId"],
"level": maxLevel,
"exp": 0,
"createdAt": sit["releasedAt"],
"addExp": 0,
"trainingStatus": map[bool]string{true: "done", false: "not_doing"}[hasTraining],
"duplicateCount": 0,
"illust": illust,
"skillExp": 0,
"skillLevel": 5,
"limitBreakRank": 0,
}
if hasTraining {
training, _ := sit["training"].(map[string]any)
appendParam := map[string]any{
"userId": userid,
"situationId": sit["situationId"],
"characterPotentialPerformance": 30,
"characterPotentialTechnique": 30,
"characterPotentialVisual": 30,
"characterBonusPerformance": 30,
"characterBonusTechnique": 30,
"characterBonusVisual": 30,
}
if training != nil {
appendParam["performance"] = training["trainingPerformance"]
appendParam["technique"] = training["trainingTechnique"]
appendParam["visual"] = training["trainingVisual"]
}
data["userAppendParameter"] = appendParam
}
encoded, err := pbutil.Encode("UserSituation", data)
if err != nil {
return c.Status(500).SendString(err.Error())
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
return c.Status(500).SendString(err.Error())
}
return c.Send(encrypted)
}

View File

@@ -0,0 +1,38 @@
package validation
import (
"bdgrp_go/pbutil"
"bdgrp_go/routes"
"bdgrp_go/utils"
"fmt"
"github.com/gofiber/fiber/v2"
)
func init() {
path := routes.PathOf()
routes.Register(func(app *fiber.App) {
app.Post(path, ngword)
fmt.Println("Loaded:", path)
})
}
func ngword(c *fiber.Ctx) error {
data := map[string]any{
"isBadWord": false,
}
encoded, err := pbutil.Encode("NgWordResponse", data)
if err != nil {
fmt.Println(err)
return c.Status(500).SendString("")
}
encrypted, err := utils.Encrypt(encoded)
if err != nil {
fmt.Println(err)
}
return c.Send(encrypted)
}

23
routes/helper.go Normal file
View File

@@ -0,0 +1,23 @@
package routes
import (
"regexp"
"runtime"
"strings"
)
func PathOf() string {
_, file, _, _ := runtime.Caller(1)
idx := strings.Index(file, "routes/")
path := file[idx+len("routes"):]
path = strings.TrimSuffix(path, ".go")
if strings.HasSuffix(path, "/index") {
path = strings.TrimSuffix(path, "index")
}
re := regexp.MustCompile(`param_(\w+)`)
path = re.ReplaceAllString(path, ":$1")
return path
}

17
routes/registry.go Normal file
View File

@@ -0,0 +1,17 @@
package routes
import "github.com/gofiber/fiber/v2"
type RouteHandler func(*fiber.App)
var registry []RouteHandler
func Register(handler RouteHandler) {
registry = append(registry, handler)
}
func LoadAll(app *fiber.App) {
for _, handler := range registry {
handler(app)
}
}

View File

@@ -0,0 +1,31 @@
package upstream
import (
"io"
"net/http"
"os"
)
var BaseUrls = map[string]string{
"TW": "https://v1010-bd.mobimon.com.tw",
"JP": "https://api.garupa.jp",
"GL": "https://api.app-bang-dream-gbp.com",
"CN": "https://l3-prod-all-bd.bilibiligame.net",
}
func Fetch(url string, headers map[string]string) ([]byte, error) {
req, _ := http.NewRequest("GET", url, nil)
for k, v := range headers {
req.Header.Set(k, v)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
func BaseUrl() string {
return BaseUrls[os.Getenv("SERVER")]
}

81
utils/crypto.go Normal file
View File

@@ -0,0 +1,81 @@
package utils
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
"os"
)
var keys = map[string]string{
"TW": "mikumikulukaluka",
"JP": "mikumikulukaluka",
"GL": "RXzFAC87WR28eNcP",
"CN": "wakakabiliwakaka",
}
var ivs = map[string]string{
"TW": "lukalukamikumiku",
"JP": "lukalukamikumiku",
"GL": "hrk0k7knXlit3S_y",
"CN": "biliwakakawohaha",
}
func getKeyIV() ([]byte, []byte, error) {
server := os.Getenv("SERVER")
key, ok := keys[server]
if !ok {
return nil, nil, fmt.Errorf("unknown server: %s", server)
}
return []byte(key), []byte(ivs[server]), nil
}
func Decrypt(buf []byte) ([]byte, error) {
key, iv, err := getKeyIV()
if err != nil {
return nil, err
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(buf)%aes.BlockSize != 0 {
return nil, fmt.Errorf("invalid block size")
}
decrypted := make([]byte, len(buf))
cipher.NewCBCDecrypter(block, iv).CryptBlocks(decrypted, buf)
// 手動移除 padding(setAutoPadding(false) 對應)
padLen := int(decrypted[len(decrypted)-1])
if padLen > 0 && padLen <= 16 && padLen <= len(decrypted) {
decrypted = decrypted[:len(decrypted)-padLen]
}
return decrypted, nil
}
func Encrypt(buf []byte) ([]byte, error) {
key, iv, err := getKeyIV()
if err != nil {
return nil, err
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
// 手動加 PKCS7 padding(setAutoPadding(true) 對應)
blockSize := block.BlockSize()
padding := blockSize - len(buf)%blockSize
padded := append(buf, bytes.Repeat([]byte{byte(padding)}, padding)...)
encrypted := make([]byte, len(padded))
cipher.NewCBCEncrypter(block, iv).CryptBlocks(encrypted, padded)
return encrypted, nil
}

507
utils/helper.go Normal file
View File

@@ -0,0 +1,507 @@
package utils
import "fmt"
func ComputeMusicClearInfo(musicScore map[string]any) map[string]any {
difficulties := []string{"easy", "normal", "hard", "expert", "special"}
type stat struct{ cleared, fullCombo, allPerfect int }
stats := map[string]*stat{}
for _, d := range difficulties {
stats[d] = &stat{}
}
for _, v := range musicScore {
data := v.(map[string]any)
entries, ok := data["entries"].([]any)
if !ok {
continue
}
for _, e := range entries {
entry := e.(map[string]any)
diff, _ := entry["musicDifficulty"].(string)
clearStatus, _ := entry["clearStatus"].(string)
if s, ok := stats[diff]; ok {
s.cleared++
if clearStatus == "full_combo" {
s.fullCombo++
}
if clearStatus == "all_perfect" {
s.allPerfect++
}
}
}
}
result := map[string]any{}
for _, d := range difficulties {
result[d] = map[string]any{
"clearedMusicCount": stats[d].cleared,
"fullComboMusicCount": stats[d].fullCombo,
"allPerfectMusicCount": stats[d].allPerfect,
}
}
return map[string]any{"entries": result}
}
func ComputeMusicClearCountInfo(musicScore map[string]any) map[string]any {
result := map[string]any{}
for id, v := range musicScore {
data := v.(map[string]any)
entries, ok := data["entries"].([]any)
if ok && len(entries) > 0 {
result[id] = len(entries)
}
}
return map[string]any{"entries": result}
}
func BuildUserSituations(userid string, master map[string]any, user map[string]any) []any {
situationMap := master["masterCharacterSituationMap"].(map[string]any)["entries"].(map[string]any)
var result []any
for _, v := range situationMap {
card := v.(map[string]any)
releasedAt := fmt.Sprintf("%v", card["releasedAt"])
if releasedAt == "4128645600000" || releasedAt == "4131237600000" {
continue
}
// maxLevel
maxLevel := 0
if paramMap, ok := card["parameterMap"].(map[string]any); ok {
for k := range paramMap {
var level int
fmt.Sscanf(k, "%d", &level)
if level > maxLevel {
maxLevel = level
}
}
}
rarity := 0
if r, ok := card["rarity"].(float64); ok {
rarity = int(r)
}
hasTraining := rarity >= 3
var ep0, ep1 map[string]any
if eps, ok := card["episodes"].(map[string]any); ok {
if entries, ok := eps["entries"].([]any); ok {
if len(entries) > 0 {
ep0, _ = entries[0].(map[string]any)
}
if len(entries) > 1 {
ep1, _ = entries[1].(map[string]any)
}
}
}
illust := "normal"
if hasTraining {
illust = "after_training"
}
if user != nil {
if si, ok := user["situationIllust"].(map[string]any); ok {
if v, ok := si[fmt.Sprintf("%v", card["situationId"])]; ok {
illust = fmt.Sprintf("%v", v)
}
}
}
trainingStatus := "not_doing"
if hasTraining {
trainingStatus = "done"
}
sit := map[string]any{
"userId": userid,
"situationId": card["situationId"],
"level": maxLevel,
"exp": 0,
"createdAt": card["releasedAt"],
"addExp": 0,
"trainingStatus": trainingStatus,
"duplicateCount": 0,
"illust": illust,
"skillExp": 0,
"skillLevel": 5,
"limitBreakRank": 4,
}
if hasTraining {
t, _ := card["training"].(map[string]any)
perf, tech, vis := 0.0, 0.0, 0.0
if t != nil {
perf, _ = t["trainingPerformance"].(float64)
tech, _ = t["trainingTechnique"].(float64)
vis, _ = t["trainingVisual"].(float64)
}
ep0Perf, ep0Tech, ep0Vis := 0.0, 0.0, 0.0
ep1Perf, ep1Tech, ep1Vis := 0.0, 0.0, 0.0
if ep0 != nil {
ep0Perf, _ = ep0["appendPerformance"].(float64)
ep0Tech, _ = ep0["appendTechnique"].(float64)
ep0Vis, _ = ep0["appendVisual"].(float64)
}
if ep1 != nil {
ep1Perf, _ = ep1["appendPerformance"].(float64)
ep1Tech, _ = ep1["appendTechnique"].(float64)
ep1Vis, _ = ep1["appendVisual"].(float64)
}
sit["userAppendParameter"] = map[string]any{
"userId": userid,
"situationId": card["situationId"],
"performance": perf,
"technique": tech,
"visual": vis,
"characterPotentialPerformance": 30,
"characterPotentialTechnique": 30,
"characterPotentialVisual": 30,
"characterBonusPerformance": 30 + ep0Perf + ep1Perf,
"characterBonusTechnique": 30 + ep0Tech + ep1Tech,
"characterBonusVisual": 30 + ep0Vis + ep1Vis,
}
}
result = append(result, sit)
}
return result
}
func BuildUserProfileDegree(userid string, user map[string]any) map[string]any {
degree := user["degree"].([]any)
result := map[string]any{
"first": map[string]any{
"userId": userid,
"profileDegreeType": "first",
"degreeId": degree[0],
},
}
if len(degree) > 1 && degree[1] != nil {
result["second"] = map[string]any{
"userId": userid,
"profileDegreeType": "second",
"degreeId": degree[1],
}
}
return result
}
func BuildCharacterRankMap() map[string]any {
entries := map[string]any{}
for i := 1; i <= 40; i++ {
entries[fmt.Sprintf("%d", i)] = map[string]any{
"rank": 100, "exp": 0, "addExp": 0,
"nextExp": 0, "totalExp": 0, "releasedPotentialLevel": 50,
}
}
return map[string]any{"entries": entries}
}
func GetScoreRank(score float64, difficultyMaster map[string]any) string {
if difficultyMaster == nil {
return "c"
}
get := func(key string) float64 {
v, _ := difficultyMaster[key].(float64)
return v
}
switch {
case score >= get("scoreSS"):
return "ss"
case score >= get("scoreS"):
return "s"
case score >= get("scoreA"):
return "a"
case score >= get("scoreB"):
return "b"
default:
return "c"
}
}
func BuildDecoEquipment(userid string, user map[string]any, m map[string]any) map[string]any {
decos, _ := user["decos"].(map[string]any)
if decos == nil {
decos = map[string]any{}
}
wc, _ := user["wearingCostume"].(map[string]any)
decks := user["decks"].([]any)
mainDeckIdx := 1
if md, ok := user["mainDeck"].(float64); ok {
mainDeckIdx = int(md)
}
mainDeck := decks[mainDeckIdx-1].(map[string]any)
charSituationMap := m["masterCharacterSituationMap"].(map[string]any)["entries"].(map[string]any)
leaderSitId := fmt.Sprintf("%v", mainDeck["leader"])
leaderEntry, _ := charSituationMap[leaderSitId].(map[string]any)
leaderCharId := any(nil)
leaderCharIdStr := ""
if leaderEntry != nil {
leaderCharId = leaderEntry["characterId"]
leaderCharIdStr = fmt.Sprintf("%v", leaderCharId)
}
decoSit, _ := decos["situation"].(map[string]any)
decoSitId := any(1)
decoSitStatus := any("normal")
if decoSit != nil {
decoSitId = decoSit["situationId"]
decoSitStatus = decoSit["situationStatus"]
}
decoL2d, _ := decos["live2d"].(map[string]any)
l2dCharId := leaderCharId
l2dCostumeId := any(nil)
if wc != nil && wc[leaderCharIdStr] != nil {
l2dCostumeId = wc[leaderCharIdStr].(map[string]any)["costumeId"]
}
l2dMotionId := any(nil)
if decoL2dMap, ok := m["masterDecoCharacterLive2dMotionMap"].(map[string]any); ok {
var firstMotion map[string]any
for _, v := range decoL2dMap["entries"].(map[string]any) {
mot := v.(map[string]any)
if fmt.Sprintf("%v", mot["characterId"]) == leaderCharIdStr {
if firstMotion == nil || mot["seq"].(float64) < firstMotion["seq"].(float64) {
firstMotion = mot
}
}
}
if firstMotion != nil {
l2dMotionId = firstMotion["motionId"]
}
}
l2dBackgroundId := any(1)
if decoL2d != nil {
if v, ok := decoL2d["characterId"]; ok {
l2dCharId = v
}
if v, ok := decoL2d["costumeId"]; ok {
l2dCostumeId = v
}
if v, ok := decoL2d["motionId"]; ok {
l2dMotionId = v
}
if v, ok := decoL2d["backgroundId"]; ok {
l2dBackgroundId = v
}
}
deco3d, _ := decos["3d"].(map[string]any)
d3dCharId := leaderCharId
d3dDressId := any(nil)
d3dHairstyleId := any(nil)
if wc != nil && wc[leaderCharIdStr] != nil {
d3dDressId = wc[leaderCharIdStr].(map[string]any)["dressId"]
d3dHairstyleId = wc[leaderCharIdStr].(map[string]any)["hairstyleId"]
}
d3dMotionId := any(nil)
if em3Map, ok := m["masterEnableCharacter3dMotionTypeMap"].(map[string]any); ok {
if charEntry, ok := em3Map["entries"].(map[string]any)[leaderCharIdStr].(map[string]any); ok {
if decoEntry, ok := charEntry["entries"].(map[string]any)["deco"].(map[string]any); ok {
if entries, ok := decoEntry["entries"].([]any); ok {
var first map[string]any
for _, e := range entries {
entry := e.(map[string]any)
if first == nil || entry["seq"].(float64) < first["seq"].(float64) {
first = entry
}
}
if first != nil {
d3dMotionId = first["motionId"]
}
}
}
}
}
d3dBackgroundId := any(11)
if deco3d != nil {
if v, ok := deco3d["characterId"]; ok {
d3dCharId = v
}
if v, ok := deco3d["dressId"]; ok {
d3dDressId = v
}
if v, ok := deco3d["hairstyleId"]; ok {
d3dHairstyleId = v
}
if v, ok := deco3d["motionId"]; ok {
d3dMotionId = v
}
if v, ok := deco3d["backgroundId"]; ok {
d3dBackgroundId = v
}
}
frameId := any(1)
if v, ok := decos["frameId"]; ok {
frameId = v
}
framepins, _ := decos["framepins"].([]any)
getPin := func(i int) any {
if framepins != nil && i < len(framepins) {
return framepins[i]
}
return nil
}
userProfileDegree := BuildUserProfileDegree(userid, user)
decoProfileDegree := map[string]any{}
for k, v := range userProfileDegree {
entry := v.(map[string]any)
decoProfileDegree[k] = map[string]any{
"decoFrameId": entry["userId"],
"profileDegreeType": entry["profileDegreeType"],
"degreeId": entry["degreeId"],
}
}
decoEffectId := any(1)
if v, ok := decos["effect"]; ok {
decoEffectId = v
}
return map[string]any{
"userDecoCharacterSituation": map[string]any{
"userId": userid,
"situationId": decoSitId,
"situationStatus": decoSitStatus,
},
"userDecoCharacterLive2d": map[string]any{
"userId": userid,
"characterId": l2dCharId,
"costumeId": l2dCostumeId,
"motionId": l2dMotionId,
"backgroundId": l2dBackgroundId,
},
"userDecoCharacter3d": map[string]any{
"userId": userid,
"characterId": d3dCharId,
"dressId": d3dDressId,
"hairstyleId": d3dHairstyleId,
"motionId": d3dMotionId,
"backgroundId": d3dBackgroundId,
},
"userDecoFramePins": map[string]any{
"userId": userid,
"decoFrameId": frameId,
"decoPinsId1": getPin(0),
"decoPinsId2": getPin(1),
"decoPinsId3": getPin(2),
"decoPinsId4": getPin(3),
"decoPinsId5": getPin(4),
},
"userDecoDegreeMap": map[string]any{"entries": decoProfileDegree},
"userDecoAppealMap": map[string]any{},
"userDecoSetting": map[string]any{
"useProfileSettingDegree": user["useProfileSettingDegree"],
"useProfileSettingSituation": user["useProfileSettingSituation"],
"selectedCharacterType": user["selectedCharacterType"],
},
"userDecoEffect": map[string]any{
"userId": userid,
"decoEffectId": decoEffectId,
},
}
}
func BuildEventStoryMemorialMap(userid string, m map[string]any, past map[string]any) map[string]any {
entries := map[string]any{}
pastStoryEntries := map[string]any{}
if pse, ok := past["pastEventStoryMap"].(map[string]any); ok {
if e, ok := pse["entries"].(map[string]any); ok {
pastStoryEntries = e
}
}
if escMap, ok := m["masterEventStoryMemorialConfigMap"].(map[string]any); ok {
for eventId := range escMap["entries"].(map[string]any) {
length := 0
if pe, ok := pastStoryEntries[eventId].(map[string]any); ok {
if en, ok := pe["entries"].([]any); ok {
length = len(en)
}
}
storyEntries := make([]any, length)
for i := range storyEntries {
storyEntries[i] = map[string]any{
"userId": userid,
"eventId": eventId,
"seq": i,
"status": "already_read",
}
}
entries[eventId] = map[string]any{
"eventId": eventId,
"userEventStoryList": map[string]any{
"entries": storyEntries,
},
"isExistUnReadStory": false,
"isLocked": false,
}
}
}
return entries
}
func GetMusicInfo(master map[string]any, musicid string, difficulty string) map[string]any {
musicList, _ := master["masterMusicDifficultyList"].(map[string]any)
entries, _ := musicList["entries"].([]any)
for _, raw := range entries {
entry, ok := raw.(map[string]any)
if !ok {
continue
}
if fmt.Sprintf("%v", entry["musicId"]) == musicid &&
fmt.Sprintf("%v", entry["difficulty"]) == difficulty {
return entry
}
}
return nil
}
func BuildMusicScoreMap(user map[string]any) map[string]any {
result := map[string]any{
"entries": map[string]any{},
}
entries := result["entries"].(map[string]any)
musicScore, _ := user["musicScore"].(map[string]any)
for musicid, raw := range musicScore {
scoreData, _ := raw.(map[string]any)
scoreEntries, _ := scoreData["entries"].([]any)
normalizedEntries := make([]any, 0, len(scoreEntries))
for _, rawScore := range scoreEntries {
score, ok := rawScore.(map[string]any)
if !ok {
continue
}
normalizedEntries = append(normalizedEntries, map[string]any{
"userId": fmt.Sprintf("%v", user["userId"]),
"musicId": musicid,
"musicDifficulty": score["musicDifficulty"],
"soloHighScore": score["soloHighScore"],
"maxCombo": score["maxCombo"],
"soloScoreRank": score["soloScoreRank"],
"clearStatus": score["clearStatus"],
})
}
entries[musicid] = map[string]any{
"entries": normalizedEntries,
}
}
return result
}

21
utils/profile.go Normal file
View File

@@ -0,0 +1,21 @@
package utils
import "fmt"
var BandRankMap = func() map[string]any {
m := map[string]any{}
for _, id := range []int{1, 2, 3, 4, 5, 18, 21, 45} {
m[fmt.Sprintf("%d", id)] = 67
}
return m
}()
var DeckRatingMap = func() map[string]any {
m := map[string]any{}
for _, id := range []int{1, 2, 3, 4, 5, 18, 21, 45} {
m[fmt.Sprintf("%d", id)] = map[string]any{
"rank": "c", "score": 0, "lowerRating": 1, "upperRating": 1600000,
}
}
return m
}()