Files

260 lines
7.9 KiB
Go

package gameserver
import (
"fmt"
"gac-hkrpg-go/internal/common"
goproto "gac-hkrpg-go/protocol/proto"
)
// Request/response layouts follow services/profile.zig and protocol.pb.zig at
// goproto.CommandSourceRevision. CSReq Go spellings below are legacy type names;
// handle resolves only the current CsReq command name, never numeric aliases.
func selectedProfileID(value *uint32, fallback uint32) uint32 {
if value != nil {
return *value
}
return fallback
}
func saveProfile(player *common.FreesrData, next common.ProfileSettings) error {
previous := player.Profile
player.Profile = next
if err := player.SavePersistentChecked(); err != nil {
player.Profile = previous
return err
}
return nil
}
func profilePlayer(s *Session) (*common.FreesrData, error) {
if p := s.JSON(); p != nil {
return p, nil
}
return nil, fmt.Errorf("profile command requires player data")
}
func fillPhoneData(p *common.FreesrData, resource *profileResources, rsp *goproto.GetPhoneDataScRsp) {
rsp.CurPhoneTheme = selectedProfileID(p.Profile.PhoneTheme, resource.CurrentPhoneTheme)
rsp.CurPhoneCase = selectedProfileID(p.Profile.PhoneCase, resource.CurrentPhoneCase)
rsp.CurChatBubble = selectedProfileID(p.Profile.ChatBubble, resource.CurrentChatBubble)
rsp.OwnedPhoneThemes = resource.PhoneThemes
rsp.OwnedPhoneCases = resource.PhoneCases
rsp.OwnedChatBubbles = resource.ChatBubbles
}
func fillPlayerBoard(p *common.FreesrData, resource *profileResources, rsp *goproto.GetPlayerBoardDataScRsp) {
rsp.CurrentHeadIconId = selectedProfileID(p.Profile.HeadIcon, resource.Icons[0])
rsp.CurrentPersonalCardId = selectedProfileID(p.Profile.PersonalCard, resource.CurrentPersonalCard)
rsp.HeadFrameInfo = resource.HeadFrame
if p.Profile.Signature != nil {
rsp.Signature = *p.Profile.Signature
}
rsp.JJDDEKIAOFC = resource.PersonalCards
for _, id := range resource.Icons {
rsp.KNINLDPFLMA = append(rsp.KNINLDPFLMA, &goproto.HeadIconData{Id: id})
}
rsp.NBIEJKLENOB = &goproto.DisplayAvatarVec{IsDisplay: true}
if p.Profile.IsDisplay != nil {
rsp.NBIEJKLENOB.IsDisplay = *p.Profile.IsDisplay
}
for _, slot := range p.SortedLineupKeys() {
id := p.Lineups[slot]
if p.Avatars[id] != nil {
rsp.KJAABDABLJJ = append(rsp.KJAABDABLJJ, id)
rsp.NBIEJKLENOB.DisplayAvatarList = append(rsp.NBIEJKLENOB.DisplayAvatarList, &goproto.DisplayAvatarData{AvatarId: id, Pos: slot})
}
}
if p.Profile.DisplayAvatars != nil {
rsp.NBIEJKLENOB.DisplayAvatarList = nil
for _, av := range *p.Profile.DisplayAvatars {
rsp.NBIEJKLENOB.DisplayAvatarList = append(rsp.NBIEJKLENOB.DisplayAvatarList, &goproto.DisplayAvatarData{AvatarId: av.AvatarID, Pos: av.Pos})
}
}
if p.Profile.AssistAvatars != nil {
rsp.KJAABDABLJJ = append([]uint32{}, (*p.Profile.AssistAvatars)...)
}
}
func init() {
handle("SelectPhoneTheme", func(s *Session, req *goproto.SelectPhoneThemeCsReq, rsp *goproto.SelectPhoneThemeScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
resource, err := loadProfileResources()
if err != nil {
return err
}
if req.ThemeId != resource.CurrentPhoneTheme && !containsU32(resource.PhoneThemes, req.ThemeId) {
rsp.Retcode = uint32(goproto.Retcode_RET_ITEM_NOT_EXIST)
return nil
}
next := p.Profile
next.PhoneTheme = &req.ThemeId
if err := saveProfile(p, next); err != nil {
return err
}
rsp.CurPhoneTheme = req.ThemeId
return nil
})
handle("SelectPhoneCase", func(s *Session, req *goproto.SelectPhoneCaseCSReq, rsp *goproto.SelectPhoneCaseScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
resource, err := loadProfileResources()
if err != nil {
return err
}
if !containsU32(resource.PhoneCases, req.PhoneCaseId) {
rsp.Retcode = uint32(goproto.Retcode_RET_ITEM_NOT_EXIST)
return nil
}
next := p.Profile
next.PhoneCase = &req.PhoneCaseId
if err := saveProfile(p, next); err != nil {
return err
}
rsp.CurPhoneCase = req.PhoneCaseId
return nil
})
handle("SelectChatBubble", func(s *Session, req *goproto.SelectChatBubbleCsReq, rsp *goproto.SelectChatBubbleScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
resource, err := loadProfileResources()
if err != nil {
return err
}
if req.BubbleId != resource.CurrentChatBubble && !containsU32(resource.ChatBubbles, req.BubbleId) {
rsp.Retcode = uint32(goproto.Retcode_RET_ITEM_NOT_EXIST)
return nil
}
next := p.Profile
next.ChatBubble = &req.BubbleId
if err := saveProfile(p, next); err != nil {
return err
}
rsp.CurChatBubble = req.BubbleId
return nil
})
handle("SetHeadIcon", func(s *Session, req *goproto.SetHeadIconCsReq, rsp *goproto.SetHeadIconScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
resource, err := loadProfileResources()
if err != nil {
return err
}
if !containsU32(resource.Icons, req.Id) {
rsp.Retcode = uint32(goproto.Retcode_RET_ITEM_NOT_EXIST)
return nil
}
next := p.Profile
next.HeadIcon = &req.Id
if err := saveProfile(p, next); err != nil {
return err
}
rsp.CurrentHeadIconId = req.Id
return nil
})
handle("SetPersonalCard", func(s *Session, req *goproto.SetPersonalCardCSReq, rsp *goproto.SetPersonalCardScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
resource, err := loadProfileResources()
if err != nil {
return err
}
if !containsU32(resource.PersonalCards, req.Id) {
rsp.Retcode = uint32(goproto.Retcode_RET_ITEM_NOT_EXIST)
return nil
}
next := p.Profile
next.PersonalCard = &req.Id
if err := saveProfile(p, next); err != nil {
return err
}
rsp.CurrentPersonalCardId = req.Id
return nil
})
handle("SetSignature", func(s *Session, req *goproto.SetSignatureCsReq, rsp *goproto.SetSignatureScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
next := p.Profile
next.Signature = &req.Signature
if err := saveProfile(p, next); err != nil {
return err
}
rsp.Signature = req.Signature
return nil
})
handle("SetIsDisplayAvatarInfo", func(s *Session, req *goproto.SetIsDisplayAvatarInfoCsReq, rsp *goproto.SetIsDisplayAvatarInfoScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
next := p.Profile
next.IsDisplay = &req.IsDisplay
if err := saveProfile(p, next); err != nil {
return err
}
rsp.IsDisplay = req.IsDisplay
return nil
})
handle("SetDisplayAvatar", func(s *Session, req *goproto.SetDisplayAvatarCsReq, rsp *goproto.SetDisplayAvatarScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
list := make([]common.ProfileAvatar, 0, len(req.DisplayAvatarList))
positions, avatars := map[uint32]bool{}, map[uint32]bool{}
for _, av := range req.DisplayAvatarList {
if av == nil || p.Avatars[av.AvatarId] == nil || positions[av.Pos] || avatars[av.AvatarId] {
rsp.Retcode = uint32(goproto.Retcode_RET_AVATAR_NOT_EXIST)
return nil
}
positions[av.Pos], avatars[av.AvatarId] = true, true
list = append(list, common.ProfileAvatar{AvatarID: av.AvatarId, Pos: av.Pos})
}
next := p.Profile
next.DisplayAvatars = &list
if err := saveProfile(p, next); err != nil {
return err
}
rsp.DisplayAvatarList = req.DisplayAvatarList
return nil
})
handle("SetAssistAvatar", func(s *Session, req *goproto.SetAssistAvatarCsReq, rsp *goproto.SetAssistAvatarScRsp) error {
p, err := profilePlayer(s)
if err != nil {
return err
}
list := append([]uint32{}, req.AvatarIdList...)
if req.AvatarId != 0 && !containsU32(list, req.AvatarId) {
list = append(list, req.AvatarId)
}
seen := map[uint32]bool{}
for _, id := range list {
if p.Avatars[id] == nil || seen[id] {
rsp.Retcode = uint32(goproto.Retcode_RET_AVATAR_NOT_EXIST)
return nil
}
seen[id] = true
}
next := p.Profile
next.AssistAvatars = &list
if err := saveProfile(p, next); err != nil {
return err
}
rsp.AvatarId, rsp.AvatarIdList = req.AvatarId, req.AvatarIdList
return nil
})
}