Skip to content

Commit 2e689b6

Browse files
Merge pull request #227 from UchuServer/bug/player-loading-blocking
2 parents de82d64 + e46df3f commit 2e689b6

File tree

8 files changed

+149
-63
lines changed

8 files changed

+149
-63
lines changed

Uchu.World/Handlers/GameMessages/ModularBuildingHandler.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Threading.Tasks;
23
using Microsoft.EntityFrameworkCore;
34
using Uchu.Core;
@@ -43,15 +44,10 @@ public async Task BuildExitConfirmationHandler(BuildExitConfirmationMessage mess
4344
}
4445

4546
[PacketHandler]
46-
public async Task SetLastCustomBuildHandler(SetLastCustomBuildMessage message, Player player)
47+
public void SetLastCustomBuildHandler(SetLastCustomBuildMessage message, Player player)
4748
{
48-
await using var ctx = new UchuContext();
49-
50-
var character = await ctx.Characters.FirstAsync(c => c.Id == player.Id);
51-
52-
character.Rocket = message.Tokens;
53-
54-
await ctx.SaveChangesAsync();
49+
if (!player.TryGetComponent<CharacterComponent>(out var characterComponent));
50+
characterComponent.Rocket = message.Tokens;
5551
}
5652

5753
[PacketHandler]

Uchu.World/Objects/Components/ReplicaComponents/CharacterComponent.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public async Task SaveAsync(UchuContext context)
211211
public int InventorySize { get; set; }
212212
public int BaseImagination { get; set; }
213213
public int BaseHealth { get; set; }
214-
public string Rocket { get; private set; }
214+
public string Rocket { get; set; }
215215
public int LaunchedRocketFrom { get; set; }
216216
public long LastActivity { get; private set; }
217217
public bool FreeToPlay { get; private set; }
@@ -575,14 +575,22 @@ public override void Construct(BitWriter writer)
575575
writer.Write((ulong) TotalFirstPlaceFinishes);
576576
writer.WriteBit(false);
577577

578-
writer.WriteBit(LandingByRocket);
578+
if (Rocket != default)
579+
{
580+
// Send the rocket if it is set to land by rocket and rocket is defined.
581+
writer.WriteBit(LandingByRocket);
579582

580-
if (LandingByRocket)
583+
if (LandingByRocket)
584+
{
585+
var rocketString = Rocket;
586+
writer.Write((ushort) rocketString.Length);
587+
writer.WriteString(rocketString, rocketString.Length, true);
588+
}
589+
}
590+
else
581591
{
582-
var rocketString = Rocket;
583-
584-
writer.Write((ushort) rocketString.Length);
585-
writer.WriteString(rocketString, rocketString.Length, true);
592+
// Set the landing as not by rocket. Even if it is, this prevents a null reference exception.
593+
writer.WriteBit(false);
586594
}
587595

588596
WritePart4(writer);

Uchu.World/Objects/Components/Server/RocketLaunchpadComponent.cs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@ protected RocketLaunchpadComponent()
1212
{
1313
Listen(OnStart, () =>
1414
{
15-
Listen(GameObject.OnInteract, async player =>
16-
{
17-
await OnInteract(player);
18-
});
15+
Listen(GameObject.OnInteract, OnInteract);
1916
});
2017
}
2118

22-
public async Task OnInteract(Player player)
19+
public void OnInteract(Player player)
2320
{
2421
var rocket = player.GetComponent<InventoryManagerComponent>()[InventoryType.Models].Items.FirstOrDefault(
2522
item => item.Lot == Lot.ModularRocket
@@ -28,7 +25,6 @@ public async Task OnInteract(Player player)
2825
if (rocket == default)
2926
{
3027
Logger.Error($"Could not find a valid rocket for {player}");
31-
3228
return;
3329
}
3430

@@ -42,13 +38,8 @@ public async Task OnInteract(Player player)
4238
Sender = player
4339
});
4440

45-
await using var ctx = new UchuContext();
46-
47-
var character = await ctx.Characters.FirstAsync(c => c.Id == player.Id);
48-
49-
character.LandingByRocket = true;
50-
51-
await ctx.SaveChangesAsync();
41+
if (!player.TryGetComponent<CharacterComponent>(out var characterComponent));
42+
characterComponent.LandingByRocket = true;
5243
}
5344
}
5445
}

Uchu.World/Objects/GameObjects/Player.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ public sealed class Player : GameObject
2424
{
2525
public static async Task<Player> Instantiate(IRakConnection connection, Zone zone, ObjectId id)
2626
{
27+
// Set up a cancellation token for the connection disconnecting.
28+
// This may happen before the object starts.
29+
var cancellationToken = new CancellationTokenSource();
30+
connection.Disconnected += (disconnectionReason) =>
31+
{
32+
cancellationToken.Cancel();
33+
return Task.CompletedTask;
34+
};
35+
2736
// Create base game object
2837
var instance = Instantiate<Player>(
2938
zone,
@@ -34,7 +43,7 @@ public static async Task<Player> Instantiate(IRakConnection connection, Zone zon
3443
lot: 1
3544
);
3645

37-
await instance.LoadAsync(connection);
46+
await instance.LoadAsync(connection, cancellationToken.Token);
3847
return instance;
3948
}
4049

@@ -51,6 +60,13 @@ internal Player()
5160

5261
Listen(OnStart, () =>
5362
{
63+
// Destroy the player on disconnect.
64+
// Also check if the player disconnected during loading.
65+
if (_loadCancellationToken != default && _loadCancellationToken.IsCancellationRequested)
66+
{
67+
DestroyAsync().Wait();
68+
return;
69+
}
5470
Connection.Disconnected += async reason =>
5571
{
5672
await DestroyAsync();
@@ -132,14 +148,15 @@ public async Task DestroyAsync(CloseReason? reason = CloseReason.ClientDisconnec
132148
/// <param name="connection">User endpoint for this character</param>
133149
/// <param name="zone">The zone to spawn in</param>
134150
/// <returns>The constructed player</returns>
135-
public async Task LoadAsync(IRakConnection connection)
151+
public async Task LoadAsync(IRakConnection connection, CancellationToken cancellationToken)
136152
{
137153
await using var uchuContext = new UchuContext();
138154
var character = await uchuContext.Characters
139155
.SingleAsync(c => c.Id == Id);
140156

141157
Connection = connection;
142158
Name = character.Name;
159+
_loadCancellationToken = cancellationToken;
143160

144161
// Setup layers
145162
Layer = StandardLayer.Player;
@@ -253,6 +270,12 @@ public override string Name
253270
/// Internal gravity scale of the player
254271
/// </summary>
255272
private float _gravityScale = 1;
273+
274+
/// <summary>
275+
/// Cancellation token for loading the player, such
276+
/// as if the player disconnects.
277+
/// </summary>
278+
private CancellationToken _loadCancellationToken;
256279

257280
/// <summary>
258281
/// Gravity scale of the player
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using RakDotNet;
2+
using RakDotNet.IO;
3+
4+
namespace Uchu.World.Objects.ReplicaManager
5+
{
6+
public class ConstructionPacket : ISerializable
7+
{
8+
/// <summary>
9+
/// Id to serialize with.
10+
/// </summary>
11+
public ushort Id { get; set; }
12+
13+
/// <summary>
14+
/// Game object to construct.
15+
/// </summary>
16+
public GameObject GameObject { get; set; }
17+
18+
/// <summary>
19+
/// Writes the serialization data.
20+
/// </summary>
21+
/// <param name="writer">Bit writer for the data.</param>
22+
public void Serialize(BitWriter writer)
23+
{
24+
writer.Write((byte) MessageIdentifier.ReplicaManagerConstruction);
25+
26+
writer.WriteBit(true);
27+
writer.Write(Id);
28+
29+
GameObject.WriteConstruct(writer);
30+
}
31+
}
32+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using RakDotNet;
2+
using RakDotNet.IO;
3+
4+
namespace Uchu.World.Objects.ReplicaManager
5+
{
6+
public class DestructionPacket: ISerializable
7+
{
8+
/// <summary>
9+
/// Id to serialize with.
10+
/// </summary>
11+
public ushort Id { get; set; }
12+
13+
/// <summary>
14+
/// Writes the serialization data.
15+
/// </summary>
16+
/// <param name="writer">Bit writer for the data.</param>
17+
public void Serialize(BitWriter writer)
18+
{
19+
writer.Write((byte) MessageIdentifier.ReplicaManagerDestruction);
20+
21+
writer.Write(Id);
22+
}
23+
}
24+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using RakDotNet;
2+
using RakDotNet.IO;
3+
4+
namespace Uchu.World.Objects.ReplicaManager
5+
{
6+
public class SerializePacket : ISerializable
7+
{
8+
/// <summary>
9+
/// Id to serialize with.
10+
/// </summary>
11+
public ushort Id { get; set; }
12+
13+
/// <summary>
14+
/// Game object to construct.
15+
/// </summary>
16+
public GameObject GameObject { get; set; }
17+
18+
/// <summary>
19+
/// Writes the serialization data.
20+
/// </summary>
21+
/// <param name="writer">Bit writer for the data.</param>
22+
public void Serialize(BitWriter writer)
23+
{
24+
writer.Write((byte) MessageIdentifier.ReplicaManagerSerialize);
25+
26+
writer.Write(Id);
27+
28+
GameObject.WriteSerialize(writer);
29+
}
30+
}
31+
}

Uchu.World/Objects/Zone.cs

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using Uchu.Physics;
2020
using Uchu.Python;
2121
using Uchu.World.Client;
22+
using Uchu.World.Objects.ReplicaManager;
2223
using Uchu.World.Scripting;
2324
using Uchu.World.Systems.AI;
2425

@@ -440,22 +441,14 @@ internal static void SendConstruction(GameObject gameObject, IEnumerable<Player>
440441
foreach (var recipient in recipients)
441442
{
442443
if (!recipient.Perspective.View(gameObject)) continue;
443-
444444
if (!recipient.Perspective.Reveal(gameObject, out var id)) continue;
445-
446445
if (id == 0) return;
447446

448-
using var stream = new MemoryStream();
449-
using var writer = new BitWriter(stream);
450-
451-
writer.Write((byte) MessageIdentifier.ReplicaManagerConstruction);
452-
453-
writer.WriteBit(true);
454-
writer.Write(id);
455-
456-
gameObject.WriteConstruct(writer);
457-
458-
recipient.Connection.Send(stream);
447+
recipient.Connection.Send(new ConstructionPacket()
448+
{
449+
Id = id,
450+
GameObject = gameObject,
451+
});
459452
}
460453
}
461454

@@ -465,16 +458,11 @@ internal static void SendSerialization(GameObject gameObject, IEnumerable<Player
465458
{
466459
if (!recipient.Perspective.TryGetNetworkId(gameObject, out var id)) continue;
467460

468-
using var stream = new MemoryStream();
469-
using var writer = new BitWriter(stream);
470-
471-
writer.Write((byte) MessageIdentifier.ReplicaManagerSerialize);
472-
473-
writer.Write(id);
474-
475-
gameObject.WriteSerialize(writer);
476-
477-
recipient.Connection.Send(stream);
461+
recipient.Connection.Send(new SerializePacket()
462+
{
463+
Id = id,
464+
GameObject = gameObject,
465+
});
478466
}
479467
}
480468

@@ -488,19 +476,12 @@ internal static void SendDestruction(GameObject gameObject, IEnumerable<Player>
488476
foreach (var recipient in recipients)
489477
{
490478
if (recipient.Perspective.View(gameObject)) continue;
491-
492479
if (!recipient.Perspective.TryGetNetworkId(gameObject, out var id)) continue;
493480

494-
using (var stream = new MemoryStream())
481+
recipient.Connection.Send(new DestructionPacket()
495482
{
496-
using var writer = new BitWriter(stream);
497-
498-
writer.Write((byte) MessageIdentifier.ReplicaManagerDestruction);
499-
500-
writer.Write(id);
501-
502-
recipient.Connection.Send(stream);
503-
}
483+
Id = id,
484+
});
504485

505486
recipient.Perspective.Drop(gameObject);
506487
}

0 commit comments

Comments
 (0)