Skip to content

Commit

Permalink
Merge pull request #532 from nitoygo/dev/extend-walk-packet
Browse files Browse the repository at this point in the history
Extend walk packets with source x,y
  • Loading branch information
sven-n authored Nov 22, 2024
2 parents 8c14e1e + 01150d0 commit aec5637
Show file tree
Hide file tree
Showing 12 changed files with 486 additions and 14 deletions.
26 changes: 26 additions & 0 deletions docs/Packets/C1-D4-ObjectWalkedExtended_by-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# C1 D4 - ObjectWalkedExtended (by server)

## Is sent when

An object in the observed scope (including the own player) walked to another position.

## Causes the following actions on the client side

The object is animated to walk to the new position.

## Structure

| Index | Length | Data Type | Value | Description |
|-------|--------|-----------|-------|-------------|
| 0 | 1 | Byte | 0xC1 | [Packet type](PacketTypes.md) |
| 1 | 1 | Byte | | Packet header - length of the packet |
| 2 | 1 | Byte | 0xD4 | Packet header - packet type identifier |
| 2 | 1 | Byte | | HeaderCode |
| 3 | 2 | ShortBigEndian | | ObjectId |
| 5 | 1 | Byte | | SourceX |
| 6 | 1 | Byte | | SourceY |
| 7 | 1 | Byte | | TargetX |
| 8 | 1 | Byte | | TargetY |
| 9 | 4 bit | Byte | | TargetRotation |
| 9 | 4 bit | Byte | | StepCount |
| 10 | | Binary | | StepData |
1 change: 1 addition & 0 deletions docs/Packets/ServerToClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@
* [C3 CA - ChatRoomConnectionInfo (by server)](C3-CA-ChatRoomConnectionInfo_by-server.md)
* [C3 CB - FriendInvitationResult (by server)](C3-CB-FriendInvitationResult_by-server.md)
* [C1 D4 - ObjectWalked (by server)](C1-D4-ObjectWalked_by-server.md)
* [C1 D4 - ObjectWalkedExtended (by server)](C1-D4-ObjectWalkedExtended_by-server.md)
* [C1 DE 00 - CharacterClassCreationUnlock (by server)](C1-DE-00-CharacterClassCreationUnlock_by-server.md)
* [C1 F1 00 - GameServerEntered (by server)](C1-F1-00-GameServerEntered_by-server.md)
* [C1 F1 01 - LoginResponse (by server)](C1-F1-01-LoginResponse_by-server.md)
Expand Down
11 changes: 6 additions & 5 deletions src/GameServer/RemoteView/World/ObjectMovedPlugIn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,19 @@ public async ValueTask ObjectMovedAsync(ILocateable obj, MoveType type)
await this.ObjectWalkedAsync(obj).ConfigureAwait(false);
break;
}
}

}

/// <summary>
/// Sends the network message.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="objectId">The object identifier.</param>
/// <param name="sourcePoint">The origin point.</param>
/// <param name="targetPoint">The target point.</param>
/// <param name="steps">The steps.</param>
/// <param name="rotation">The rotation.</param>
/// <param name="stepsLength">Length of the steps.</param>
protected virtual async ValueTask SendWalkAsync(IConnection connection, ushort objectId, Point targetPoint, Memory<Direction> steps, Direction rotation, int stepsLength)
protected virtual async ValueTask SendWalkAsync(IConnection connection, ushort objectId, Point sourcePoint, Point targetPoint, Memory<Direction> steps, Direction rotation, int stepsLength)
{
int Write()
{
Expand Down Expand Up @@ -156,7 +157,7 @@ private async ValueTask ObjectWalkedAsync(ILocateable obj)
targetPoint = obj.Position;
}

await this.SendWalkAsync(connection, objectId, targetPoint, steps, rotation, stepsLength).ConfigureAwait(false);
await this.SendWalkAsync(connection, objectId, obj.Position, targetPoint, steps, rotation, stepsLength).ConfigureAwait(false);
}

private void SetStepData(ObjectWalkedRef walkPacket, Span<Direction> steps, int stepsSize)
Expand Down Expand Up @@ -198,7 +199,7 @@ private byte GetInstantMoveCode()
}
}

private byte GetWalkCode()
protected byte GetWalkCode()
{
if (this._player.ClientVersion.Season == 0)
{
Expand Down
2 changes: 1 addition & 1 deletion src/GameServer/RemoteView/World/ObjectMovedPlugIn075.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public ObjectMovedPlugIn075(RemotePlayer player)
}

/// <inheritdoc />
protected override ValueTask SendWalkAsync(IConnection connection, ushort objectId, Point targetPoint, Memory<Direction> steps, Direction rotation, int stepsLength)
protected override ValueTask SendWalkAsync(IConnection connection, ushort objectId, Point sourcePoint, Point targetPoint, Memory<Direction> steps, Direction rotation, int stepsLength)
{
return connection.SendObjectWalked075Async(objectId, targetPoint.X, targetPoint.Y, rotation.ToPacketByte());
}
Expand Down
81 changes: 81 additions & 0 deletions src/GameServer/RemoteView/World/ObjectMovedPlugInExtended.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// <copyright file="ObjectMovedPlugIn.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.World;

using System.Buffers;
using System.Runtime.InteropServices;
using MUnique.OpenMU.DataModel.Configuration;
using MUnique.OpenMU.GameLogic;
using MUnique.OpenMU.GameLogic.NPC;
using MUnique.OpenMU.GameLogic.Views;
using MUnique.OpenMU.GameLogic.Views.World;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.Packets.ServerToClient;
using MUnique.OpenMU.Network.PlugIns;
using MUnique.OpenMU.Pathfinding;
using MUnique.OpenMU.PlugIns;

/// <summary>
/// The default implementation of the <see cref="IObjectMovedPlugIn"/> which is forwarding everything to the game client with specific data packets.
/// </summary>
[PlugIn(nameof(ObjectMovedPlugInExtended), "The default implementation of the IObjectMovedPlugIn which is forwarding everything to the game client with specific data packets.")]
[Guid("a56b7400-e51d-4fd6-930b-479c14673719")]
[MinimumClient(106, 3, ClientLanguage.Invariant)]
public class ObjectMovedPlugInExtended : ObjectMovedPlugIn
{
/// <summary>
/// Initializes a new instance of the <see cref="ObjectMovedPlugInExtended"/> class.
/// </summary>
/// <param name="player">The player.</param>
public ObjectMovedPlugInExtended(RemotePlayer player)
: base(player)
{
}

/// <inheritdoc />
protected override async ValueTask SendWalkAsync(IConnection connection, ushort objectId, Point sourcePoint, Point targetPoint, Memory<Direction> steps, Direction rotation, int stepsLength)
{
int Write()
{
var stepsSize = steps.Length == 0 ? 1 : (steps.Length / 2) + 2;
var size = ObjectWalkedExtended.GetRequiredSize(stepsSize);
var span = connection.Output.GetSpan(size)[..size];

var walkPacket = new ObjectWalkedExtendedRef(span)
{
HeaderCode = this.GetWalkCode(),
ObjectId = objectId,
SourceX = sourcePoint.X,
SourceY = sourcePoint.Y,
TargetX = targetPoint.X,
TargetY = targetPoint.Y,
TargetRotation = rotation.ToPacketByte(),
StepCount = (byte)stepsLength,
};

this.SetStepData(walkPacket, steps.Span, stepsSize);
return size;
}

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

private void SetStepData(ObjectWalkedExtendedRef walkPacket, Span<Direction> steps, int stepsSize)
{
if (steps == default || walkPacket.StepCount == 0)
{
return;
}

walkPacket.StepData[0] = (byte)(steps[0].ToPacketByte() << 4 | stepsSize);
for (int i = 0; i < stepsSize - 1; i += 2)
{
var index = 1 + (i / 2);
var firstStep = steps[i].ToPacketByte();
var secondStep = steps.Length > i + 1 ? steps[i + 1].ToPacketByte() : 0;
walkPacket.StepData[index] = (byte)(firstStep << 4 | secondStep);
}
}
}
4 changes: 2 additions & 2 deletions src/Network/MUnique.OpenMU.Network.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
MUnique.OpenMU.Network contains all what's required to connect from and to a MU Online game, connect or chat server. It implements the MU Online network protocol.
It also contains several the encryption algorithms and keys which were used until a few years ago up to Season 6 Episode 3.
</Description>
<PackageVersion>0.8.22</PackageVersion>
<Version>0.8.22</Version>
<PackageVersion>0.8.23</PackageVersion>
<Version>0.8.23</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
4 changes: 2 additions & 2 deletions src/Network/Packets/MUnique.OpenMU.Network.Packets.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
<PackageTags>MUnique OpenMU MUOnline Network Packets</PackageTags>
<PackageId>MUnique.OpenMU.Network.Packets</PackageId>
<Description>This package contains message structs for the MMORPG "MU Online", which are primarily focused on the english version of Season 6 Episode 3.</Description>
<PackageVersion>0.8.22</PackageVersion>
<Version>0.8.22</Version>
<PackageVersion>0.8.23</PackageVersion>
<Version>0.8.23</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
152 changes: 152 additions & 0 deletions src/Network/Packets/ServerToClient/ServerToClientPackets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6889,6 +6889,158 @@ public Span<byte> StepData
}


/// <summary>
/// Is sent by the server when: An object in the observed scope (including the own player) walked to another position.
/// Causes reaction on client side: The object is animated to walk to the new position.
/// </summary>
public readonly struct ObjectWalkedExtended
{
private readonly Memory<byte> _data;

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

/// <summary>
/// Initializes a new instance of the <see cref="ObjectWalkedExtended"/> 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 ObjectWalkedExtended(Memory<byte> data, bool initialize)
{
this._data = data;
if (initialize)
{
var header = this.Header;
header.Type = HeaderType;
header.Code = Code;
header.Length = (byte)data.Length;
}
}

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

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

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

/// <summary>
/// Gets or sets the header code.
/// </summary>
public byte HeaderCode
{
get => this._data.Span[2];
set => this._data.Span[2] = value;
}

/// <summary>
/// Gets or sets the object id.
/// </summary>
public ushort ObjectId
{
get => ReadUInt16BigEndian(this._data.Span[3..]);
set => WriteUInt16BigEndian(this._data.Span[3..], value);
}

/// <summary>
/// Gets or sets the source x.
/// </summary>
public byte SourceX
{
get => this._data.Span[5];
set => this._data.Span[5] = value;
}

/// <summary>
/// Gets or sets the source y.
/// </summary>
public byte SourceY
{
get => this._data.Span[6];
set => this._data.Span[6] = value;
}

/// <summary>
/// Gets or sets the target x.
/// </summary>
public byte TargetX
{
get => this._data.Span[7];
set => this._data.Span[7] = value;
}

/// <summary>
/// Gets or sets the target y.
/// </summary>
public byte TargetY
{
get => this._data.Span[8];
set => this._data.Span[8] = value;
}

/// <summary>
/// Gets or sets the target rotation.
/// </summary>
public byte TargetRotation
{
get => this._data.Span[9..].GetByteValue(4, 4);
set => this._data.Span[9..].SetByteValue(value, 4, 4);
}

/// <summary>
/// Gets or sets the step count.
/// </summary>
public byte StepCount
{
get => this._data.Span[9..].GetByteValue(4, 0);
set => this._data.Span[9..].SetByteValue(value, 4, 0);
}

/// <summary>
/// Gets or sets the step data.
/// </summary>
public Span<byte> StepData
{
get => this._data.Slice(10).Span;
}

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

/// <summary>
/// Performs an implicit conversion from <see cref="ObjectWalkedExtended"/> 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>(ObjectWalkedExtended packet) => packet._data;

/// <summary>
/// Calculates the size of the packet for the specified length of <see cref="StepData"/>.
/// </summary>
/// <param name="stepDataLength">The length in bytes of <see cref="StepData"/> on which the required size depends.</param>

public static int GetRequiredSize(int stepDataLength) => stepDataLength + 10;
}


/// <summary>
/// Is sent by the server when: An object in the observed scope (including the own player) walked to another position.
/// Causes reaction on client side: The object is animated to walk to the new position.
Expand Down
Loading

0 comments on commit aec5637

Please sign in to comment.