feat(go): Port full Ananta private server to Go architecture
This commit is contained in:
1 parent
ca2e80f9b7
commit
c73d744649
28 files changed
+3585
-57
No files matched your search
@@ -0,0 +1,129 @@
|
||||
package gameserver
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"ananta-ps/internal/config"
|
||||
"ananta-ps/pkg/crypto/chacha8"
|
||||
"ananta-ps/pkg/protocol"
|
||||
)
|
||||
|
||||
func TestGameServerWorldEntry(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Client: config.ClientConfig{
|
||||
ServerID: 801,
|
||||
Aid: 5944,
|
||||
},
|
||||
Network: config.NetworkConfig{
|
||||
BindHost: "127.0.0.1",
|
||||
AdvertisedHost: "127.0.0.1",
|
||||
GamePort: 15203,
|
||||
},
|
||||
Player: config.PlayerConfig{
|
||||
Pid: 100,
|
||||
InitialUnitId: 100000000000,
|
||||
InitialSpiritTemplateId: 15020967,
|
||||
AccountId: "test_acc",
|
||||
DisplayName: "test_player",
|
||||
},
|
||||
World: config.WorldConfig{
|
||||
RaidId: 23300888,
|
||||
SceneInstanceId: 20001222,
|
||||
UniverseId: 76000888,
|
||||
Spawn: config.Vec3{X: 100, Y: 0, Z: 200},
|
||||
Facing: 0,
|
||||
},
|
||||
}
|
||||
|
||||
srv := New(cfg, "../../data/player_info_template.bin")
|
||||
if err := srv.Start(); err != nil {
|
||||
t.Fatalf("failed to start game server: %v", err)
|
||||
}
|
||||
defer srv.Stop()
|
||||
|
||||
// Connect client
|
||||
conn, err := net.DialTimeout("tcp", "127.0.0.1:15203", 2*time.Second)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 1. Client handshake
|
||||
clientHandshake := make([]byte, 260)
|
||||
aesKey := []byte("0123456789abcdef")
|
||||
copy(clientHandshake[4:20], aesKey)
|
||||
if err := protocol.WriteFrame(conn, 0x01, clientHandshake, nil); err != nil {
|
||||
t.Fatalf("failed to write handshake: %v", err)
|
||||
}
|
||||
|
||||
// 2. Server reply
|
||||
replyFrame, err := protocol.ReadFrame(conn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read reply: %v", err)
|
||||
}
|
||||
|
||||
aesNonce := replyFrame.Payload[8:20]
|
||||
encryptedHead := replyFrame.Payload[20:96]
|
||||
tag := replyFrame.Payload[96:112]
|
||||
|
||||
cipherBlock, err := aes.NewCipher(aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create aes cipher: %v", err)
|
||||
}
|
||||
aesGcm, err := cipher.NewGCM(cipherBlock)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create aes gcm: %v", err)
|
||||
}
|
||||
|
||||
fullCipher := append(encryptedHead, tag...)
|
||||
chaChaHead, err := aesGcm.Open(nil, aesNonce, fullCipher, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decrypt chacha head: %v", err)
|
||||
}
|
||||
|
||||
clientSendCipher, _ := chacha8.New(chaChaHead[0:32], chaChaHead[64:76])
|
||||
clientReadCipher, _ := chacha8.New(chaChaHead[32:64], chaChaHead[64:76])
|
||||
|
||||
// 3. Send LoginGame Invoke
|
||||
invokePayload := protocol.BuildInvoke(protocol.MethodLoginGame, 1, nil)
|
||||
if err := protocol.WriteFrame(conn, 0x09, invokePayload, clientSendCipher); err != nil {
|
||||
t.Fatalf("failed to write LoginGame: %v", err)
|
||||
}
|
||||
|
||||
// 4. Read Return frame
|
||||
retFrame, err := protocol.ReadFrame(conn, clientReadCipher)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read return: %v", err)
|
||||
}
|
||||
pkt := protocol.ParseRpcPacket(retFrame.Payload)
|
||||
if pkt.Kind != protocol.PacketKindReturn || pkt.InvokeID != 1 {
|
||||
t.Fatalf("expected return for invoke 1, got %v", pkt)
|
||||
}
|
||||
|
||||
// 5. Read S2C notifications (ServerTime, SyncPlayerInfo, SyncEnterScene)
|
||||
foundEnterScene := false
|
||||
for i := 0; i < 3; i++ {
|
||||
notifyFrame, err := protocol.ReadFrame(conn, clientReadCipher)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read notify frame: %v", err)
|
||||
}
|
||||
nPkt := protocol.ParseRpcPacket(notifyFrame.Payload)
|
||||
if nPkt.MethodID == protocol.MethodSyncEnterScene {
|
||||
foundEnterScene = true
|
||||
}
|
||||
}
|
||||
|
||||
if !foundEnterScene {
|
||||
t.Fatalf("expected SyncEnterScene in notifications")
|
||||
}
|
||||
|
||||
// Verify session tracking
|
||||
sessions := srv.GetActiveSessions()
|
||||
if len(sessions) != 1 {
|
||||
t.Fatalf("expected 1 active session, got %d", len(sessions))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user