Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions Intersect.Server.Core/Entities/Player.Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@ public partial class Player
[NotMapped, JsonIgnore]
public long SaveTimer { get; set; } = Timing.Global.Milliseconds + Options.Instance.Processing.PlayerSaveInterval;

[NotMapped, JsonIgnore]
public bool IsSaving
{
get
{
lock (_pendingLogoutLock)
{
if (_pendingLogouts.Contains(Id))
{
return true;
}
}

lock (_savingLock)
{
return _saving;
}
}
}

#endregion

#region Entity Framework
Expand Down Expand Up @@ -165,15 +185,6 @@ public static bool PlayerExists(string name)

public bool LoadRelationships(PlayerContext playerContext, bool loadBags = false)
{
lock (_savingLock)
{
if (_saving)
{
Log.Warn($"Skipping loading relationships for player {Id} because it is being saved.");
return false;
}
}

var entityEntry = playerContext.Players.Attach(this);
entityEntry.Collection(p => p.Bank).Load();
entityEntry.Collection(p => p.Hotbar).Load();
Expand Down
26 changes: 22 additions & 4 deletions Intersect.Server.Core/Entities/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,11 @@ private void Logout(bool softLogout = false)
{
lock (_savingLock)
{
lock (_pendingLogoutLock)
{
_pendingLogouts.Add(Id);
}

_saving = true;
}

Expand Down Expand Up @@ -591,14 +596,17 @@ private void Logout(bool softLogout = false)
var stackTrace = default(string);
#endif
var logoutOperationId = Guid.NewGuid();
DbInterface.Pool.QueueWorkItem(CompleteLogout, logoutOperationId, stackTrace);
DbInterface.Pool.QueueWorkItem(CompleteLogout, logoutOperationId, softLogout, stackTrace);
}

#if DIAGNOSTIC
private int _logoutCounter = 0;
#endif

public void CompleteLogout(Guid logoutOperationId, string? stackTrace = default)
private static readonly HashSet<Guid> _pendingLogouts = [];
private static readonly object _pendingLogoutLock = new();

public void CompleteLogout(Guid logoutOperationId, bool softLogout, string? stackTrace = default)
{
if (logoutOperationId != default)
{
Expand Down Expand Up @@ -648,10 +656,20 @@ public void CompleteLogout(Guid logoutOperationId, string? stackTrace = default)

lock (_savingLock)
{
var logoutType = softLogout ? "soft" : "hard";
Log.Info($"[Player.CompleteLogout] Done saving {Name} ({logoutType} logout, {Id})");
_saving = false;
}

Dispose();
if (!softLogout)
{
Dispose();
}

lock (_pendingLogoutLock)
{
_pendingLogouts.Remove(Id);
}
}

#if DIAGNOSTIC
Log.Debug($"Finished {nameof(CompleteLogout)}() #{currentExecutionId} on {Name} ({User?.Name})");
Expand Down
3 changes: 3 additions & 0 deletions Intersect.Server.Core/Localization/Strings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ public sealed partial class AccountNamespace : LocaleNamespace
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public readonly LocalizedString LoadFail = @"Failed to load account. Please try logging in again.";

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public readonly LocalizedString PlayerSavingTryAgainLater = @"'{00}' is currently being saved, please try again later.";

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public readonly LocalizedString MaxCharacters = @"You have already created the maximum number of characters. Delete one before creating a new one.";

Expand Down
22 changes: 21 additions & 1 deletion Intersect.Server.Core/Networking/PacketHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2508,13 +2508,33 @@ public void HandlePacket(Client client, SelectCharacterPacket packet)
return;
}

if (character.IsSaving)
{
PacketSender.SendError(
client,
Strings.Account.PlayerSavingTryAgainLater.ToString(character.Name),
Strings.General.NoticeError
);
return;
}

ObjectDisposedException.ThrowIf(character.IsDisposed, character);

client.LoadCharacter(character);

UserActivityHistory.LogActivity(client.User?.Id ?? Guid.Empty, client?.Entity?.Id ?? Guid.Empty, client?.Ip, UserActivityHistory.PeerType.Client, UserActivityHistory.UserAction.SelectPlayer, $"{client?.Name},{client?.Entity?.Name}");
UserActivityHistory.LogActivity(
client.User?.Id ?? Guid.Empty,
client?.Entity?.Id ?? Guid.Empty,
client?.Ip,
UserActivityHistory.PeerType.Client,
UserActivityHistory.UserAction.SelectPlayer,
$"{client?.Name},{client?.Entity?.Name}"
);

try
{
client.Entity?.SetOnline();

PacketSender.SendJoinGame(client);
}
catch (Exception exception)
Expand Down
Loading