fork from 1.3

This commit is contained in:
moux23333
2024-01-27 21:06:07 +08:00
commit 22fc0b0848
1507 changed files with 24139 additions and 0 deletions

View 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;
}
}
}

View 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);
}
}
}

View File

@@ -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;
}
}
}

View 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}");
}
}
}

View 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 { }
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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
}
}