enter intro cutscene

This commit is contained in:
Naruse
2026-04-20 12:40:38 +08:00
parent 2826239284
commit 279da58dc1
81 changed files with 7279 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
using MikuSB.Enums.Packet;
using MikuSB.GameServer.Game.Player;
using MikuSB.GameServer.Server.Packet;
using MikuSB.TcpSharp;
using MikuSB.Util;
using System.Buffers;
using System.Net;
using System.Net.Sockets;
namespace MikuSB.GameServer.Server;
public class Connection(Socket socket, IPEndPoint remote) : SocketConnection(socket, remote)
{
private static readonly Logger Logger = new("GameServer");
public PlayerInstance? Player { get; set; }
private static readonly HashSet<string> DummyPacketNames =
[
];
public override async void Start()
{
Logger.Info($"New connection from {RemoteEndPoint}.");
State = SessionStateEnum.WAITING_FOR_TOKEN;
await ReceiveLoop();
}
public override void Stop(bool isServerStop = false)
{
Player?.OnLogoutAsync();
SocketListener.UnregisterConnection(this);
base.Stop(isServerStop);
}
public static int GetInt32(byte[] buf, int index)
{
int networkValue = BitConverter.ToInt32(buf, index);
return IPAddress.NetworkToHostOrder((int)networkValue);
}
protected async Task ReceiveLoop()
{
try
{
var stream = new NetworkStream(Socket, ownsSocket: false);
while (SocketConnected())
{
var decodedPacket = await new PacketCodec().ReadPacketAsync(stream, CancelToken.Token);
if (decodedPacket == null)
{
Logger.Info("Client disconnected");
break;
}
switch (decodedPacket.Framing)
{
case PacketFraming.FourByteLittleEndianLength:
case PacketFraming.TwoByteBigEndianLength:
Framing = decodedPacket.Framing;
LogPacket("Recv", decodedPacket.CmdId, decodedPacket.Body.ToArray(),Framing);
await HandlePacket(decodedPacket.CmdId, decodedPacket.Body.ToArray());
break;
case PacketFraming.Control:
Logger.Info("Control packet received");
// Handle control packet if needed
break;
case PacketFraming.Unknown:
Logger.Warn("Unknown packet format received");
break;
}
}
}
catch (OperationCanceledException)
{
Logger.Info("ReceiveLoop cancelled");
}
catch (Exception ex)
{
Logger.Info($"ReceiveLoop error: {ex}");
}
finally
{
Socket.Close();
}
Stop();
}
private async Task HandlePacket(ushort opcode, 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, payload, (ushort)DownStreamSeqNo);
}
catch (Exception e)
{
Logger.Error(e.Message, e);
}
return;
}
if (ConfigManager.Config.ServerOption.EnableDebug &&
ConfigManager.Config.ServerOption.DebugNoHandlerPacket && !IgnoreLog.Contains(opcode))
Logger.Error($"No handler found for {packetName}({opcode})");
//if (ConfigManager.Config.ServerOption.AutoSendResponseWhenNoHandler)
//{
// await SendDummy(packetName);
//}
}
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);
}
}

View File

@@ -0,0 +1,13 @@
using MikuSB.TcpSharp;
namespace MikuSB.GameServer.Server;
public class Listener : SocketListener
{
public static Connection? GetActiveConnection(int uid)
{
var con = Connections.Values.FirstOrDefault(c =>
(c as Connection)?.Player?.Uid == uid && c.State == SessionStateEnum.ACTIVE) as Connection;
return con;
}
}

View File

@@ -0,0 +1,6 @@
namespace MikuSB.GameServer.Server.Packet;
public abstract class Handler
{
public abstract Task OnHandle(Connection connection, byte[] data, ushort SeqNo = 0);
}

View File

@@ -0,0 +1,31 @@
using System.Reflection;
namespace MikuSB.GameServer.Server.Packet;
public static class HandlerManager
{
public static Dictionary<int, Handler> handlers = [];
public static void Init()
{
var classes = Assembly.GetExecutingAssembly().GetTypes(); // Get all classes in the assembly
foreach (var cls in classes)
{
var attribute = (Opcode?)Attribute.GetCustomAttribute(cls, typeof(Opcode));
if (attribute != null) handlers.Add(attribute.CmdId, (Handler)Activator.CreateInstance(cls)!);
}
}
public static Handler? GetHandler(int cmdId)
{
try
{
return handlers[cmdId];
}
catch
{
return null;
}
}
}

View File

@@ -0,0 +1,7 @@
namespace MikuSB.GameServer.Server.Packet;
[AttributeUsage(AttributeTargets.Class)]
public class Opcode(int cmdId) : Attribute
{
public int CmdId = cmdId;
}

View File

@@ -0,0 +1,50 @@
using MikuSB.Data;
using MikuSB.Database;
using MikuSB.Database.Account;
using MikuSB.Database.Player;
using MikuSB.GameServer.Game.Player;
using MikuSB.GameServer.Server.Packet.Send.Login;
using MikuSB.Proto;
using MikuSB.TcpSharp;
using MikuSB.Util;
namespace MikuSB.GameServer.Server.Packet.Recv.Login;
[Opcode(CmdIds.ReqLogin)]
public class HandlerReqLogin : Handler
{
public override async Task OnHandle(Connection connection, byte[] data, ushort seqNo)
{
var req = ReqLogin.Parser.ParseFrom(data);
var account = AccountData.GetAccountByUid(1);
if (account == null)
{
AccountData.CreateAccount("MIKU", 0, "");
account = AccountData.GetAccountByUid(1);
if (account == null)
{
await connection.SendPacket(CmdIds.NtfLogout);
return;
}
}
if (!ResourceManager.IsLoaded)
// resource manager not loaded, return
return;
var prev = Listener.GetActiveConnection(account.Uid);
if (prev != null)
{
await connection.SendPacket(CmdIds.NtfLogout);
prev.Stop();
}
connection.State = SessionStateEnum.WAITING_FOR_LOGIN;
var pd = DatabaseHelper.GetInstance<PlayerGameData>(account.Uid);
connection.Player = pd == null ? new PlayerInstance(account.Uid) : new PlayerInstance(pd);
connection.DebugFile = Path.Combine(ConfigManager.Config.Path.LogPath, "Debug/", $"{account.Uid}/",
$"Debug-{DateTime.Now:yyyy-MM-dd HH-mm-ss}.log");
await connection.Player.OnEnterGame();
connection.Player.Connection = connection;
await connection.SendPacket(new PacketRspLogin(connection.Player!));
}
}

View File

@@ -0,0 +1,29 @@
using MikuSB.GameServer.Game.Player;
using MikuSB.TcpSharp;
using MikuSB.Proto;
using MikuSB.Util.Extensions;
namespace MikuSB.GameServer.Server.Packet.Send.Login;
public class PacketRspLogin : BasePacket
{
public PacketRspLogin(PlayerInstance player) : base(CmdIds.RspLogin)
{
var proto = new RspLogin
{
Timestamp = (uint)Extensions.GetUnixSec(),
WorldChannel = 1,
AreaId = 1,
Data = new Player
{
Pid = (ulong)player.Data.Uid,
Account = player.Data.Name,
Name = player.Data.Name,
Level = 80
},
NeedRename = false
};
SetData(proto);
}
}