baseline: OpenMU upstream b5a0961 (fresh source)

This commit is contained in:
Acentech Dev
2026-07-14 19:00:35 +03:00
parent 450402e47d
commit 36fc125d5c
11968 changed files with 748705 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
// <copyright file="AddToLetterListPlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Interfaces;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IAddToLetterListPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.AddToLetterListPlugIn_Name), Description = nameof(PlugInResources.AddToLetterListPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("d30bea99-9d77-4182-99be-e08095c1969f")]
public class AddToLetterListPlugIn : IAddToLetterListPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="AddToLetterListPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public AddToLetterListPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask AddToLetterListAsync(LetterHeader letter, ushort newLetterIndex, bool newLetter)
{
await this._player.Connection.SendAddLetterAsync(
newLetterIndex,
letter.SenderName ?? string.Empty,
letter.LetterDate.ToUniversalTime().AddHours(this._player.Account?.TimeZone ?? 0).ToString("yyyy-MM-dd HH:mm:ss"),
letter.Subject ?? string.Empty,
newLetter ? AddLetter.LetterState.New : letter.ReadFlag ? AddLetter.LetterState.Read : AddLetter.LetterState.Unread)
.ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,50 @@
// <copyright file="ChatRoomCreatedPlugIn.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.Net;
using System.Runtime.InteropServices;
using MUnique.OpenMU.GameLogic.Views.Messenger;
using MUnique.OpenMU.Interfaces;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IChatRoomCreatedPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.ChatRoomCreatedPlugIn_Name), Description = nameof(PlugInResources.ChatRoomCreatedPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("a7c99cb5-94f6-42ea-b6e2-2272a9a81e12")]
public class ChatRoomCreatedPlugIn : IChatRoomCreatedPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="ChatRoomCreatedPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public ChatRoomCreatedPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask ChatRoomCreatedAsync(ChatServerAuthenticationInfo authenticationInfo, string friendName, bool success)
{
var hostAddress = authenticationInfo.HostAddress;
if (IPAddress.TryParse(authenticationInfo.HostAddress, out var chatServerAddress)
&& chatServerAddress.IsOnSameHost()
&& this._player.Connection?.LocalEndPoint is IPEndPoint localEndPoint)
{
hostAddress = localEndPoint.Address.ToString();
}
await this._player.Connection.SendChatRoomConnectionInfoAsync(
hostAddress,
authenticationInfo.RoomId,
uint.Parse(authenticationInfo.AuthenticationToken),
friendName,
success)
.ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,33 @@
// <copyright file="FriendAddedPlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IFriendAddedPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.FriendAddedPlugIn_Name), Description = nameof(PlugInResources.FriendAddedPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("7edba5ed-eec5-4aa7-b302-418444868841")]
public class FriendAddedPlugIn : IFriendAddedPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="FriendAddedPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public FriendAddedPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask FriendAddedAsync(string friendName)
{
await this._player.Connection.SendFriendAddedAsync(friendName).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,33 @@
// <copyright file="FriendDeletedPlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IFriendDeletedPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.FriendDeletedPlugIn_Name), Description = nameof(PlugInResources.FriendDeletedPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("3f6f86ec-ffe8-4fa7-82c3-4a743fab7157")]
public class FriendDeletedPlugIn : IFriendDeletedPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="FriendDeletedPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public FriendDeletedPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask FriendDeletedAsync(string deletedFriend)
{
await this._player.Connection.SendFriendDeletedAsync(deletedFriend).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,33 @@
// <copyright file="FriendStateUpdatePlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IFriendStateUpdatePlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.FriendStateUpdatePlugIn_Name), Description = nameof(PlugInResources.FriendStateUpdatePlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("1ed98d6a-7917-4209-bd03-e8a966b99688")]
public class FriendStateUpdatePlugIn : IFriendStateUpdatePlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="FriendStateUpdatePlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public FriendStateUpdatePlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask FriendStateUpdateAsync(string friend, int serverId)
{
await this._player.Connection.SendFriendOnlineStateUpdateAsync(friend, (byte)serverId).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,77 @@
// <copyright file="InitializeMessengerPlugIn.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.GameLogic;
using MUnique.OpenMU.GameLogic.Views.Messenger;
using MUnique.OpenMU.Interfaces;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IInitializeMessengerPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.InitializeMessengerPlugIn_Name), Description = nameof(PlugInResources.InitializeMessengerPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("cb079c23-e90c-473d-87ae-317937158924")]
public class InitializeMessengerPlugIn : IInitializeMessengerPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="InitializeMessengerPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public InitializeMessengerPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask InitializeMessengerAsync(MessengerInitializationData data, int maxLetters)
{
var connection = this._player.Connection;
if (connection is null || this._player.SelectedCharacter is null)
{
return;
}
int Write()
{
var friendList = data.Friends;
var size = MessengerInitializationRef.GetRequiredSize(friendList.Count);
var span = connection.Output.GetSpan(size)[..size];
var message = new MessengerInitializationRef(span)
{
FriendCount = (byte)friendList.Count,
LetterCount = (byte)this._player.SelectedCharacter.Letters.Count,
MaximumLetterCount = (byte)maxLetters,
};
int i = 0;
foreach (var friend in friendList)
{
var friendBlock = message[i];
friendBlock.Name = friend;
friendBlock.ServerId = (byte)SpecialServerId.Offline;
i++;
}
return size;
}
await connection.SendAsync(Write).ConfigureAwait(false);
foreach (var requesterName in data.OpenFriendRequests)
{
await this._player.InvokeViewPlugInAsync<IShowFriendRequestPlugIn>(p => p.ShowFriendRequestAsync(requesterName)).ConfigureAwait(false);
}
var letters = this._player.SelectedCharacter.Letters;
for (ushort l = 0; l < letters.Count; l++)
{
await this._player.InvokeViewPlugInAsync<IAddToLetterListPlugIn>(p => p.AddToLetterListAsync(letters[l], l, false)).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,33 @@
// <copyright file="LetterDeletedPlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="ILetterDeletedPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.LetterDeletedPlugIn_Name), Description = nameof(PlugInResources.LetterDeletedPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("3bcd507e-cb61-4b25-a208-4ee264f4793e")]
public class LetterDeletedPlugIn : ILetterDeletedPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="LetterDeletedPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public LetterDeletedPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask LetterDeletedAsync(ushort letterIndex)
{
await this._player.Connection.SendRemoveLetterAsync(letterIndex).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,47 @@
// <copyright file="LetterSendResultPlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="ILetterSendResultPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.LetterSendResultPlugIn_Name), Description = nameof(PlugInResources.LetterSendResultPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("c67cad23-20ba-4cd7-ba4e-b672beed427c")]
public class LetterSendResultPlugIn : ILetterSendResultPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="LetterSendResultPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public LetterSendResultPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask LetterSendResultAsync(LetterSendSuccess success, uint letterId)
{
await this._player.Connection.SendLetterSendResponseAsync(letterId, Convert(success)).ConfigureAwait(false);
}
private static LetterSendResponse.LetterSendRequestResult Convert(LetterSendSuccess success)
{
return success switch
{
LetterSendSuccess.TryAgain => LetterSendResponse.LetterSendRequestResult.TryAgain,
LetterSendSuccess.Success => LetterSendResponse.LetterSendRequestResult.Success,
LetterSendSuccess.MailboxFull => LetterSendResponse.LetterSendRequestResult.MailboxFull,
LetterSendSuccess.ReceiverNotExists => LetterSendResponse.LetterSendRequestResult.ReceiverNotExists,
LetterSendSuccess.CantSendToYourself => LetterSendResponse.LetterSendRequestResult.CantSendToYourself,
LetterSendSuccess.NotEnoughMoney => LetterSendResponse.LetterSendRequestResult.NotEnoughMoney,
_ => throw new ArgumentException($"Unhandled case {success}."),
};
}
}

View File

@@ -0,0 +1,33 @@
// <copyright file="ShowFriendInvitationResultPlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IShowFriendInvitationResultPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.ShowFriendInvitationResultPlugIn_Name), Description = nameof(PlugInResources.ShowFriendInvitationResultPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("8df329bd-88da-423c-8f85-173180ab8601")]
public class ShowFriendInvitationResultPlugIn : IShowFriendInvitationResultPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="ShowFriendInvitationResultPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public ShowFriendInvitationResultPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask ShowFriendInvitationResultAsync(bool success, uint requestId)
{
await this._player.Connection.SendFriendInvitationResultAsync(success, requestId).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,33 @@
// <copyright file="ShowFriendRequestPlugIn.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.GameLogic.Views.Messenger;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IShowFriendRequestPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.ShowFriendRequestPlugIn_Name), Description = nameof(PlugInResources.ShowFriendRequestPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("efb8b51b-181a-4a7d-b5a4-34c0dbd41748")]
public class ShowFriendRequestPlugIn : IShowFriendRequestPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="ShowFriendRequestPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public ShowFriendRequestPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask ShowFriendRequestAsync(string requester)
{
await this._player.Connection.SendFriendRequestAsync(requester).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,65 @@
// <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]
[Display(Name = nameof(PlugInResources.ShowLetterExtendedPlugIn_Name), Description = nameof(PlugInResources.ShowLetterExtendedPlugIn_Description), ResourceType = typeof(PlugInResources))]
[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);
}
}

View File

@@ -0,0 +1,65 @@
// <copyright file="ShowLetterPlugIn.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.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IShowLetterPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.ShowLetterPlugIn_Name), Description = nameof(PlugInResources.ShowLetterPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("6ce73080-6916-465f-b6d1-34641687ded3")]
public class ShowLetterPlugIn : IShowLetterPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="ShowLetterPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public ShowLetterPlugIn(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 = OpenLetterRef.GetRequiredSize(letter.Message);
var span = connection.Output.GetSpan(size)[..size];
var result = new OpenLetterRef(span)
{
LetterIndex = (ushort)letterIndex,
MessageSize = (ushort)Encoding.UTF8.GetByteCount(letter.Message),
Animation = letter.Animation,
Rotation = letter.Rotation,
Message = letter.Message,
};
// TODO: Somewhere is the GM-Sign defined.
if (letter.SenderAppearance is not null)
{
appearanceSerializer.WriteAppearanceData(result.SenderAppearance, letter.SenderAppearance, false);
}
return size;
}
await connection.SendAsync(Write).ConfigureAwait(false);
}
}