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,106 @@
|
||||
package gameserver
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
HeadMagic uint32 = 0x9D74C714
|
||||
TailMagic uint32 = 0xD7A152C8
|
||||
)
|
||||
|
||||
// NetPacket is the framed protocol inside the KCP stream.
|
||||
type NetPacket struct {
|
||||
CmdType uint16
|
||||
Head []byte
|
||||
Body []byte
|
||||
}
|
||||
|
||||
var ErrMalformedPacket = errors.New("malformed packet")
|
||||
|
||||
func (p *NetPacket) Encode() []byte {
|
||||
out := make([]byte, 0, 12+len(p.Head)+len(p.Body))
|
||||
var be32 [4]byte
|
||||
var be16 [2]byte
|
||||
|
||||
binary.BigEndian.PutUint32(be32[:], HeadMagic)
|
||||
out = append(out, be32[:]...)
|
||||
binary.BigEndian.PutUint16(be16[:], p.CmdType)
|
||||
out = append(out, be16[:]...)
|
||||
binary.BigEndian.PutUint16(be16[:], uint16(len(p.Head)))
|
||||
out = append(out, be16[:]...)
|
||||
binary.BigEndian.PutUint32(be32[:], uint32(len(p.Body)))
|
||||
out = append(out, be32[:]...)
|
||||
out = append(out, p.Head...)
|
||||
out = append(out, p.Body...)
|
||||
binary.BigEndian.PutUint32(be32[:], TailMagic)
|
||||
out = append(out, be32[:]...)
|
||||
return out
|
||||
}
|
||||
|
||||
// DecodeNetPacket parses one framed packet (must be a complete packet).
|
||||
func DecodeNetPacket(data []byte) (*NetPacket, error) {
|
||||
if len(data) < 16 {
|
||||
return nil, fmt.Errorf("%w: too short (%d)", ErrMalformedPacket, len(data))
|
||||
}
|
||||
if binary.BigEndian.Uint32(data[0:4]) != HeadMagic {
|
||||
return nil, fmt.Errorf("%w: bad head magic", ErrMalformedPacket)
|
||||
}
|
||||
cmdType := binary.BigEndian.Uint16(data[4:6])
|
||||
headLen := int(binary.BigEndian.Uint16(data[6:8]))
|
||||
bodyLen := int(binary.BigEndian.Uint32(data[8:12]))
|
||||
if len(data) < 12+headLen+bodyLen+4 {
|
||||
return nil, fmt.Errorf("%w: truncated", ErrMalformedPacket)
|
||||
}
|
||||
if binary.BigEndian.Uint32(data[12+headLen+bodyLen:]) != TailMagic {
|
||||
return nil, fmt.Errorf("%w: bad tail magic", ErrMalformedPacket)
|
||||
}
|
||||
return &NetPacket{
|
||||
CmdType: cmdType,
|
||||
Head: data[12 : 12+headLen],
|
||||
Body: data[12+headLen : 12+headLen+bodyLen],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NetOperation is the 20-byte handshake control packet.
|
||||
type NetOperation struct {
|
||||
Head uint32
|
||||
Param1 uint32
|
||||
Param2 uint32
|
||||
Data uint32
|
||||
Tail uint32
|
||||
}
|
||||
|
||||
const (
|
||||
NetOpConnectHead uint32 = 0xFF
|
||||
NetOpConnectTail uint32 = 0xFFFFFFFF
|
||||
NetOpAcceptHead uint32 = 0x145
|
||||
NetOpAcceptTail uint32 = 0x14514545
|
||||
NetOpDropHead uint32 = 0x194
|
||||
NetOpDropTail uint32 = 0x19419494
|
||||
)
|
||||
|
||||
func DecodeNetOperation(data []byte) (*NetOperation, error) {
|
||||
if len(data) < 20 {
|
||||
return nil, fmt.Errorf("%w: netop too short", ErrMalformedPacket)
|
||||
}
|
||||
return &NetOperation{
|
||||
Head: binary.BigEndian.Uint32(data[0:4]),
|
||||
Param1: binary.BigEndian.Uint32(data[4:8]),
|
||||
Param2: binary.BigEndian.Uint32(data[8:12]),
|
||||
Data: binary.BigEndian.Uint32(data[12:16]),
|
||||
Tail: binary.BigEndian.Uint32(data[16:20]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *NetOperation) Encode() []byte {
|
||||
out := make([]byte, 20)
|
||||
binary.BigEndian.PutUint32(out[0:4], o.Head)
|
||||
binary.BigEndian.PutUint32(out[4:8], o.Param1)
|
||||
binary.BigEndian.PutUint32(out[8:12], o.Param2)
|
||||
binary.BigEndian.PutUint32(out[12:16], o.Data)
|
||||
binary.BigEndian.PutUint32(out[16:20], o.Tail)
|
||||
return out
|
||||
}
|
||||
Reference in new issue
Block a user