pre cw with probe and a bunch script to read game behavior
This commit is contained in:
1 parent
5120219ae2
commit
da8a32f60d
310 files changed
+219693
-872
No files matched your search
@@ -0,0 +1,158 @@
|
||||
package gameserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"gac-hkrpg-go/internal/common"
|
||||
goproto "gac-hkrpg-go/protocol/proto"
|
||||
)
|
||||
|
||||
type prydwenEndgameSnapshot struct {
|
||||
Source struct {
|
||||
DatasetVersion string `json:"dataset_version"`
|
||||
ChallengeVersion string `json:"challenge_version"`
|
||||
ChallengeName string `json:"challenge_name"`
|
||||
} `json:"source"`
|
||||
AvatarAliases map[string]string `json:"avatar_aliases"`
|
||||
Mode string `json:"mode"`
|
||||
Floor uint32 `json:"floor"`
|
||||
Stages []struct {
|
||||
Stage uint32 `json:"stage"`
|
||||
Rank uint32 `json:"rank"`
|
||||
Characters []string `json:"characters"`
|
||||
} `json:"stages"`
|
||||
}
|
||||
|
||||
type prydwenAvatarResource struct {
|
||||
ID uint32 `json:"AvatarID"`
|
||||
VOTag string `json:"AvatarVOTag"`
|
||||
ConfigPath string `json:"JsonPath"`
|
||||
}
|
||||
|
||||
var (
|
||||
prydwenOnce sync.Once
|
||||
prydwenLineups []*goproto.ChallengeLineupList
|
||||
prydwenLoadErr error
|
||||
)
|
||||
|
||||
func normalizedAvatarName(name string) string {
|
||||
name = strings.ToLower(name)
|
||||
return strings.Map(func(r rune) rune {
|
||||
if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') {
|
||||
return r
|
||||
}
|
||||
return -1
|
||||
}, name)
|
||||
}
|
||||
|
||||
func loadPrydwenLineups() ([]*goproto.ChallengeLineupList, error) {
|
||||
prydwenOnce.Do(func() {
|
||||
prydwenLineups, prydwenLoadErr = readPrydwenLineups()
|
||||
})
|
||||
return prydwenLineups, prydwenLoadErr
|
||||
}
|
||||
|
||||
func readPrydwenLineups() ([]*goproto.ChallengeLineupList, error) {
|
||||
raw, err := common.ReadResourceFile("resources/PrydwenEndgameTeams.json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read Prydwen endgame team snapshot: %w", err)
|
||||
}
|
||||
var snapshot prydwenEndgameSnapshot
|
||||
if err := json.Unmarshal(raw, &snapshot); err != nil {
|
||||
return nil, fmt.Errorf("parse Prydwen endgame team snapshot: %w", err)
|
||||
}
|
||||
if snapshot.Mode != "moc" || snapshot.Floor == 0 || len(snapshot.Stages) == 0 {
|
||||
return nil, fmt.Errorf("Prydwen endgame team snapshot has no supported MoC floor")
|
||||
}
|
||||
|
||||
avatarRaw, err := common.ReadResourceFile("resources/AvatarConfig.json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read Client AvatarConfig resource: %w", err)
|
||||
}
|
||||
var avatarTable struct {
|
||||
Entries []prydwenAvatarResource `json:"avatar_config"`
|
||||
}
|
||||
if err := json.Unmarshal(avatarRaw, &avatarTable); err != nil {
|
||||
return nil, fmt.Errorf("parse Client AvatarConfig resource: %w", err)
|
||||
}
|
||||
avatarIDs := make(map[string]uint32, len(avatarTable.Entries)*2)
|
||||
for _, avatar := range avatarTable.Entries {
|
||||
if avatar.ID == 0 {
|
||||
continue
|
||||
}
|
||||
if tag := normalizedAvatarName(avatar.VOTag); tag != "" {
|
||||
avatarIDs[tag] = avatar.ID
|
||||
}
|
||||
pathName := strings.TrimSuffix(filepath.Base(avatar.ConfigPath), filepath.Ext(avatar.ConfigPath))
|
||||
pathName = strings.TrimSuffix(strings.TrimPrefix(pathName, "Avatar_"), "_Config")
|
||||
if pathName = normalizedAvatarName(pathName); pathName != "" {
|
||||
avatarIDs[pathName] = avatar.ID
|
||||
}
|
||||
}
|
||||
|
||||
lineups := make([]*goproto.ChallengeLineupList, 0, len(snapshot.Stages))
|
||||
seenStages := map[uint32]bool{}
|
||||
for _, stage := range snapshot.Stages {
|
||||
if stage.Stage == 0 || seenStages[stage.Stage] || len(stage.Characters) != 4 {
|
||||
return nil, fmt.Errorf("invalid Prydwen MoC stage %d team size/order", stage.Stage)
|
||||
}
|
||||
seenStages[stage.Stage] = true
|
||||
avatars := make([]*goproto.ChallengeAvatarInfo, 0, len(stage.Characters))
|
||||
for index, slug := range stage.Characters {
|
||||
resourceTag := snapshot.AvatarAliases[slug]
|
||||
if resourceTag == "" {
|
||||
resourceTag = slug
|
||||
}
|
||||
id := avatarIDs[normalizedAvatarName(resourceTag)]
|
||||
if id == 0 {
|
||||
return nil, fmt.Errorf("Prydwen avatar %q has no ID in Client AvatarConfig", slug)
|
||||
}
|
||||
avatars = append(avatars, &goproto.ChallengeAvatarInfo{
|
||||
AvatarType: goproto.AvatarType_AVATAR_FORMAL_TYPE,
|
||||
Id: id,
|
||||
Index: uint32(index),
|
||||
})
|
||||
}
|
||||
lineups = append(lineups, &goproto.ChallengeLineupList{AvatarList: avatars})
|
||||
}
|
||||
return lineups, nil
|
||||
}
|
||||
|
||||
func buildPrydwenRecommendResponse(req *goproto.GetFriendRecommendLineupCsReq) (*goproto.GetFriendRecommendLineupScRsp, error) {
|
||||
lineups, err := loadPrydwenLineups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &goproto.GetFriendRecommendLineupScRsp{
|
||||
Key: req.Key,
|
||||
Type: req.Type,
|
||||
MGKCKHIIICL: []*goproto.FPDCINMDJCE{{
|
||||
KJFEKHDEBIK: &goproto.FPDCINMDJCE_NHKCFOALAPD{
|
||||
NHKCFOALAPD: &goproto.OJJJDPNOKHG{LineupList: lineups},
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
handle("GetFriendRecommendLineup", func(_ *Session, req *goproto.GetFriendRecommendLineupCsReq, rsp *goproto.GetFriendRecommendLineupScRsp) error {
|
||||
// Preserve request context. The game UI asks this endpoint for the
|
||||
// recommendation panel; an empty auto-response left the panel blank.
|
||||
response, err := buildPrydwenRecommendResponse(req)
|
||||
if err != nil {
|
||||
Log(fmt.Sprintf("[RECOMMEND] Prydwen data unavailable type=%s key=%d: %v", req.Type, req.Key, err))
|
||||
return nil
|
||||
}
|
||||
rsp.Key = response.Key
|
||||
rsp.Type = response.Type
|
||||
rsp.MGKCKHIIICL = response.MGKCKHIIICL
|
||||
rsp.Retcode = response.Retcode
|
||||
rsp.ALDBIIIGLOM = response.ALDBIIIGLOM
|
||||
Log(fmt.Sprintf("[RECOMMEND] served Prydwen MoC teams type=%s key=%d stages=%d", req.Type, req.Key, len(response.MGKCKHIIICL[0].GetNHKCFOALAPD().LineupList)))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user