mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-03-03 17:05:21 +03:00
Implement room chat and leaves.
This commit is contained in:
parent
9aad0faf6b
commit
0fee2e1e13
@ -3,7 +3,6 @@ using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Syroot.Worms.IO
|
||||
{
|
||||
@ -19,29 +18,16 @@ namespace Syroot.Worms.IO
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to read with.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
|
||||
/// <param name="encoding">The 1-byte <see cref="Encoding"/> to use or <see langword="null"/> to use
|
||||
/// <see cref="Encoding.ASCII"/>.</param>
|
||||
/// <returns>The read string.</returns>
|
||||
public static unsafe string ReadFixedString(this Stream stream, int length)
|
||||
public static unsafe string ReadFixedString(this Stream stream, int length, Encoding? encoding = null)
|
||||
{
|
||||
// Ensure to not try to decode any bytes after the 0 termination.
|
||||
Span<byte> bytes = stackalloc byte[length];
|
||||
stream.Read(bytes);
|
||||
for (length = 0; length < bytes.Length && bytes[length] != 0; length++) ;
|
||||
return Encoding.ASCII.GetString(bytes.Slice(0, length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 0-terminated string which is stored in a fixed-size block of <paramref name="length"/> bytes.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to read with.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
|
||||
/// <returns>The read string.</returns>
|
||||
public static async Task<string> ReadFixedStringAsync(this Stream stream, int length)
|
||||
{
|
||||
// Ensure to not try to decode any bytes after the 0 termination.
|
||||
byte[] bytes = new byte[length];
|
||||
await stream.ReadAsync(bytes, 0, length);
|
||||
for (length = 0; length < bytes.Length && bytes[length] != 0; length++) ;
|
||||
return Encoding.ASCII.GetString(bytes, 0, length);
|
||||
return (encoding ?? Encoding.ASCII).GetString(bytes.Slice(0, length));
|
||||
}
|
||||
|
||||
/// <s
|
||||
@ -73,28 +59,16 @@ namespace Syroot.Worms.IO
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to write with.</param>
|
||||
/// <param name="value">The string to write.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size block takes.</param>
|
||||
public static void WriteFixedString(this Stream stream, string value, int length)
|
||||
/// <param name="encoding">The 1-byte <see cref="Encoding"/> to use or <see langword="null"/> to use
|
||||
/// <see cref="Encoding.ASCII"/>.</param>
|
||||
public static void WriteFixedString(this Stream stream, string value, int length, Encoding? encoding = null)
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[length];
|
||||
if (value != null)
|
||||
Encoding.ASCII.GetBytes(value.AsSpan(), bytes);
|
||||
(encoding ?? Encoding.ASCII).GetBytes(value.AsSpan(), bytes);
|
||||
stream.Write(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given string into a fixed-size block of <paramref name="length"/> bytes and 0-terminates it.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to write with.</param>
|
||||
/// <param name="value">The string to write.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size block takes.</param>
|
||||
public static async Task WriteFixedStringAsync(this Stream stream, string value, int length)
|
||||
{
|
||||
byte[] bytes = new byte[length];
|
||||
if (value != null)
|
||||
Encoding.ASCII.GetBytes(value.AsSpan(), bytes);
|
||||
await stream.WriteAsync(bytes, 0, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the unmanaged representation of a struct of type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
|
26
src/tool/Syroot.Worms.Worms2.GameServer/Encodings.cs
Normal file
26
src/tool/Syroot.Worms.Worms2.GameServer/Encodings.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Worms2.GameServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents additional code pages.
|
||||
/// </summary>
|
||||
internal static class Encodings
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Windows-1252 encoding (codepage 1252).</summary>
|
||||
internal static readonly Encoding Windows1252;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes static members of the <see cref="Encodings"/> class.
|
||||
/// </summary>
|
||||
static Encodings()
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Windows1252 = Encoding.GetEncoding(1252);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
/// <remarks>Names are in ISO 3166 Alpha-2 notation.</remarks>
|
||||
public enum Nation : byte
|
||||
{
|
||||
/// <summary>No flag.</summary>
|
||||
None,
|
||||
/// <summary>United Kingdom</summary>
|
||||
UK,
|
||||
|
@ -6,12 +6,32 @@ using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Worms2.GameServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a unit of communication between Worms 2 client and server.
|
||||
/// </summary>
|
||||
internal class Packet
|
||||
{
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Packet"/> class.
|
||||
/// </summary>
|
||||
internal Packet() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Packet"/> class with the given contents.
|
||||
/// </summary>
|
||||
/// <param name="code">The <see cref="PacketCode"/> describing the action of the packet.</param>
|
||||
/// <param name="value0">A parameter for the action.</param>
|
||||
/// <param name="value1">A parameter for the action.</param>
|
||||
/// <param name="value2">A parameter for the action.</param>
|
||||
/// <param name="value3">A parameter for the action.</param>
|
||||
/// <param name="value4">A parameter for the action.</param>
|
||||
/// <param name="value10">A parameter for the action.</param>
|
||||
/// <param name="data">A textual parameter for the action.</param>
|
||||
/// <param name="error">An error code returned from the server after executing the action.</param>
|
||||
/// <param name="name">A named parameter for the action.</param>
|
||||
/// <param name="session">A <see cref="SessionInfo"/> for the action.</param>
|
||||
internal Packet(PacketCode code,
|
||||
int? value0 = null, int? value1 = null, int? value2 = null, int? value3 = null, int? value4 = null,
|
||||
int? value10 = null, string? data = null, int? error = null,
|
||||
@ -32,16 +52,59 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets <see cref="PacketCode"/> describing the action of the packet.
|
||||
/// </summary>
|
||||
internal PacketCode Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a parameter for the action.
|
||||
/// </summary>
|
||||
internal int? Value0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a parameter for the action.
|
||||
/// </summary>
|
||||
internal int? Value1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a parameter for the action.
|
||||
/// </summary>
|
||||
internal int? Value2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a parameter for the action.
|
||||
/// </summary>
|
||||
internal int? Value3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a parameter for the action.
|
||||
/// </summary>
|
||||
internal int? Value4 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a parameter for the action.
|
||||
/// </summary>
|
||||
internal int? Value10 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a textual parameter for the action.
|
||||
/// </summary>
|
||||
internal string? Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an error code returned from the server after executing the action.
|
||||
/// </summary>
|
||||
internal int? Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a named parameter for the action.
|
||||
/// </summary>
|
||||
internal string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a <see cref="SessionInfo"/> for the action.
|
||||
/// </summary>
|
||||
internal SessionInfo? Session { get; set; }
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
@ -68,6 +131,10 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
|
||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Blocks and reads the packet data from the given <paramref name="stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to read the packet data from.</param>
|
||||
internal void Receive(Stream stream)
|
||||
{
|
||||
int dataLength = 0;
|
||||
@ -80,12 +147,16 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
if (flags.HasFlag(Flags.HasValue4)) Value4 = stream.ReadInt32();
|
||||
if (flags.HasFlag(Flags.HasValue10)) Value10 = stream.ReadInt32();
|
||||
if (flags.HasFlag(Flags.HasDataLength)) dataLength = stream.ReadInt32();
|
||||
if (flags.HasFlag(Flags.HasData) && dataLength != 0) Data = stream.ReadFixedString(dataLength);
|
||||
if (flags.HasFlag(Flags.HasData) && dataLength != 0) Data = stream.ReadFixedString(dataLength, Encodings.Windows1252);
|
||||
if (flags.HasFlag(Flags.HasError)) Error = stream.ReadInt32();
|
||||
if (flags.HasFlag(Flags.HasUserName)) Name = stream.ReadFixedString(20);
|
||||
if (flags.HasFlag(Flags.HasUserInfo)) Session = stream.ReadStruct<SessionInfo>();
|
||||
if (flags.HasFlag(Flags.HasName)) Name = stream.ReadFixedString(20, Encodings.Windows1252);
|
||||
if (flags.HasFlag(Flags.HasSession)) Session = stream.ReadStruct<SessionInfo>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Blocks and writes the packet data to the given <paramref name="stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to write the packet data to.</param>
|
||||
internal void Send(Stream stream)
|
||||
{
|
||||
stream.WriteInt32((int)Code);
|
||||
@ -98,11 +169,11 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
if (Value10.HasValue) stream.WriteInt32(Value10.Value);
|
||||
if (Data != null)
|
||||
{
|
||||
stream.WriteInt32(Data.Length);
|
||||
stream.WriteFixedString(Data, Data.Length);
|
||||
stream.WriteInt32(Data.Length + 1);
|
||||
stream.WriteFixedString(Data, Data.Length + 1, Encodings.Windows1252);
|
||||
}
|
||||
if (Error.HasValue) stream.WriteInt32(Error.Value);
|
||||
if (Name != null) stream.WriteFixedString(Name, 20);
|
||||
if (Name != null) stream.WriteFixedString(Name, 20, Encodings.Windows1252);
|
||||
if (Session.HasValue) stream.WriteStruct(Session.Value);
|
||||
}
|
||||
|
||||
@ -123,8 +194,8 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
flags |= Flags.HasData;
|
||||
}
|
||||
if (Error.HasValue) flags |= Flags.HasError;
|
||||
if (Name != null) flags |= Flags.HasUserName;
|
||||
if (Session.HasValue) flags |= Flags.HasUserInfo;
|
||||
if (Name != null) flags |= Flags.HasName;
|
||||
if (Session.HasValue) flags |= Flags.HasSession;
|
||||
return flags;
|
||||
}
|
||||
|
||||
@ -143,8 +214,8 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
HasDataLength = 1 << 5,
|
||||
HasData = 1 << 6,
|
||||
HasError = 1 << 7,
|
||||
HasUserName = 1 << 8,
|
||||
HasUserInfo = 1 << 9
|
||||
HasName = 1 << 8,
|
||||
HasSession = 1 << 9
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace Syroot.Worms.Worms2.GameServer
|
||||
using System.Net;
|
||||
|
||||
namespace Syroot.Worms.Worms2.GameServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a room in which users can meet, chat, and host games.
|
||||
@ -13,11 +15,13 @@
|
||||
/// <param name="id">The unique numerical identifier of the room.</param>
|
||||
/// <param name="name">The name of the room as given by the creator.</param>
|
||||
/// <param name="nation">The flag displayed with the room.</param>
|
||||
internal Room(int id, string name, Nation nation)
|
||||
/// <param name="ipAddress">The IP address of the creator of the room.</param>
|
||||
internal Room(int id, string name, Nation nation, IPAddress ipAddress)
|
||||
{
|
||||
ID = id;
|
||||
Name = name;
|
||||
Session = new SessionInfo(nation, SessionType.Room);
|
||||
IPAddress = ipAddress;
|
||||
}
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
@ -36,5 +40,10 @@
|
||||
/// Gets the <see cref="SessionInfo"/> describing the room.
|
||||
/// </summary>
|
||||
internal SessionInfo Session { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IP address of the creator of the room.
|
||||
/// </summary>
|
||||
internal IPAddress IPAddress { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Syroot.ColoredConsole;
|
||||
|
||||
@ -18,7 +17,7 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private int _lastID;
|
||||
private int _lastID = 0x1000; // start at an offset to prevent bugs with chat
|
||||
private readonly List<User> _users = new List<User>();
|
||||
private readonly List<Room> _rooms = new List<Room>();
|
||||
private readonly List<Game> _games = new List<Game>();
|
||||
@ -39,9 +38,10 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
[PacketCode.CreateRoom] = OnCreateRoom,
|
||||
[PacketCode.Join] = OnJoinRoom,
|
||||
[PacketCode.LeaveRoom] = OnLeaveRoom,
|
||||
[PacketCode.CloseRoom] = OnCloseRoom,
|
||||
[PacketCode.CreateGame] = OnCreateGame,
|
||||
[PacketCode.ChatRoom] = OnChatRoom,
|
||||
[PacketCode.ConnectGame] = OnConnectGame
|
||||
[PacketCode.ConnectGame] = OnConnectGame,
|
||||
};
|
||||
|
||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||
@ -74,8 +74,6 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
ColorConsole.WriteLine(Color.Magenta, $"{connection.RemoteEndPoint} << {packet}");
|
||||
}
|
||||
|
||||
private int GetNextID() => Interlocked.Increment(ref _lastID);
|
||||
|
||||
private User? GetUser(PacketConnection connection)
|
||||
{
|
||||
foreach (User user in _users)
|
||||
@ -185,7 +183,7 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
&& packet.Session.HasValue
|
||||
&& !_users.Any(x => x.Name.Equals(packet.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||
{
|
||||
User newUser = new User(connection, GetNextID(), packet.Name, packet.Session.Value.Nation);
|
||||
User newUser = new User(connection, ++_lastID, packet.Name, packet.Session.Value.Nation);
|
||||
|
||||
// Notify other users about new user.
|
||||
foreach (User user in _users)
|
||||
@ -206,6 +204,7 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
else
|
||||
{
|
||||
SendPacket(connection, new Packet(PacketCode.LoginReply,
|
||||
value1: 0,
|
||||
error: 1));
|
||||
}
|
||||
}
|
||||
@ -221,23 +220,25 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
&& packet.Session.HasValue
|
||||
&& !_rooms.Any(x => x.Name.Equals(packet.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||
{
|
||||
Room newRoom = new Room(GetNextID(), packet.Name, packet.Session.Value.Nation);
|
||||
Room newRoom = new Room(++_lastID, packet.Name, packet.Session.Value.Nation,
|
||||
connection.RemoteEndPoint.Address);
|
||||
_rooms.Add(newRoom);
|
||||
|
||||
// Send reply to creator.
|
||||
SendPacket(connection, new Packet(PacketCode.CreateRoomReply,
|
||||
value1: newRoom.ID,
|
||||
error: 0));
|
||||
|
||||
// Notify other users about new room.
|
||||
foreach (User user in _users.Where(x => x != fromUser))
|
||||
{
|
||||
SendPacket(user.Connection, new Packet(PacketCode.CreateRoom,
|
||||
value1: newRoom.ID,
|
||||
value4: 0,
|
||||
data: String.Empty, // do not report creator IP
|
||||
name: newRoom.Name,
|
||||
session: newRoom.Session));
|
||||
}
|
||||
|
||||
// Send reply to creator.
|
||||
SendPacket(connection, new Packet(PacketCode.CreateRoomReply,
|
||||
value1: newRoom.ID,
|
||||
error: 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -261,7 +262,7 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
foreach (User user in _users.Where(x => x != fromUser))
|
||||
{
|
||||
SendPacket(user.Connection, new Packet(PacketCode.Join,
|
||||
value1: fromUser.RoomID,
|
||||
value2: fromUser.RoomID,
|
||||
value10: fromUser.ID));
|
||||
}
|
||||
|
||||
@ -278,26 +279,84 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
|
||||
private void OnLeaveRoom(PacketConnection connection, Packet packet)
|
||||
{
|
||||
SendPacket(connection, new Packet(PacketCode.LeaveRoomReply,
|
||||
error: 0));
|
||||
User? fromUser = GetUser(connection);
|
||||
if (fromUser == null)
|
||||
return;
|
||||
|
||||
// Require left room ID and user ID.
|
||||
if (packet.Value2.HasValue && packet.Value2 == fromUser.RoomID
|
||||
&& packet.Value10.HasValue && packet.Value10 == fromUser.ID)
|
||||
{
|
||||
LeaveRoom(fromUser);
|
||||
// Reply to leaver.
|
||||
SendPacket(connection, new Packet(PacketCode.LeaveRoomReply,
|
||||
error: 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reply to leaver.
|
||||
SendPacket(connection, new Packet(PacketCode.LeaveRoomReply,
|
||||
error: 1));
|
||||
}
|
||||
}
|
||||
|
||||
private void LeaveRoom(User fromUser)
|
||||
{
|
||||
// Close an abandoned room.
|
||||
bool roomClosed = fromUser.RoomID != 0 && !_users.Any(x => x != fromUser && x.RoomID == fromUser.RoomID);
|
||||
if (roomClosed)
|
||||
_rooms.Remove(_rooms.Single(x => x.ID == fromUser.RoomID));
|
||||
|
||||
// Notify other users.
|
||||
foreach (User user in _users.Where(x => x != fromUser))
|
||||
{
|
||||
// Notify room leave, if any.
|
||||
if (fromUser.RoomID != 0)
|
||||
{
|
||||
SendPacket(user.Connection, new Packet(PacketCode.LeaveRoom,
|
||||
value2: fromUser.RoomID,
|
||||
value10: fromUser.ID));
|
||||
}
|
||||
// Notify room close, if any.
|
||||
if (roomClosed)
|
||||
{
|
||||
SendPacket(user.Connection, new Packet(PacketCode.CloseRoom,
|
||||
value10: fromUser.RoomID));
|
||||
}
|
||||
}
|
||||
|
||||
// Update user room.
|
||||
fromUser.RoomID = 0;
|
||||
}
|
||||
|
||||
private void OnDisconnectUser(PacketConnection connection)
|
||||
{
|
||||
User? disconnectedUser = GetUser(connection);
|
||||
if (disconnectedUser == null)
|
||||
User? fromUser = GetUser(connection);
|
||||
if (fromUser == null)
|
||||
return;
|
||||
|
||||
_users.Remove(disconnectedUser);
|
||||
_users.Remove(fromUser);
|
||||
|
||||
// Notify other users.
|
||||
LeaveRoom(fromUser);
|
||||
|
||||
// Notify user disconnect.
|
||||
foreach (User user in _users)
|
||||
{
|
||||
SendPacket(user.Connection, new Packet(PacketCode.DisconnectUser,
|
||||
value10: disconnectedUser.ID));
|
||||
value10: fromUser.ID));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCloseRoom(PacketConnection connection, Packet packet)
|
||||
{
|
||||
User? fromUser = GetUser(connection);
|
||||
if (fromUser == null)
|
||||
return;
|
||||
|
||||
// Simply reply success to client, the server decides when to actually close rooms.
|
||||
SendPacket(connection, new Packet(PacketCode.CloseRoomReply, error: 0));
|
||||
}
|
||||
|
||||
private void OnCreateGame(PacketConnection connection, Packet packet)
|
||||
{
|
||||
SendPacket(connection, new Packet(PacketCode.CreateGameReply,
|
||||
@ -307,8 +366,58 @@ namespace Syroot.Worms.Worms2.GameServer
|
||||
|
||||
private void OnChatRoom(PacketConnection connection, Packet packet)
|
||||
{
|
||||
SendPacket(connection, new Packet(PacketCode.ChatRoomReply,
|
||||
error: 0));
|
||||
User? fromUser = GetUser(connection);
|
||||
if (fromUser == null)
|
||||
return;
|
||||
|
||||
// Requires user ID, target ID, and message data.
|
||||
if (!packet.Value0.HasValue || !packet.Value3.HasValue || packet.Data == null)
|
||||
return;
|
||||
|
||||
int targetID = packet.Value3.Value;
|
||||
string prefix;
|
||||
if (packet.Data.StartsWith(prefix = $"GRP:[ {fromUser.Name} ] ", StringComparison.InvariantCulture))
|
||||
{
|
||||
// Check if user can access the room.
|
||||
if (fromUser.RoomID == targetID)
|
||||
{
|
||||
// Notify all users of the room.
|
||||
string message = packet.Data.Substring(prefix.Length);
|
||||
foreach (User user in _users.Where(x => x.RoomID == fromUser.RoomID && x != fromUser))
|
||||
{
|
||||
SendPacket(user.Connection, new Packet(PacketCode.ChatRoom,
|
||||
value0: fromUser.ID,
|
||||
value3: user.RoomID,
|
||||
data: prefix + message));
|
||||
}
|
||||
// Notify sender.
|
||||
SendPacket(connection, new Packet(PacketCode.ChatRoomReply, error: 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
SendPacket(connection, new Packet(PacketCode.ChatRoomReply, error: 1));
|
||||
}
|
||||
}
|
||||
else if (packet.Data.StartsWith(prefix = $"PRV:[ {fromUser.Name} ] ", StringComparison.InvariantCulture))
|
||||
{
|
||||
// Check if user can access the user.
|
||||
User? user = _users.FirstOrDefault(x => x.RoomID == fromUser.RoomID && x.ID == targetID);
|
||||
if (user == null)
|
||||
{
|
||||
SendPacket(connection, new Packet(PacketCode.ChatRoomReply, error: 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Notify receiver of the message.
|
||||
string message = packet.Data.Substring(prefix.Length);
|
||||
SendPacket(user.Connection, new Packet(PacketCode.ChatRoom,
|
||||
value0: fromUser.ID,
|
||||
value3: user.ID,
|
||||
data: prefix + message));
|
||||
// Notify sender.
|
||||
SendPacket(connection, new Packet(PacketCode.ChatRoomReply, error: 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConnectGame(PacketConnection connection, Packet packet)
|
||||
|
@ -8,6 +8,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Syroot.ColoredConsole" Version="1.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
|
||||
<ProjectReference Include="..\..\library\Syroot.Worms\Syroot.Worms.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
Loading…
x
Reference in New Issue
Block a user