mirror of
https://github.com/MikuLeaks/KianaBH3.git
synced 2025-12-14 22:04:36 +01:00
Init enter game
This commit is contained in:
189
GameServer/Server/Connection.cs
Normal file
189
GameServer/Server/Connection.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using KianaBH.GameServer.Game.Player;
|
||||
using KianaBH.GameServer.Server.Packet;
|
||||
using KianaBH.KcpSharp;
|
||||
using KianaBH.KcpSharp.Base;
|
||||
using KianaBH.Proto;
|
||||
using KianaBH.Util;
|
||||
using KianaBH.Util.Extensions;
|
||||
using KianaBH.Util.Security;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.Reflection;
|
||||
using System.Buffers;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace KianaBH.GameServer.Server;
|
||||
|
||||
public class Connection(KcpConversation conversation, IPEndPoint remote) : KcpConnection(conversation, remote)
|
||||
{
|
||||
private static readonly Logger Logger = new("GameServer");
|
||||
|
||||
public PlayerInstance? Player { get; set; }
|
||||
|
||||
private static readonly HashSet<string> DummyPacketNames =
|
||||
[
|
||||
"AddGoodfeelReq", "ArkPlusActivityGetDataReq", "BuffAssistGetActivityReq", "BwWorldCampActivityGetDataReq",
|
||||
"ChatworldBeastGetActivityReq", "ChatworldGetPrayInfoReq", "ClientReportReq", "GetAdventureGroupReq",
|
||||
"GetArmadaDataReq", "GetArmadaStageScoreActivityReq", "GetAskAddFriendListReq", "GetAssistantFrozenListReq",
|
||||
"GetAvatarMissionActivityReq", "GetBattlePassMissionPanelReq", "GetBlackListReq", "GetCardProductInfoReq",
|
||||
"GetChapterActivityDataReq", "GetChapterCompensationInfoReq", "GetChatgroupListReq", "GetClientMailDataReq",
|
||||
"GetConsignedOrderDataReq", "GetCurrencyExchangeInfoReq", "GetExtractReforgeActivityReq",
|
||||
"GetFarmActivityDataReq", "GetFriendListReq", "GetFriendRemarkListReq", "GetGachaDisplayReq",
|
||||
"GetGardenScheduleReq", "GetGobackReq", "GetGratuityActivityReq", "GetMasterPupilCardReq",
|
||||
"GetMasterPupilDataReq", "GetMasterPupilMainDataReq", "GetMosaicActivityReq", "GetNewbieActivityReq",
|
||||
"GetNinjaActivityReq", "GetOfflineResourceDataReq", "GetOpenworldQuestActivityReq",
|
||||
"GetRaffleActivityReq", "GetRankScheduleDataReq", "GetRecommendFriendListReq", "GetRecommendGoodsReq",
|
||||
"GetRoomDataReq", "GetRpgTaleReq", "GetScratchTicketReq", "GetSecurityPasswordReq", "GetShoppingMallListReq",
|
||||
"GetStageChapterReq", "GetSupportActivityReq", "GetSurveyDataReq",
|
||||
"GetTradingCardActivityReq", "GetTvtActivityReq", "GetWeeklyRoutineActivityReq", "GrandKeyActivateSkillReq",
|
||||
"MassiveWarGetActivityReq", "OpenworldGetMechaTeamReq", "OpenworldHuntActivityGetDataReq",
|
||||
"PjmsGetAchievementDataReq", "PjmsGetConditionDataReq", "PjmsGetCurWorldReq", "PjmsGetStoryDataReq",
|
||||
"ReunionCookGetActivityReq", "SimplifiedGodWarGetActivityReq",
|
||||
"StageInnerDataReportReq", "SusannaTrialGetActivityReq", "ThemeWantedRefreshTicketReq",
|
||||
"UpdateMissionProgressReq", "WaveRushGetActivityReq"
|
||||
];
|
||||
|
||||
public override async void Start()
|
||||
{
|
||||
Logger.Info($"New connection from {RemoteEndPoint}.");
|
||||
State = SessionStateEnum.WAITING_FOR_TOKEN;
|
||||
await ReceiveLoop();
|
||||
}
|
||||
|
||||
public override async void Stop(bool isServerStop = false)
|
||||
{
|
||||
//if (isServerStop) await Player!.SendPacket(new PacketPlayerKickOutScNotify(KickType.KickLoginWhiteTimeout));
|
||||
Player?.OnLogoutAsync();
|
||||
KcpListener.UnregisterConnection(this);
|
||||
base.Stop(isServerStop);
|
||||
}
|
||||
|
||||
protected async Task ReceiveLoop()
|
||||
{
|
||||
while (!CancelToken.IsCancellationRequested)
|
||||
{
|
||||
// WaitToReceiveAsync call completes when there is at least one message is received or the transport is closed.
|
||||
var result = await Conversation.WaitToReceiveAsync(CancelToken.Token);
|
||||
if (result.TransportClosed)
|
||||
{
|
||||
Logger.Debug("Connection was closed");
|
||||
break;
|
||||
}
|
||||
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(result.BytesReceived);
|
||||
try
|
||||
{
|
||||
// TryReceive should not return false here, unless the transport is closed.
|
||||
// So we don't need to check for result.TransportClosed.
|
||||
if (!Conversation.TryReceive(buffer, out result))
|
||||
{
|
||||
Logger.Error("Failed to receive packet");
|
||||
break;
|
||||
}
|
||||
|
||||
await ProcessMessageAsync(buffer.AsMemory(0, result.BytesReceived));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error("Packet parse error", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
Stop();
|
||||
}
|
||||
|
||||
// DO THE PROCESSING OF THE GAME PACKET
|
||||
private async Task ProcessMessageAsync(Memory<byte> data)
|
||||
{
|
||||
var gamePacket = data.ToArray();
|
||||
|
||||
await using MemoryStream ms = new(gamePacket);
|
||||
using BinaryReader br = new(ms);
|
||||
|
||||
// Handle
|
||||
try
|
||||
{
|
||||
while (br.BaseStream.Position < br.BaseStream.Length)
|
||||
{
|
||||
// Length
|
||||
if (br.BaseStream.Length - br.BaseStream.Position < 32) return;
|
||||
// Packet sanity check
|
||||
var headMagic = br.ReadUInt32BE();
|
||||
if (headMagic != 0x01234567)
|
||||
{
|
||||
Logger.Error($"Bad Data Package Received: got 0x{headMagic:X}, expect 0x01234567");
|
||||
return; // Bad packet
|
||||
}
|
||||
|
||||
var packetVersion = br.ReadUInt16BE();
|
||||
var ClientVersion = br.ReadUInt16BE();
|
||||
var PacketId = br.ReadUInt32BE();
|
||||
var UserId = br.ReadUInt32BE();
|
||||
var UserIp = br.ReadUInt32BE();
|
||||
var Sign = br.ReadUInt32BE();
|
||||
var SignType = br.ReadUInt16BE();
|
||||
var CmdId = br.ReadUInt16BE();
|
||||
var HeaderLength = br.ReadUInt16BE();
|
||||
var BodyLength = br.ReadUInt32BE();
|
||||
|
||||
// Data
|
||||
var header = br.ReadBytes(HeaderLength);
|
||||
var Body = br.ReadBytes((int)BodyLength);
|
||||
var TailMagic = br.ReadUInt32BE();
|
||||
LogPacket("Recv", CmdId, Body);
|
||||
await HandlePacket(CmdId, header, Body);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e.Message, e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandlePacket(ushort opcode, byte[] header, byte[] payload)
|
||||
{
|
||||
var packetName = LogMap.GetValueOrDefault(opcode);
|
||||
if (DummyPacketNames.Contains(packetName!))
|
||||
{
|
||||
await SendDummy(packetName!);
|
||||
Logger.Info($"[Dummy] Send Dummy {packetName}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the Handler for this opcode
|
||||
var handler = HandlerManager.GetHandler(opcode);
|
||||
if (handler != null)
|
||||
{
|
||||
// Handle
|
||||
// Make sure session is ready for packets
|
||||
var state = State;
|
||||
try
|
||||
{
|
||||
await handler.OnHandle(this, header, payload);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e.Message, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendDummy(string packetName)
|
||||
{
|
||||
var respName = packetName.Replace("Req", "Rsp"); // Get the response packet name
|
||||
if (respName == packetName) return; // do not send rsp when resp name = recv name
|
||||
var respOpcode = LogMap.FirstOrDefault(x => x.Value == respName).Key; // Get the response opcode
|
||||
|
||||
// Send Rsp
|
||||
await SendPacket(respOpcode);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user