fork from 1.3
This commit is contained in:
53
FreeSR.Gateserver/Network/Factory/ProtoFactory.cs
Normal file
53
FreeSR.Gateserver/Network/Factory/ProtoFactory.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
namespace FreeSR.Gateserver.Network.Factory
|
||||
{
|
||||
using FreeSR.Proto;
|
||||
using ProtoBuf;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
internal static class ProtoFactory
|
||||
{
|
||||
private static readonly ImmutableDictionary<CmdType, Type> s_types;
|
||||
|
||||
static ProtoFactory()
|
||||
{
|
||||
var builder = ImmutableDictionary.CreateBuilder<CmdType, Type>();
|
||||
builder.AddRange(new Dictionary<CmdType, Type>()
|
||||
{
|
||||
{CmdType.PlayerGetTokenCsReq, typeof(PlayerGetTokenCsReq)},
|
||||
{CmdType.PlayerLoginCsReq, typeof(PlayerLoginCsReq)},
|
||||
{CmdType.GetAvatarDataCsReq, typeof(GetAvatarDataCsReq)},
|
||||
|
||||
{CmdType.GetAllLineupDataCsReq, typeof(GetAllLineupDataCsReq)},
|
||||
{CmdType.GetCurLineupDataCsReq, typeof(GetCurLineupDataCsReq)},
|
||||
{CmdType.ChangeLineupLeaderCsReq, typeof(ChangeLineupLeaderCsReq)},
|
||||
|
||||
{CmdType.GetMissionStatusCsReq, typeof(GetMissionStatusCsReq)},
|
||||
{CmdType.GetQuestDataCsReq, typeof(GetQuestDataCsReq)},
|
||||
{CmdType.GetChallengeCsReq, typeof(GetChallengeCsReq)},
|
||||
{CmdType.GetCurSceneInfoCsReq, typeof(GetCurSceneInfoCsReq)},
|
||||
|
||||
{CmdType.GetBasicInfoCsReq, typeof(GetBasicInfoCsReq)},
|
||||
{CmdType.GetHeroBasicTypeInfoCsReq, typeof(GetHeroBasicTypeInfoCsReq)},
|
||||
{CmdType.PlayerHeartBeatCsReq, typeof(PlayerHeartBeatCsReq)},
|
||||
|
||||
{CmdType.GetGachaInfoCsReq, typeof(GetGachaInfoCsReq)},
|
||||
{CmdType.DoGachaCsReq, typeof(DoGachaCsReq)},
|
||||
|
||||
{CmdType.GetNpcTakenRewardCsReq, typeof(GetNpcTakenRewardCsReq)},
|
||||
{CmdType.GetFirstTalkByPerformanceNpcCsReq, typeof(GetFirstTalkByPerformanceNpcCsReq)},
|
||||
|
||||
{CmdType.GetBagCsReq, typeof(GetBagCsReq)}
|
||||
});
|
||||
|
||||
s_types = builder.ToImmutable();
|
||||
}
|
||||
|
||||
public static object Deserialize(int id, byte[] rawData)
|
||||
{
|
||||
if (s_types.TryGetValue((CmdType)id, out var type))
|
||||
return Serializer.Deserialize(type, new MemoryStream(rawData));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
FreeSR.Gateserver/Network/Handlers/Decoder/PacketDecoder.cs
Normal file
29
FreeSR.Gateserver/Network/Handlers/Decoder/PacketDecoder.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace FreeSR.Gateserver.Network.Handlers.Decoder
|
||||
{
|
||||
using DotNetty.Buffers;
|
||||
using DotNetty.Codecs;
|
||||
using DotNetty.Transport.Channels;
|
||||
using FreeSR.Gateserver.Network.Packet;
|
||||
using NLog;
|
||||
|
||||
internal class PacketDecoder : MessageToMessageDecoder<IByteBuffer>
|
||||
{
|
||||
private static readonly Logger s_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
protected override void Decode(IChannelHandlerContext context, IByteBuffer message, List<object> output)
|
||||
{
|
||||
var netPacket = new NetPacket();
|
||||
|
||||
DeserializationResult result;
|
||||
if ((result = netPacket.Deserialize(message)) != DeserializationResult.SUCC)
|
||||
{
|
||||
context.CloseAsync();
|
||||
s_log.Info("Closing connection, reason: " + result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
output.Add(netPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
namespace FreeSR.Gateserver.Network.Handlers.Decoder
|
||||
{
|
||||
using DotNetty.Buffers;
|
||||
using DotNetty.Codecs;
|
||||
using DotNetty.Transport.Channels;
|
||||
|
||||
internal class StarRailHeaderDecoder : ByteToMessageDecoder
|
||||
{
|
||||
private IByteBuffer _current;
|
||||
|
||||
public StarRailHeaderDecoder()
|
||||
{
|
||||
_current = Unpooled.Buffer();
|
||||
}
|
||||
|
||||
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output)
|
||||
{
|
||||
var allocated = Unpooled.Buffer();
|
||||
allocated.WriteBytes(_current);
|
||||
allocated.WriteBytes(input);
|
||||
_current = allocated;
|
||||
|
||||
byte[] lands = new byte[_current.ReadableBytes];
|
||||
_current.ReadBytes(lands);
|
||||
_current.ResetReaderIndex();
|
||||
|
||||
IByteBuffer packet;
|
||||
while ((packet = Process()) != null)
|
||||
output.Add(packet);
|
||||
}
|
||||
|
||||
private IByteBuffer Process()
|
||||
{
|
||||
if (_current.ReadableBytes < 12)
|
||||
return null;
|
||||
|
||||
_current.ReadInt(); // headMagic
|
||||
_current.ReadShort(); // CmdID
|
||||
int headerLength = _current.ReadShort();
|
||||
int payloadLength = _current.ReadInt();
|
||||
|
||||
int totalLength = 12 + headerLength + payloadLength + 4;
|
||||
_current.ResetReaderIndex();
|
||||
if (_current.ReadableBytes < totalLength)
|
||||
return null;
|
||||
|
||||
IByteBuffer result = _current.ReadBytes(totalLength);
|
||||
_current = _current.ReadBytes(_current.ReadableBytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
FreeSR.Gateserver/Network/Handlers/Encoder/PacketEncoder.cs
Normal file
19
FreeSR.Gateserver/Network/Handlers/Encoder/PacketEncoder.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace FreeSR.Gateserver.Network.Handlers.Encoder
|
||||
{
|
||||
using DotNetty.Buffers;
|
||||
using DotNetty.Codecs;
|
||||
using DotNetty.Transport.Channels;
|
||||
using FreeSR.Gateserver.Network.Packet;
|
||||
using NLog;
|
||||
|
||||
internal class PacketEncoder : MessageToByteEncoder<NetPacket>
|
||||
{
|
||||
private static readonly Logger s_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
protected override void Encode(IChannelHandlerContext context, NetPacket message, IByteBuffer output)
|
||||
{
|
||||
output.WriteBytes(message.Buf);
|
||||
s_log.Info($"Sent packet with cmdId {message.CmdId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
103
FreeSR.Gateserver/Network/Handlers/Manager/PacketHandler.cs
Normal file
103
FreeSR.Gateserver/Network/Handlers/Manager/PacketHandler.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
namespace FreeSR.Gateserver.Network.Handlers.Manager
|
||||
{
|
||||
using DotNetty.Transport.Channels;
|
||||
using FreeSR.Gateserver.Manager;
|
||||
using FreeSR.Gateserver.Network.Packet;
|
||||
using FreeSR.Proto;
|
||||
using NLog;
|
||||
using ProtoBuf;
|
||||
|
||||
internal class PacketHandler : ChannelHandlerAdapter
|
||||
{
|
||||
private static readonly Logger s_log = LogManager.GetCurrentClassLogger();
|
||||
private readonly NetSession _session;
|
||||
|
||||
public PacketHandler(NetSession session)
|
||||
{
|
||||
_session = session;
|
||||
}
|
||||
|
||||
public override void ChannelRead(IChannelHandlerContext context, object message)
|
||||
{
|
||||
NetPacket packet = message as NetPacket;
|
||||
if (packet.Data == null)
|
||||
{
|
||||
if (!SendDummyResponse(packet.CmdId))
|
||||
s_log.Warn($"CmdID {packet.CmdId} is undefined.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
s_log.Info($"Received packet {packet.CmdId}!");
|
||||
NotifyManager.Notify(_session, packet.CmdId, packet.Data);
|
||||
}
|
||||
|
||||
private bool SendDummyResponse(int id)
|
||||
{
|
||||
if (s_dummyTable.TryGetValue((CmdType)id, out CmdType rspId))
|
||||
{
|
||||
_session.Send(rspId, new DummyPacket());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Dictionary<CmdType, CmdType> s_dummyTable = new Dictionary<CmdType, CmdType>
|
||||
{
|
||||
{CmdType.GetLevelRewardTakenListCsReq, CmdType.GetLevelRewardTakenListScRsp},
|
||||
{CmdType.GetRogueScoreRewardInfoCsReq, CmdType.GetRogueScoreRewardInfoScRsp},
|
||||
{CmdType.GetGachaInfoCsReq, CmdType.GetGachaInfoScRsp},
|
||||
{CmdType.QueryProductInfoCsReq, CmdType.QueryProductInfoScRsp},
|
||||
{CmdType.GetQuestDataCsReq, CmdType.GetQuestDataScRsp},
|
||||
{CmdType.GetQuestRecordCsReq, CmdType.GetQuestRecordScRsp},
|
||||
{CmdType.GetFriendListInfoCsReq, CmdType.GetFriendListInfoScRsp},
|
||||
{CmdType.GetFriendApplyListInfoCsReq, CmdType.GetFriendApplyListInfoScRsp},
|
||||
{CmdType.GetCurAssistCsReq, CmdType.GetCurAssistScRsp},
|
||||
{CmdType.GetRogueHandbookDataCsReq, CmdType.GetRogueHandbookDataScRsp},
|
||||
{CmdType.GetDailyActiveInfoCsReq, CmdType.GetDailyActiveInfoScRsp},
|
||||
{CmdType.GetFightActivityDataCsReq, CmdType.GetFightActivityDataScRsp},
|
||||
{CmdType.GetMultipleDropInfoCsReq, CmdType.GetMultipleDropInfoScRsp},
|
||||
{CmdType.GetPlayerReturnMultiDropInfoCsReq, CmdType.GetPlayerReturnMultiDropInfoScRsp},
|
||||
{CmdType.GetShareDataCsReq, CmdType.GetShareDataScRsp},
|
||||
{CmdType.GetTreasureDungeonActivityDataCsReq, CmdType.GetTreasureDungeonActivityDataScRsp},
|
||||
{CmdType.PlayerReturnInfoQueryCsReq, CmdType.PlayerReturnInfoQueryScRsp},
|
||||
{CmdType.GetBasicInfoCsReq, CmdType.GetBasicInfoScRsp},
|
||||
{CmdType.GetHeroBasicTypeInfoCsReq, CmdType.GetHeroBasicTypeInfoScRsp},
|
||||
{CmdType.GetBagCsReq, CmdType.GetBagScRsp},
|
||||
{CmdType.GetPlayerBoardDataCsReq, CmdType.GetPlayerBoardDataScRsp},
|
||||
{CmdType.GetAvatarDataCsReq, CmdType.GetAvatarDataScRsp},
|
||||
{CmdType.GetAllLineupDataCsReq, CmdType.GetAllLineupDataScRsp},
|
||||
{CmdType.GetActivityScheduleConfigCsReq, CmdType.GetActivityScheduleConfigScRsp},
|
||||
{CmdType.GetMissionDataCsReq, CmdType.GetMissionDataScRsp},
|
||||
{CmdType.GetMissionEventDataCsReq, CmdType.GetMissionEventDataScRsp},
|
||||
{CmdType.GetChallengeCsReq, CmdType.GetChallengeScRsp},
|
||||
{CmdType.GetCurChallengeCsReq, CmdType.GetCurChallengeScRsp},
|
||||
{CmdType.GetRogueInfoCsReq, CmdType.GetRogueInfoScRsp},
|
||||
{CmdType.GetExpeditionDataCsReq, CmdType.GetExpeditionDataScRsp},
|
||||
{CmdType.GetRogueDialogueEventDataCsReq, CmdType.GetRogueDialogueEventDataScRsp},
|
||||
{CmdType.GetJukeboxDataCsReq, CmdType.GetJukeboxDataScRsp},
|
||||
{CmdType.SyncClientResVersionCsReq, CmdType.SyncClientResVersionScRsp},
|
||||
{CmdType.DailyFirstMeetPamCsReq, CmdType.DailyFirstMeetPamScRsp},
|
||||
{CmdType.GetMuseumInfoCsReq, CmdType.GetMuseumInfoScRsp},
|
||||
{CmdType.GetLoginActivityCsReq, CmdType.GetLoginActivityScRsp},
|
||||
{CmdType.GetRaidInfoCsReq, CmdType.GetRaidInfoScRsp},
|
||||
{CmdType.GetTrialActivityDataCsReq, CmdType.GetTrialActivityDataScRsp},
|
||||
{CmdType.GetBoxingClubInfoCsReq, CmdType.GetBoxingClubInfoScRsp},
|
||||
{CmdType.GetNpcStatusCsReq, CmdType.GetNpcStatusScRsp},
|
||||
{CmdType.TextJoinQueryCsReq, CmdType.TextJoinQueryScRsp},
|
||||
{CmdType.GetSpringRecoverDataCsReq, CmdType.GetSpringRecoverDataScRsp},
|
||||
{CmdType.GetChatFriendHistoryCsReq, CmdType.GetChatFriendHistoryScRsp},
|
||||
{CmdType.GetSecretKeyInfoCsReq, CmdType.GetSecretKeyInfoScRsp},
|
||||
{CmdType.GetVideoVersionKeyCsReq, CmdType.GetVideoVersionKeyScRsp},
|
||||
{CmdType.GetCurLineupDataCsReq, CmdType.GetCurLineupDataScRsp},
|
||||
{CmdType.GetCurBattleInfoCsReq, CmdType.GetCurBattleInfoScRsp},
|
||||
{CmdType.GetCurSceneInfoCsReq, CmdType.GetCurSceneInfoScRsp},
|
||||
{CmdType.GetPhoneDataCsReq, CmdType.GetPhoneDataScRsp},
|
||||
{CmdType.PlayerLoginFinishCsReq, CmdType.PlayerLoginFinishScRsp}
|
||||
};
|
||||
|
||||
[ProtoContract]
|
||||
private class DummyPacket { }
|
||||
}
|
||||
}
|
||||
32
FreeSR.Gateserver/Network/NetSession.cs
Normal file
32
FreeSR.Gateserver/Network/NetSession.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace FreeSR.Gateserver.Network
|
||||
{
|
||||
using DotNetty.Buffers;
|
||||
using DotNetty.Transport.Channels;
|
||||
using FreeSR.Gateserver.Network.Packet;
|
||||
using FreeSR.Proto;
|
||||
|
||||
internal class NetSession
|
||||
{
|
||||
private IChannel _channel;
|
||||
|
||||
public NetSession(IChannel channel)
|
||||
{
|
||||
_channel = channel;
|
||||
}
|
||||
|
||||
public async void Send<T>(CmdType cmdId, T data) where T : class
|
||||
{
|
||||
var packet = new NetPacket()
|
||||
{
|
||||
CmdId = (int)cmdId,
|
||||
Data = data
|
||||
};
|
||||
|
||||
var buffer = Unpooled.Buffer();
|
||||
packet.Serialize<T>(buffer);
|
||||
packet.Buf = buffer;
|
||||
|
||||
await _channel.WriteAndFlushAsync(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
FreeSR.Gateserver/Network/NetworkManager.cs
Normal file
65
FreeSR.Gateserver/Network/NetworkManager.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
namespace FreeSR.Gateserver.Network
|
||||
{
|
||||
using DotNetty.Transport.Bootstrapping;
|
||||
using DotNetty.Transport.Channels;
|
||||
using DotNetty.Transport.Channels.Sockets;
|
||||
using FreeSR.Gateserver.Manager;
|
||||
using FreeSR.Gateserver.Manager.Handlers;
|
||||
using FreeSR.Gateserver.Network.Handlers.Decoder;
|
||||
using FreeSR.Gateserver.Network.Handlers.Encoder;
|
||||
using FreeSR.Gateserver.Network.Handlers.Manager;
|
||||
using FreeSR.Shared;
|
||||
using FreeSR.Shared.Configuration;
|
||||
using System.Net;
|
||||
|
||||
internal sealed class NetworkManager : Singleton<NetworkManager>
|
||||
{
|
||||
private ServerBootstrap _bootstrap;
|
||||
private IChannel _serverChannel;
|
||||
|
||||
public async Task Initialize(NetworkConfiguration config)
|
||||
{
|
||||
// Notify handlers
|
||||
{
|
||||
NotifyManager.AddReqGroupHandler(typeof(PlayerReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(MailReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(TutorialReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(ItemReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(AvatarReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(LineupReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(MissionReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(QuestReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(ChallengeReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(SceneReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(GachaReqGroup));
|
||||
NotifyManager.AddReqGroupHandler(typeof(NPCReqGroup));
|
||||
|
||||
NotifyManager.Init();
|
||||
}
|
||||
|
||||
var bossGroup = new MultithreadEventLoopGroup();
|
||||
var workerGroup = new MultithreadEventLoopGroup();
|
||||
|
||||
_bootstrap = new ServerBootstrap()
|
||||
.Group(bossGroup, workerGroup)
|
||||
.Channel<TcpServerSocketChannel>()
|
||||
.Option(ChannelOption.SoBacklog, 120)
|
||||
.Option(ChannelOption.TcpNodelay, true)
|
||||
.Option(ChannelOption.SoKeepalive, true)
|
||||
.ChildHandler(
|
||||
new ActionChannelInitializer<IChannel>(channel =>
|
||||
{
|
||||
var session = new NetSession(channel);
|
||||
var pipeline = channel.Pipeline;
|
||||
|
||||
pipeline.AddFirst(new StarRailHeaderDecoder());
|
||||
pipeline.AddLast(new PacketDecoder());
|
||||
pipeline.AddLast(new PacketEncoder());
|
||||
pipeline.AddLast(new PacketHandler(session));
|
||||
})
|
||||
);
|
||||
|
||||
_serverChannel = await _bootstrap.BindAsync(IPAddress.Parse(config.Host), config.Port);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
FreeSR.Gateserver/Network/Packet/NetPacket.cs
Normal file
77
FreeSR.Gateserver/Network/Packet/NetPacket.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
namespace FreeSR.Gateserver.Network.Packet
|
||||
{
|
||||
using DotNetty.Buffers;
|
||||
using FreeSR.Gateserver.Network.Factory;
|
||||
using ProtoBuf;
|
||||
|
||||
internal class NetPacket
|
||||
{
|
||||
private const uint HeadMagicConst = 0x9d74c714;
|
||||
private const uint TailMagicConst = 0xd7a152c8;
|
||||
|
||||
public int CmdId { get; set; }
|
||||
public int HeadLen { get; set; }
|
||||
public uint HeadMagic { get; set; }
|
||||
public int PacketLen { get; set; }
|
||||
public byte[] RawData { get; set; }
|
||||
public uint TailMagic { get; set; }
|
||||
public object Data { get; set; }
|
||||
public IByteBuffer Buf { get; set; }
|
||||
|
||||
public NetPacket()
|
||||
{
|
||||
// NetPacket.
|
||||
}
|
||||
|
||||
public DeserializationResult Deserialize(IByteBuffer buf)
|
||||
{
|
||||
HeadMagic = buf.ReadUnsignedInt();
|
||||
if (HeadMagic != HeadMagicConst)
|
||||
return DeserializationResult.MAGIC_MISMATCH;
|
||||
|
||||
CmdId = buf.ReadShort();
|
||||
HeadLen = buf.ReadShort();
|
||||
PacketLen = buf.ReadInt();
|
||||
|
||||
if (buf.ReadableBytes < HeadLen + PacketLen + 4)
|
||||
return DeserializationResult.INVALID_LENGTH;
|
||||
|
||||
RawData = new byte[PacketLen];
|
||||
|
||||
_ = buf.ReadBytes(HeadLen);
|
||||
buf.ReadBytes(RawData);
|
||||
|
||||
TailMagic = buf.ReadUnsignedInt();
|
||||
if (TailMagic != TailMagicConst)
|
||||
return DeserializationResult.MAGIC_MISMATCH;
|
||||
|
||||
Data = ProtoFactory.Deserialize(CmdId, RawData);
|
||||
|
||||
return DeserializationResult.SUCC;
|
||||
}
|
||||
|
||||
public void Serialize<T>(IByteBuffer buf) where T : class
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
Serializer.Serialize(stream, Data as T);
|
||||
RawData = stream.ToArray();
|
||||
PacketLen = RawData.Length;
|
||||
|
||||
buf.WriteUnsignedShort((ushort)(HeadMagicConst >> 16));
|
||||
buf.WriteUnsignedShort(0xc714);
|
||||
buf.WriteShort(CmdId);
|
||||
buf.WriteShort(HeadLen);
|
||||
buf.WriteInt(PacketLen);
|
||||
buf.WriteBytes(RawData);
|
||||
buf.WriteUnsignedShort((ushort)(TailMagicConst >> 16));
|
||||
buf.WriteUnsignedShort(0x52c8);
|
||||
}
|
||||
}
|
||||
|
||||
internal enum DeserializationResult
|
||||
{
|
||||
SUCC = 1,
|
||||
INVALID_LENGTH,
|
||||
MAGIC_MISMATCH
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user