Skip to content

Commit

Permalink
Added extended message for mails
Browse files Browse the repository at this point in the history
The old structure doesn't have enough space for the larger appearance data. I made it even larger than needed for future extensions.
  • Loading branch information
sven-n committed Jan 20, 2025
1 parent d803424 commit 8c1a52d
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 8c1a52d

Please sign in to comment.