Skip to content

Commit 00a2cbb

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 5795c5d + 599d5df commit 00a2cbb

15 files changed

Lines changed: 469 additions & 65 deletions

src/DCLPulse/InterestManagement/ParcelEncoder.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ public ParcelEncoder(IOptions<ParcelEncoderOptions> optionsContainer)
2121
parcelSize = options.ParcelSize;
2222
}
2323

24+
public int EncodeFromGlobalPosition(Vector3 globalPosition, out Vector3 localPosition)
25+
{
26+
int x = (int)MathF.Floor(globalPosition.X / parcelSize);
27+
int z = (int)MathF.Floor(globalPosition.Z / parcelSize);
28+
localPosition = new Vector3(globalPosition.X - (x * parcelSize), globalPosition.Y, globalPosition.Z - (z * parcelSize));
29+
return Encode(x, z);
30+
}
31+
2432
public int Encode(int x, int z) =>
2533
x - minX + ((z - minZ) * width);
2634

src/DCLPulse/Messaging/EmoteStartHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ public void Handle(Dictionary<PeerIndex, PeerState> peers, PeerIndex from, Clien
1818

1919
emoteBoard.Start(from, emoteStart.EmoteId, timeProvider.MonotonicTime, durationMs);
2020

21-
logger.LogDebug("Peer {Peer} started emote {EmoteId}", from.Value, emoteStart.EmoteId);
21+
logger.LogInformation("Peer {Peer} started emote {EmoteId}", from.Value, emoteStart.EmoteId);
2222
}
23-
}
23+
}

src/DCLPulse/Messaging/EmoteStopHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ public void Handle(Dictionary<PeerIndex, PeerState> peers, PeerIndex from, Clien
1818
return;
1919
}
2020

21-
logger.LogDebug("Peer {Peer} stopped emote", from.Value);
21+
logger.LogInformation("Peer {Peer} stopped emote", from.Value);
2222

2323
emoteBoard.Stop(from, timeProvider.MonotonicTime);
2424
}
25-
}
25+
}

src/DCLPulse/Messaging/PlayerStateInputHandler.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public void Handle(Dictionary<PeerIndex, PeerState> peers, PeerIndex from, Clien
5050

5151
snapshotBoard.Publish(from, in snapshot);
5252
spatialGrid.Set(from, snapshot.GlobalPosition);
53+
54+
logger.LogDebug("Received input from {Peer} with position {GlobalPosition}, rotation {RotationY}, velocity {Velocity}, movement blend {MovementBlend}, anim state {AnimationFlags}",
55+
from.Value, snapshot.GlobalPosition, snapshot.RotationY, snapshot.Velocity, snapshot.MovementBlend, snapshot.AnimationFlags);
5356
}
5457

5558
private static bool IsSameState(in PeerSnapshot current, PlayerState incoming) =>
@@ -62,7 +65,10 @@ private static bool IsSameState(in PeerSnapshot current, PlayerState incoming) =
6265
&& FloatEquals(current.HeadYaw, incoming.GetHeadYaw())
6366
&& FloatEquals(current.HeadPitch, incoming.GetHeadPitch())
6467
&& current.AnimationFlags == (PlayerAnimationFlags)incoming.StateFlags
65-
&& current.GlideState == incoming.GlideState;
68+
&& current.GlideState == incoming.GlideState
69+
// Ensures that the first movement input after a teleport is always published,
70+
// even if the position/state values happen to be identical
71+
&& !current.IsTeleport;
6672

6773
private static bool FloatEquals(in float a, in float b) =>
6874
Math.Abs(a - b) < TOLERANCE;

src/DCLPulse/Messaging/ProfileAnnouncementHandler.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
namespace Pulse.Messaging;
66

7-
public class ProfileAnnouncementHandler(ProfileBoard profileBoard) : IMessageHandler
7+
public class ProfileAnnouncementHandler(ILogger<ProfileAnnouncementHandler> logger,
8+
ProfileBoard profileBoard) : IMessageHandler
89
{
910
public void Handle(Dictionary<PeerIndex, PeerState> peers, PeerIndex from, ClientMessage message)
1011
{
1112
profileBoard.Set(from, message.ProfileAnnouncement.Version);
13+
14+
logger.LogInformation("Received profile announcement from {Peer}", from.Value);
1215
}
1316
}

src/DCLPulse/Messaging/ResyncRequestHandler.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@ public void Handle(Dictionary<PeerIndex, PeerState> peers, PeerIndex from, Clien
1111

1212
state.ResyncRequests ??= new Dictionary<PeerIndex, uint>();
1313
state.ResyncRequests[new PeerIndex(message.Resync.SubjectId)] = message.Resync.KnownSeq;
14+
15+
logger.LogWarning("Received resync request from {Peer} for subject {SubjectId} with known sequence {KnownSeq}",
16+
from.Value, message.Resync.SubjectId, message.Resync.KnownSeq);
1417
}
1518
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Decentraland.Common;
2+
using Decentraland.Pulse;
3+
using Pulse.InterestManagement;
4+
using Pulse.Peers;
5+
using Pulse.Peers.Simulation;
6+
7+
namespace Pulse.Messaging;
8+
9+
public class TeleportHandler(ILogger<TeleportHandler> logger,
10+
ITimeProvider timeProvider,
11+
SnapshotBoard snapshotBoard,
12+
ParcelEncoder parcelEncoder)
13+
: RuntimePacketHandlerBase<TeleportHandler>(logger), IMessageHandler
14+
{
15+
public void Handle(Dictionary<PeerIndex, PeerState> peers, PeerIndex from, ClientMessage message)
16+
{
17+
if (SkipFromUnauthorizedPeer(peers, from, message, out _))
18+
return;
19+
20+
Vector3 localPosition = message.Teleport.Position;
21+
int parcelIndex = message.Teleport.ParcelIndex;
22+
System.Numerics.Vector3 globalPosition = parcelEncoder.DecodeToGlobalPosition(parcelIndex, localPosition);
23+
24+
float rotationY = 0;
25+
float? headYaw = null, headPitch = null;
26+
27+
if (snapshotBoard.TryRead(from, out PeerSnapshot prevSnapshot))
28+
{
29+
rotationY = prevSnapshot.RotationY;
30+
headYaw = prevSnapshot.HeadYaw;
31+
headPitch = prevSnapshot.HeadPitch;
32+
}
33+
34+
var snapshot = new PeerSnapshot(snapshotBoard.LastSeq(from) + 1,
35+
timeProvider.MonotonicTime,
36+
parcelIndex, localPosition, globalPosition,
37+
System.Numerics.Vector3.Zero,
38+
rotationY,
39+
JumpCount: 0, MovementBlend: 0, SlideBlend: 0,
40+
headYaw, headPitch,
41+
PlayerAnimationFlags.Grounded,
42+
GlideState.PropClosed,
43+
IsTeleport: true);
44+
45+
snapshotBoard.Publish(from, snapshot);
46+
47+
logger.LogInformation("Teleport requested by {Peer} at {Position}", from, globalPosition);
48+
}
49+
}

src/DCLPulse/Peers/PeerSnapshot.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,8 @@ public record struct PeerSnapshot(
2626
float? HeadYaw,
2727
float? HeadPitch,
2828
PlayerAnimationFlags AnimationFlags,
29-
GlideState GlideState
29+
GlideState GlideState,
30+
31+
// Flags
32+
bool IsTeleport = false
3033
);

src/DCLPulse/Peers/PeerToPeerView.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,10 @@ public struct PeerToPeerView
4040
/// Compared against <see cref="Simulation.EmoteBoard" /> each tick to detect transitions.
4141
/// </summary>
4242
public string? LastSentEmoteId;
43+
44+
/// <summary>
45+
/// The sequence number of the last teleport snapshot sent to the observer for this subject.
46+
/// Prevents duplicate teleport broadcasts and supports consecutive teleports.
47+
/// </summary>
48+
public uint? LastSentTeleportSeq;
4349
}

src/DCLPulse/Peers/Simulation/PeerSimulation.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ public sealed class PeerSimulation : IPeerSimulation
2929
private readonly SpatialGrid spatialGrid;
3030
private readonly IdentityBoard identityBoard;
3131
private readonly MessagePipe messagePipe;
32-
private readonly uint[] simulationSteps;
3332
private readonly ITimeProvider timeProvider;
3433
private readonly ITransport transport;
3534
private readonly ProfileBoard profileBoard;
@@ -84,7 +83,6 @@ public PeerSimulation(
8483
this.spatialGrid = spatialGrid;
8584
this.identityBoard = identityBoard;
8685
this.messagePipe = messagePipe;
87-
this.simulationSteps = simulationSteps;
8886
this.timeProvider = timeProvider;
8987
this.transport = transport;
9088
this.profileBoard = profileBoard;
@@ -244,7 +242,30 @@ private void ProcessVisibleSubjects(
244242
}
245243
else
246244
{
247-
if (resyncRequests != null && resyncRequests.Remove(entry.Subject, out uint lastKnownSeq))
245+
// Only announce on delta because PlayerJoined is considered as an announcement
246+
TryAnnounceProfile();
247+
248+
if (subjectSnapshot.IsTeleport && view.LastSentTeleportSeq != subjectSnapshot.Seq)
249+
{
250+
// Clear the resync since the teleport has the full player state and can fulfill it
251+
resyncRequests?.Remove(entry.Subject);
252+
253+
messagePipe.Send(new OutgoingMessage(observerId, new ServerMessage
254+
{
255+
Teleported = new TeleportPerformed
256+
{
257+
SubjectId = entry.Subject,
258+
Sequence = subjectSnapshot.Seq,
259+
ServerTick = subjectSnapshot.ServerTick,
260+
State = CreatePlayerState(subjectSnapshot),
261+
}
262+
}, ITransport.PacketMode.RELIABLE));
263+
264+
view.LastSentTeleportSeq = subjectSnapshot.Seq;
265+
266+
logger.LogInformation($"Broadcasting teleport from {entry.Subject} to {observerId} at {subjectSnapshot.GlobalPosition}");
267+
}
268+
else if (resyncRequests != null && resyncRequests.Remove(entry.Subject, out uint lastKnownSeq))
248269
{
249270
// Try a targeted delta from the client's baseline; fall back to full state
250271
// if the baseline is evicted, the seq hasn't advanced, or all fields are within epsilon.
@@ -259,9 +280,6 @@ private void ProcessVisibleSubjects(
259280
}
260281
else
261282
SendDelta(view.LastSentSnapshot, ITransport.PacketMode.UNRELIABLE_SEQUENCED);
262-
263-
// Only announce on delta because PlayerJoined is considered as an announcement
264-
TryAnnounceProfile();
265283
}
266284

267285
SyncEmoteState();

0 commit comments

Comments
 (0)