Skip to content

Commit

Permalink
Merge pull request #583 from MUnique/dev/#580-fix-read-mail
Browse files Browse the repository at this point in the history
Added extended message for mails
  • Loading branch information
sven-n authored Jan 21, 2025
2 parents d803424 + 8c1a52d commit 63e21f1
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 0 deletions.
22 changes: 22 additions & 0 deletions docs/Packets/C4-C7-OpenLetterExtended_by-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# C4 C7 - OpenLetterExtended (by server)

## Is sent when

After the player requested to read a letter.

## Causes the following actions on the client side

The letter is opened in a new dialog.

## Structure

| Index | Length | Data Type | Value | Description |
|-------|--------|-----------|-------|-------------|
| 0 | 1 | Byte | 0xC4 | [Packet type](PacketTypes.md) |
| 1 | 2 | Short | | Packet header - length of the packet |
| 3 | 1 | Byte | 0xC7 | Packet header - packet type identifier |
| 4 | 2 | ShortLittleEndian | | LetterIndex |
| 6 | 42 | Binary | | SenderAppearance |
| 48 | 1 | Byte | | Rotation |
| 49 | 1 | Byte | | Animation |
| 50 | | String | | Message |
1 change: 1 addition & 0 deletions docs/Packets/ServerToClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@
* [C1 C5 - LetterSendResponse (by server)](C1-C5-LetterSendResponse_by-server.md)
* [C3 C6 - AddLetter (by server)](C3-C6-AddLetter_by-server.md)
* [C4 C7 - OpenLetter (by server)](C4-C7-OpenLetter_by-server.md)
* [C4 C7 - OpenLetterExtended (by server)](C4-C7-OpenLetterExtended_by-server.md)
* [C1 C8 - RemoveLetter (by server)](C1-C8-RemoveLetter_by-server.md)
* [C3 CA - ChatRoomConnectionInfo (by server)](C3-CA-ChatRoomConnectionInfo_by-server.md)
* [C3 CB - FriendInvitationResult (by server)](C3-CB-FriendInvitationResult_by-server.md)
Expand Down
64 changes: 64 additions & 0 deletions src/GameServer/RemoteView/Messenger/ShowLetterExtendedPlugIn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// <copyright file="ShowLetterExtendedPlugIn.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>

namespace MUnique.OpenMU.GameServer.RemoteView.Messenger;

using System.Runtime.InteropServices;
using MUnique.OpenMU.DataModel.Entities;
using MUnique.OpenMU.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.Network.PlugIns;
using MUnique.OpenMU.PlugIns;

/// <summary>
/// The default implementation of the <see cref="IShowLetterPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn(nameof(ShowLetterExtendedPlugIn), "The extended implementation of the IShowLetterPlugIn which is forwarding everything to the game client with specific data packets.")]
[Guid("9FC6D771-FCCE-4780-B68E-5FBFF3FE1EB0")]
[MinimumClient(106, 3, ClientLanguage.Invariant)]
public class ShowLetterExtendedPlugIn : IShowLetterPlugIn
{
private readonly RemotePlayer _player;

/// <summary>
/// Initializes a new instance of the <see cref="ShowLetterExtendedPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public ShowLetterExtendedPlugIn(RemotePlayer player) => this._player = player;

/// <inheritdoc/>
public async ValueTask ShowLetterAsync(LetterBody letter)
{
var connection = this._player.Connection;
if (connection is null || this._player.SelectedCharacter is null)
{
return;
}

var appearanceSerializer = this._player.AppearanceSerializer;
var letterIndex = this._player.SelectedCharacter.Letters.IndexOf(letter.Header!);
int Write()
{
var size = OpenLetterExtendedRef.GetRequiredSize(letter.Message);
var span = connection.Output.GetSpan(size)[..size];
var result = new OpenLetterExtendedRef(span)
{
LetterIndex = (ushort)letterIndex,
Animation = letter.Animation,
Rotation = letter.Rotation,
Message = letter.Message,
};

if (letter.SenderAppearance is not null)
{
appearanceSerializer.WriteAppearanceData(result.SenderAppearance, letter.SenderAppearance, false);
}

return size;
}

await connection.SendAsync(Write).ConfigureAwait(false);
}
}
36 changes: 36 additions & 0 deletions src/Network/Packets/ServerToClient/ConnectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5546,6 +5546,42 @@ int WritePacket()
await connection.SendAsync(WritePacket).ConfigureAwait(false);
}

/// <summary>
/// Sends a <see cref="OpenLetterExtended" /> to this connection.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="letterIndex">The letter index.</param>
/// <param name="senderAppearance">The sender appearance.</param>
/// <param name="rotation">The rotation.</param>
/// <param name="animation">The animation.</param>
/// <param name="message">The message.</param>
/// <remarks>
/// Is sent by the server when: After the player requested to read a letter.
/// Causes reaction on client side: The letter is opened in a new dialog.
/// </remarks>
public static async ValueTask SendOpenLetterExtendedAsync(this IConnection? connection, ushort @letterIndex, Memory<byte> @senderAppearance, byte @rotation, byte @animation, string @message)
{
if (connection is null)
{
return;
}

int WritePacket()
{
var length = OpenLetterExtendedRef.GetRequiredSize(message);
var packet = new OpenLetterExtendedRef(connection.Output.GetSpan(length)[..length]);
packet.LetterIndex = @letterIndex;
@senderAppearance.Span.CopyTo(packet.SenderAppearance);
packet.Rotation = @rotation;
packet.Animation = @animation;
packet.Message = @message;

return packet.Header.Length;
}

await connection.SendAsync(WritePacket).ConfigureAwait(false);
}

/// <summary>
/// Sends a <see cref="RemoveLetter" /> to this connection.
/// </summary>
Expand Down
121 changes: 121 additions & 0 deletions src/Network/Packets/ServerToClient/ServerToClientPackets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26790,6 +26790,127 @@ public string Message
}


/// <summary>
/// Is sent by the server when: After the player requested to read a letter.
/// Causes reaction on client side: The letter is opened in a new dialog.
/// </summary>
public readonly struct OpenLetterExtended
{
private readonly Memory<byte> _data;

/// <summary>
/// Initializes a new instance of the <see cref="OpenLetterExtended"/> struct.
/// </summary>
/// <param name="data">The underlying data.</param>
public OpenLetterExtended(Memory<byte> data)
: this(data, true)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="OpenLetterExtended"/> struct.
/// </summary>
/// <param name="data">The underlying data.</param>
/// <param name="initialize">If set to <c>true</c>, the header data is automatically initialized and written to the underlying span.</param>
private OpenLetterExtended(Memory<byte> data, bool initialize)
{
this._data = data;
if (initialize)
{
var header = this.Header;
header.Type = HeaderType;
header.Code = Code;
header.Length = (ushort)data.Length;
}
}

/// <summary>
/// Gets the header type of this data packet.
/// </summary>
public static byte HeaderType => 0xC4;

/// <summary>
/// Gets the operation code of this data packet.
/// </summary>
public static byte Code => 0xC7;

/// <summary>
/// Gets the header of this packet.
/// </summary>
public C4Header Header => new (this._data);

/// <summary>
/// Gets or sets the letter index.
/// </summary>
public ushort LetterIndex
{
get => ReadUInt16LittleEndian(this._data.Span[4..]);
set => WriteUInt16LittleEndian(this._data.Span[4..], value);
}

/// <summary>
/// Gets or sets the sender appearance.
/// </summary>
public Span<byte> SenderAppearance
{
get => this._data.Slice(6, 42).Span;
}

/// <summary>
/// Gets or sets the rotation.
/// </summary>
public byte Rotation
{
get => this._data.Span[48];
set => this._data.Span[48] = value;
}

/// <summary>
/// Gets or sets the animation.
/// </summary>
public byte Animation
{
get => this._data.Span[49];
set => this._data.Span[49] = value;
}

/// <summary>
/// Gets or sets the message.
/// </summary>
public string Message
{
get => this._data.Span.ExtractString(50, this._data.Length - 50, System.Text.Encoding.UTF8);
set => this._data.Slice(50).Span.WriteString(value, System.Text.Encoding.UTF8);
}

/// <summary>
/// Performs an implicit conversion from a Memory of bytes to a <see cref="OpenLetterExtended"/>.
/// </summary>
/// <param name="packet">The packet as span.</param>
/// <returns>The packet as struct.</returns>
public static implicit operator OpenLetterExtended(Memory<byte> packet) => new (packet, false);

/// <summary>
/// Performs an implicit conversion from <see cref="OpenLetterExtended"/> to a Memory of bytes.
/// </summary>
/// <param name="packet">The packet as struct.</param>
/// <returns>The packet as byte span.</returns>
public static implicit operator Memory<byte>(OpenLetterExtended packet) => packet._data;

/// <summary>
/// Calculates the size of the packet for the specified field content.
/// </summary>
/// <param name="content">The content of the variable 'Message' field from which the size will be calculated.</param>
public static int GetRequiredSize(string content) => System.Text.Encoding.UTF8.GetByteCount(content) + 1 + 50;

/// <summary>
/// Calculates the size of the packet for the specified field content.
/// </summary>
/// <param name="contentLength">The content length in bytes of the variable 'Message' field from which the size will be calculated.</param>
public static int GetRequiredSize(int contentLength) => contentLength + 1 + 50;
}


/// <summary>
/// Is sent by the server when: After a letter has been deleted by the request of the player.
/// Causes reaction on client side: The letter is removed from the letter list.
Expand Down
36 changes: 36 additions & 0 deletions src/Network/Packets/ServerToClient/ServerToClientPackets.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9596,6 +9596,42 @@
</Field>
</Fields>
</Packet>
<Packet>
<HeaderType>C4Header</HeaderType>
<Code>C7</Code>
<Name>OpenLetterExtended</Name>
<Direction>ServerToClient</Direction>
<SentWhen>After the player requested to read a letter.</SentWhen>
<CausedReaction>The letter is opened in a new dialog.</CausedReaction>
<Fields>
<Field>
<Index>4</Index>
<Type>ShortLittleEndian</Type>
<Name>LetterIndex</Name>
</Field>
<Field>
<Index>6</Index>
<Type>Binary</Type>
<Name>SenderAppearance</Name>
<Length>42</Length>
</Field>
<Field>
<Index>48</Index>
<Type>Byte</Type>
<Name>Rotation</Name>
</Field>
<Field>
<Index>49</Index>
<Type>Byte</Type>
<Name>Animation</Name>
</Field>
<Field>
<Index>50</Index>
<Type>String</Type>
<Name>Message</Name>
</Field>
</Fields>
</Packet>
<Packet>
<HeaderType>C1Header</HeaderType>
<Code>C8</Code>
Expand Down
Loading

0 comments on commit 63e21f1

Please sign in to comment.