feat: port GaC-hkrpg-ps to Go with SceneCastSkill camera-detach fix
- mihoyo-variant KCP in pure Go (28-byte conv+token header), UDP gateway with 0xFF/0x145/0x194 handshake, ms-precision KCP clock + retransmit ticker - protobuf for 4.6.51 generated from the AstralOS StarRail.proto (4932 messages) plus CmdID map from // CmdID: comments (2114 ids) - sdkserver port: query_dispatch/query_gateway (Gateserver pb + base64), hotfix fetch, auth endpoints, SRTools freesr-data.json upload - gameserver handlers: login flow, scene load/spawn with real monster entity tracking, lineup, avatar/skin, missions, tutorials (1249+855), bag/equip, challenge incl. StartChallenge 1787 layout + Tierce 8973 + peak 8948, all raw tierce replies - SceneCastSkill camera bug fix: only real scene monsters (tracked per session) trigger battle; attacking props/NPCs/air replies retcode 0 without battle_info so the camera stays locked on the character - end-to-end smoke test simulating a client over real UDP: handshake, PlayerGetToken, and both SceneCastSkill paths - reuses the Rust PS data files unchanged (freesr-data.json, persistent, res.json, teleports.json, challenge_data.json, mission_unlocks.json)
This commit is contained in:
commit
59ea97b1a6
45 files changed
+1963868
No files matched your search
@@ -0,0 +1,150 @@
|
||||
package gameserver
|
||||
|
||||
import (
|
||||
"gac-hkrpg-go/internal/common"
|
||||
goproto "gac-hkrpg-go/protocol/proto"
|
||||
)
|
||||
|
||||
func commonToLineupAvatars(f *common.FreesrData) []*goproto.LineupAvatar {
|
||||
return common.ToLineupAvatars(f)
|
||||
}
|
||||
|
||||
func init() {
|
||||
handle("GetAllLineupData", func(s *Session, req *goproto.GetAllLineupDataCsReq, rsp *goproto.GetAllLineupDataScRsp) error {
|
||||
player := s.JSON()
|
||||
if player == nil {
|
||||
return nil
|
||||
}
|
||||
rsp.LineupList = append(rsp.LineupList, &goproto.LineupInfo{
|
||||
ExtraLineupType: goproto.ExtraLineupType_ExtraLineupType_LineupNone,
|
||||
Name: "Squad 1",
|
||||
Mp: 5,
|
||||
MaxMp: 5,
|
||||
AvatarList: commonToLineupAvatars(player),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
handle("GetCurLineupData", func(s *Session, req *goproto.GetCurLineupDataCsReq, rsp *goproto.GetCurLineupDataScRsp) error {
|
||||
player := s.JSON()
|
||||
if player == nil {
|
||||
return nil
|
||||
}
|
||||
rsp.Lineup = &goproto.LineupInfo{
|
||||
ExtraLineupType: goproto.ExtraLineupType_ExtraLineupType_LineupNone,
|
||||
Name: "Squad 1",
|
||||
Mp: 5,
|
||||
MaxMp: 5,
|
||||
AvatarList: commonToLineupAvatars(player),
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
handle("JoinLineup", func(s *Session, req *goproto.JoinLineupCsReq, rsp *goproto.JoinLineupScRsp) error {
|
||||
player := s.JSON()
|
||||
if player == nil {
|
||||
return nil
|
||||
}
|
||||
player.Lineups[req.Slot] = req.BaseAvatarId
|
||||
player.SavePersistent()
|
||||
return refreshLineup(s)
|
||||
})
|
||||
|
||||
handle("ReplaceLineup", func(s *Session, req *goproto.ReplaceLineupCsReq, rsp *goproto.ReplaceLineupScRsp) error {
|
||||
player := s.JSON()
|
||||
if player == nil {
|
||||
return nil
|
||||
}
|
||||
for _, item := range req.LineupSlotList {
|
||||
player.Lineups[item.Slot] = item.Id
|
||||
}
|
||||
player.SavePersistent()
|
||||
return refreshLineup(s)
|
||||
})
|
||||
|
||||
handle("SwapLineup", func(s *Session, req *goproto.SwapLineupCsReq, rsp *goproto.SwapLineupScRsp) error {
|
||||
player := s.JSON()
|
||||
if player == nil {
|
||||
return nil
|
||||
}
|
||||
// MPIEGFCNBEN / ENBIBCPPLDC are the obfuscated src/dst slots; the swap
|
||||
// is symmetric so the mapping direction doesn't matter.
|
||||
srcSlot, dstSlot := req.MPIEGFCNBEN, req.ENBIBCPPLDC
|
||||
srcAvatar := player.Lineups[srcSlot]
|
||||
dstAvatar := player.Lineups[dstSlot]
|
||||
player.Lineups[srcSlot] = dstAvatar
|
||||
player.Lineups[dstSlot] = srcAvatar
|
||||
player.SavePersistent()
|
||||
return refreshLineup(s)
|
||||
})
|
||||
|
||||
handle("SwitchLineupIndex", func(s *Session, req *goproto.SwitchLineupIndexCsReq, rsp *goproto.SwitchLineupIndexScRsp) error {
|
||||
return refreshLineup(s)
|
||||
})
|
||||
|
||||
handle("GetLineupAvatarData", func(s *Session, req *goproto.GetLineupAvatarDataCsReq, rsp *goproto.GetLineupAvatarDataScRsp) error {
|
||||
rsp.Retcode = 0
|
||||
return nil
|
||||
})
|
||||
|
||||
handle("QuitLineup", func(s *Session, req *goproto.QuitLineupCsReq, rsp *goproto.QuitLineupScRsp) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
handle("ChangeLineupLeader", func(s *Session, req *goproto.ChangeLineupLeaderCsReq, rsp *goproto.ChangeLineupLeaderScRsp) error {
|
||||
rsp.Slot = req.Slot
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// refreshLineup mirrors refresh_lineup: SceneGroupRefreshScNotify + SyncLineupNotify.
|
||||
func refreshLineup(s *Session) error {
|
||||
player := s.JSON()
|
||||
if player == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
lineup := &goproto.LineupInfo{
|
||||
ExtraLineupType: goproto.ExtraLineupType_ExtraLineupType_LineupNone,
|
||||
Name: "Squad 1",
|
||||
AvatarList: commonToLineupAvatars(player),
|
||||
MaxMp: 5,
|
||||
Mp: 5,
|
||||
}
|
||||
|
||||
notify := &goproto.SceneGroupRefreshScNotify{
|
||||
FloorId: player.Scene.FloorID,
|
||||
DimensionId: 0,
|
||||
}
|
||||
group := &goproto.SceneGroupRefreshInfo{
|
||||
GroupId: 0,
|
||||
State: 0,
|
||||
GroupRefreshType: goproto.SceneGroupRefreshType_SCENE_GROUP_REFRESH_TYPE_LOADED,
|
||||
}
|
||||
for _, slot := range player.SortedLineupKeys() {
|
||||
avatarID := player.Lineups[slot]
|
||||
group.RefreshEntity = append(group.RefreshEntity, &goproto.SceneEntityRefreshInfo{
|
||||
RefreshType: &goproto.SceneEntityRefreshInfo_AddEntity{
|
||||
AddEntity: &goproto.SceneEntityInfo{
|
||||
EntityId: slot + 1,
|
||||
GroupId: 0,
|
||||
InstId: 0,
|
||||
Entity: &goproto.SceneEntityInfo_Actor{
|
||||
Actor: &goproto.SceneActorInfo{
|
||||
AvatarType: goproto.AvatarType_AVATAR_FORMAL_TYPE,
|
||||
BaseAvatarId: avatarID,
|
||||
MapLayer: 0,
|
||||
Uid: 25,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
notify.GroupRefreshInfo = append(notify.GroupRefreshInfo, group)
|
||||
|
||||
if err := s.Send(notify); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Send(&goproto.SyncLineupNotify{Lineup: lineup})
|
||||
}
|
||||
Reference in new issue
Block a user