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,110 @@
// <copyright file="PartyHealthViewPlugIn.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.Party;
using System.Runtime.InteropServices;
using MUnique.OpenMU.GameLogic;
using MUnique.OpenMU.GameLogic.Views.Party;
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 party view which is forwarding everything to the game client which specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.PartyHealthViewPlugIn_Name), Description = nameof(PlugInResources.PartyHealthViewPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("CEE58BCB-FB8C-4AEB-9FC8-5D3A11FA7C03")]
[MinimumClient(0, 90, ClientLanguage.Invariant)]
public class PartyHealthViewPlugIn : IPartyHealthViewPlugIn
{
private readonly RemotePlayer _player;
private byte[]? _healthValues;
/// <summary>
/// Initializes a new instance of the <see cref="PartyHealthViewPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public PartyHealthViewPlugIn(RemotePlayer player)
{
this._player = player;
}
private byte[] HealthValues => this._healthValues ??= new byte[this._player.Party!.MaxPartySize];
/// <inheritdoc/>
public bool IsHealthUpdateNeeded()
{
return this.UpdateHealthValues();
}
/// <inheritdoc/>
public async ValueTask UpdatePartyHealthAsync()
{
var partyList = this._player.Party?.PartyList;
if (partyList is null)
{
return;
}
// Refresh the cache before sending so direct calls don't send stale values.
this.UpdateHealthValues();
var connection = this._player.Connection;
if (connection is null)
{
return;
}
var partyListCount = partyList.Count;
int Write()
{
var size = PartyHealthUpdateRef.GetRequiredSize(partyListCount);
var span = connection.Output.GetSpan(size)[..size];
var packet = new PartyHealthUpdateRef(span)
{
Count = (byte)partyListCount,
};
for (int i = 0; i < partyListCount; i++)
{
var member = packet[i];
member.Index = (byte)i;
member.Value = this.HealthValues[i];
}
return size;
}
await connection.SendAsync(Write).ConfigureAwait(false);
}
private bool UpdateHealthValues()
{
var partyList = this._player.Party?.PartyList;
if (partyList is null)
{
// Party was left in the meantime
this._healthValues?.ClearToDefaults();
return false;
}
bool updated = false;
for (int i = partyList.Count - 1; i >= 0; --i)
{
var partyMember = partyList[i];
double value = (double)partyMember.CurrentHealth / partyMember.MaximumHealth;
var newValue = (byte)(value * 10);
if (this.HealthValues[i] != newValue)
{
updated = true;
this.HealthValues[i] = newValue;
}
}
return updated;
}
}

View File

@@ -0,0 +1,33 @@
// <copyright file="PartyMemberRemovedPlugIn.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.Party;
using System.Runtime.InteropServices;
using MUnique.OpenMU.GameLogic.Views.Party;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IPartyMemberRemovedPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.PartyMemberRemovedPlugIn_Name), Description = nameof(PlugInResources.PartyMemberRemovedPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("d69b37b3-9e7f-40d1-9260-ba7a4f6369a2")]
public class PartyMemberRemovedPlugIn : IPartyMemberRemovedPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="PartyMemberRemovedPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public PartyMemberRemovedPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask PartyMemberRemovedAsync(byte index)
{
await this._player.Connection.SendRemovePartyMemberAsync(index).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,34 @@
// <copyright file="ShowPartyRequestPlugIn.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.Party;
using System.Runtime.InteropServices;
using MUnique.OpenMU.GameLogic;
using MUnique.OpenMU.GameLogic.Views.Party;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// The default implementation of the <see cref="IShowPartyRequestPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.ShowPartyRequestPlugIn_Name), Description = nameof(PlugInResources.ShowPartyRequestPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("d25e8b80-3128-4102-8916-98f3d68aa065")]
public class ShowPartyRequestPlugIn : IShowPartyRequestPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="ShowPartyRequestPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public ShowPartyRequestPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask ShowPartyRequestAsync(IPartyMember requester)
{
await this._player.Connection.SendPartyRequestAsync(requester.Id).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,70 @@
// <copyright file="UpdatePartyListPlugIn.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.Party;
using System.Runtime.InteropServices;
using MUnique.OpenMU.GameLogic.Views.Party;
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="IUpdatePartyListPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.UpdatePartyListPlugIn_Name), Description = nameof(PlugInResources.UpdatePartyListPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("bf880a4b-f4f6-41f0-adff-6eab0e99d985")]
[MinimumClient(0, 90, ClientLanguage.Invariant)]
public class UpdatePartyListPlugIn : IUpdatePartyListPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="UpdatePartyListPlugIn"/> class.
/// </summary>
/// <param name="player">The player.</param>
public UpdatePartyListPlugIn(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask UpdatePartyListAsync()
{
var connection = this._player.Connection;
var party = this._player.Party;
if (party is null || connection is null)
{
return;
}
var partyList = party.PartyList;
var partyListCount = partyList.Count;
int Write()
{
var size = PartyListRef.GetRequiredSize(partyListCount);
var span = connection.Output.GetSpan(size)[..size];
var packet = new PartyListRef(span)
{
Count = (byte)partyListCount,
};
for (byte i = 0; i < partyListCount; i++)
{
var partyMember = partyList[i];
var partyMemberBlock = packet[i];
partyMemberBlock.Index = i;
partyMemberBlock.Name = partyMember.Name;
partyMemberBlock.MapId = (byte)(partyMember.CurrentMap?.MapId ?? 0);
partyMemberBlock.PositionX = partyMember.Position.X;
partyMemberBlock.PositionY = partyMember.Position.Y;
partyMemberBlock.CurrentHealth = partyMember.CurrentHealth;
partyMemberBlock.MaximumHealth = partyMember.MaximumHealth;
}
return size;
}
await connection.SendAsync(Write).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,68 @@
// <copyright file="UpdatePartyListPlugIn075.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.Party;
using System.Runtime.InteropServices;
using MUnique.OpenMU.GameLogic.Views.Party;
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="IUpdatePartyListPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.UpdatePartyListPlugIn075_Name), Description = nameof(PlugInResources.UpdatePartyListPlugIn075_Description), ResourceType = typeof(PlugInResources))]
[Guid("125303BA-9614-45CE-A0C5-A82F1535367A")]
[MaximumClient(0, 89, ClientLanguage.Invariant)]
public class UpdatePartyListPlugIn075 : IUpdatePartyListPlugIn
{
private readonly RemotePlayer _player;
/// <summary>
/// Initializes a new instance of the <see cref="UpdatePartyListPlugIn075"/> class.
/// </summary>
/// <param name="player">The player.</param>
public UpdatePartyListPlugIn075(RemotePlayer player) => this._player = player;
/// <inheritdoc/>
public async ValueTask UpdatePartyListAsync()
{
var connection = this._player.Connection;
var party = this._player.Party;
if (party is null || connection is null)
{
return;
}
var partyList = party.PartyList;
var partyListCount = partyList.Count;
int Write()
{
var size = PartyList075Ref.GetRequiredSize(partyListCount);
var span = connection.Output.GetSpan(size)[..size];
var packet = new PartyList075Ref(span)
{
Count = (byte)partyListCount,
};
for (byte i = 0; i < partyListCount; i++)
{
var partyMember = partyList[i];
var partyMemberBlock = packet[i];
partyMemberBlock.Index = i;
partyMemberBlock.Name = partyMember.Name;
partyMemberBlock.MapId = (byte)(partyMember.CurrentMap?.MapId ?? 0);
partyMemberBlock.PositionX = partyMember.Position.X;
partyMemberBlock.PositionY = partyMember.Position.Y;
}
return size;
}
await connection.SendAsync(Write).ConfigureAwait(false);
}
}