Skip to content

Commit 11579ab

Browse files
committed
editor + client jackpot fix
1 parent 6fa4601 commit 11579ab

File tree

3 files changed

+72
-24
lines changed

3 files changed

+72
-24
lines changed

Intersect.Server/Database/IntersectDbContext.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Diagnostics;
44
using Intersect.Config;
55
using Intersect.Server.Database.Converters;
6+
using Intersect.Server.Database.PlayerData;
67
using Microsoft.EntityFrameworkCore;
78
using Microsoft.EntityFrameworkCore.ChangeTracking;
89
using Microsoft.EntityFrameworkCore.Infrastructure;
@@ -57,18 +58,21 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
5758
: QueryTrackingBehavior.TrackAll);
5859

5960
var loggerFactory = ContextOptions.LoggerFactory;
60-
#if DEBUG
61-
loggerFactory ??= new IntersectLoggerFactory();
61+
#if DIAGNOSTIC
62+
if (this is PlayerContext)
63+
{
64+
loggerFactory ??= new IntersectLoggerFactory();
65+
}
6266
#endif
6367

6468
var enableSensitiveDataLogging = ContextOptions.EnableSensitiveDataLogging;
65-
#if DEBUG
66-
enableSensitiveDataLogging = true;
69+
#if DIAGNOSTIC
70+
enableSensitiveDataLogging = this is PlayerContext;
6771
#endif
6872

6973
var enableDetailedErrors = ContextOptions.EnableDetailedErrors;
70-
#if DEBUG
71-
enableDetailedErrors = true;
74+
#if DIAGNOSTIC
75+
enableDetailedErrors = this is PlayerContext;
7276
#endif
7377

7478
_ = optionsBuilder

Intersect.Server/Database/PlayerData/User.cs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Intersect.Enums;
88
using Intersect.GameObjects;
99
using Intersect.Logging;
10+
using Intersect.Reflection;
1011
using Intersect.Security;
1112
using Intersect.Server.Core;
1213
using Intersect.Server.Database.Logging.Entities;
@@ -309,8 +310,16 @@ public async Task SaveAsync(
309310

310311
public void Save(bool force = false, bool create = false) => Save(default, force, create);
311312

312-
public void Save(PlayerContext? playerContext, bool force = false, bool create = false)
313+
#if DIAGNOSTIC
314+
private int _saveCounter = 0;
315+
#endif
316+
317+
private void Save(PlayerContext? playerContext, bool force = false, bool create = false)
313318
{
319+
#if DIAGNOSTIC
320+
var currentExecutionId = _saveCounter++;
321+
#endif
322+
314323
//No passing in custom contexts here.. they may already have this user in the change tracker and things just get weird.
315324
//The cost of making a new context is almost nil.
316325
var lockTaken = false;
@@ -332,6 +341,10 @@ public void Save(PlayerContext? playerContext, bool force = false, bool create =
332341
return;
333342
}
334343

344+
#if DIAGNOSTIC
345+
Log.Debug($"DBOP-A Save({playerContext}, {force}, {create}) #{currentExecutionId} {Name} ({Id})");
346+
#endif
347+
335348
if (playerContext == null)
336349
{
337350
createdContext = DbInterface.CreatePlayerContext(false);
@@ -360,6 +373,10 @@ public void Save(PlayerContext? playerContext, bool force = false, bool create =
360373
}
361374

362375
playerContext.SaveChanges();
376+
377+
#if DIAGNOSTIC
378+
Log.Debug($"DBOP-B Save({playerContext}, {force}, {create}) #{currentExecutionId} {Name} ({Id})");
379+
#endif
363380
}
364381
catch (DbUpdateConcurrencyException ex)
365382
{
@@ -369,37 +386,46 @@ public void Save(PlayerContext? playerContext, bool force = false, bool create =
369386
var type = entry.GetType().FullName;
370387
concurrencyErrors.AppendLine($"Entry Type [{type} / {entry.State}]");
371388
concurrencyErrors.AppendLine("--------------------");
389+
concurrencyErrors.AppendLine($"Type: {entry.Entity.GetFullishName()}");
372390

373391
var proposedValues = entry.CurrentValues;
374392
var databaseValues = entry.GetDatabaseValues();
375393

376-
foreach (var property in proposedValues.Properties)
377-
{
378-
concurrencyErrors.AppendLine(
379-
$"{property.Name} (Token: {property.IsConcurrencyToken}): Proposed: {proposedValues[property]} Original Value: {entry.OriginalValues[property]} Database Value: {(databaseValues != null ? databaseValues[property] : "null")}"
380-
);
381-
}
394+
var propertyNameColumnSize = proposedValues.Properties.Max(property => property.Name.Length);
382395

383-
foreach (var property in entry.Properties)
396+
foreach (var property in proposedValues.Properties)
384397
{
385398
concurrencyErrors.AppendLine(
386-
$"{property.Metadata.Name} {nameof(property.IsModified)}={property.IsModified} {nameof(property.IsTemporary)}={property.IsTemporary}"
399+
$"\t{property.Name:propertyNameColumnSize} (Token: {property.IsConcurrencyToken}): Proposed: {proposedValues[property]} Original Value: {entry.OriginalValues[property]} Database Value: {(databaseValues != null ? databaseValues[property] : "null")}"
387400
);
388401
}
389402

390403
concurrencyErrors.AppendLine("");
391404
concurrencyErrors.AppendLine("");
392405
}
393406

394-
Log.Error(ex, $"Jackpot! Concurrency Bug For {Name} in {(createdContext == default ? "Existing" : "Created")} Context");
407+
var suffix = string.Empty;
408+
#if DIAGNOSTIC
409+
suffix = $"#{currentExecutionId}";
410+
#endif
411+
Log.Error(ex, $"Jackpot! Concurrency Bug For {Name} in {(createdContext == default ? "Existing" : "Created")} Context {suffix}");
395412
Log.Error(concurrencyErrors.ToString());
413+
414+
#if DIAGNOSTIC
415+
Log.Debug($"DBOP-C Save({playerContext}, {force}, {create}) #{currentExecutionId} {Name} ({Id})");
416+
#endif
417+
396418
ServerContext.DispatchUnhandledException(
397419
new Exception("Failed to save user, shutting down to prevent rollbacks!")
398420
);
399421
}
400422
catch (Exception ex)
401423
{
402424
Log.Error(ex, "Failed to save user: " + Name);
425+
426+
#if DIAGNOSTIC
427+
Log.Debug($"DBOP-C Save({playerContext}, {force}, {create}) #{currentExecutionId} {Name} ({Id})");
428+
#endif
403429
ServerContext.DispatchUnhandledException(
404430
new Exception("Failed to save user, shutting down to prevent rollbacks!")
405431
);
@@ -449,7 +475,8 @@ public static User TryLogin(string username, string ptPassword)
449475
var hashedPassword = SaltPasswordHash(ptPassword, user.Salt);
450476
if (string.Equals(user.Password, hashedPassword, StringComparison.Ordinal))
451477
{
452-
return PostLoad(user);
478+
//return PostLoad(user);
479+
return user;
453480
}
454481
}
455482
else

Intersect.Server/Entities/Player.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -498,11 +498,24 @@ private void Logout(bool softLogout = false)
498498
DbInterface.Pool.QueueWorkItem(CompleteLogout);
499499
}
500500

501+
#if DIAGNOSTIC
502+
private int _logoutCounter = 0;
503+
#endif
504+
501505
public void CompleteLogout()
502506
{
507+
#if DIAGNOSTIC
508+
var currentExecutionId = _logoutCounter++;
509+
Log.Debug($"Started {nameof(CompleteLogout)}() #{currentExecutionId} on {Name} ({User?.Name})");
510+
#endif
511+
503512
User?.Save();
504513

505514
Dispose();
515+
516+
#if DIAGNOSTIC
517+
Log.Debug($"Finished {nameof(CompleteLogout)}() #{currentExecutionId} on {Name} ({User?.Name})");
518+
#endif
506519
}
507520

508521
//Update
@@ -535,6 +548,10 @@ public override void Update(long timeMs)
535548
var user = User;
536549
if (user != null)
537550
{
551+
if (Client.IsEditor)
552+
{
553+
Log.Debug($"Editor saving user: {user.Name}");
554+
}
538555
DbInterface.Pool.QueueWorkItem(user.Save, false);
539556
}
540557
SaveTimer = Timing.Global.Milliseconds + Options.Instance.Processing.PlayerSaveInterval;
@@ -1425,7 +1442,7 @@ public override bool CanAttack(Entity entity, SpellBase spell)
14251442
{
14261443
return false;
14271444
}
1428-
1445+
14291446
if (spell?.Combat?.TargetType == SpellTargetType.Self ||
14301447
spell?.Combat?.TargetType == SpellTargetType.Projectile ||
14311448
spell?.SpellType == SpellType.Dash
@@ -2477,7 +2494,7 @@ public bool TryGiveItem(Item item, ItemHandling handler = ItemHandling.Normal, b
24772494

24782495
break;
24792496
}
2480-
2497+
24812498
case ItemHandling.UpTo:
24822499
if (CanGiveItem(item, slot)) // Can receive item under regular rules.
24832500
{
@@ -3278,10 +3295,10 @@ public int FindInventoryItemQuantity(Guid itemId)
32783295
/// </summary>
32793296
/// <param name="slot">The <see cref="InventorySlot"/> to find</param>
32803297
/// <returns>An <see cref="int"/>containing the relevant index, or -1 if not found</returns>
3281-
public int FindInventoryItemSlotIndex(InventorySlot slot)
3298+
public int FindInventoryItemSlotIndex(InventorySlot slot)
32823299
{
32833300
return Items.FindIndex(sl => sl.Id == slot.Id);
3284-
}
3301+
}
32853302

32863303
/// <summary>
32873304
/// Finds all inventory slots matching the desired item and quantity.
@@ -3516,7 +3533,7 @@ public void SellItem(int slot, int amount)
35163533
}
35173534

35183535
PacketSender.SendInventoryItemUpdate(this, currentSlotIndex);
3519-
3536+
35203537
amountRemaining -= amountFromSlot;
35213538
if (amountRemaining > 0)
35223539
{
@@ -4182,7 +4199,7 @@ public void StoreBagItem(int inventorySlotIndex, int amount, int bagSlotIndex)
41824199

41834200
relevantSlots.Add(requestedSlot);
41844201
}
4185-
4202+
41864203
// If the item is stackable, add slots that contain that item into the mix
41874204
if (itemDescriptor.IsStackable)
41884205
{
@@ -5213,7 +5230,7 @@ public bool SlotIsEquipped(int slot, out int equippedSlot)
52135230
}
52145231
equippedSlot++;
52155232
}
5216-
5233+
52175234
equippedSlot = -1;
52185235
return false;
52195236
}

0 commit comments

Comments
 (0)