Persistence fixes
This commit is contained in:
parent
668287a7e2
commit
90adbdab89
@ -95,7 +95,7 @@ internal sealed unsafe class GameHooks : IDisposable
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(mapping.PlayerName))
|
if (!string.IsNullOrEmpty(mapping.PlayerName))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Content id {ContentId} belongs to '{Name}'", mapping.ContentId,
|
_logger.LogDebug("Content id {ContentId} belongs to '{Name}'", mapping.ContentId,
|
||||||
mapping.PlayerName);
|
mapping.PlayerName);
|
||||||
mappings.Add(mapping);
|
mappings.Add(mapping);
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ internal sealed unsafe class GameHooks : IDisposable
|
|||||||
///
|
///
|
||||||
/// Both 1 and 2 are sent to you on login, unprompted.
|
/// Both 1 and 2 are sent to you on login, unprompted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 0x380)]
|
[StructLayout(LayoutKind.Explicit, Size = 0x420)]
|
||||||
internal struct SocialListResultPage
|
internal struct SocialListResultPage
|
||||||
{
|
{
|
||||||
[FieldOffset(0x10)] private fixed byte Players[10 * 0x58];
|
[FieldOffset(0x10)] private fixed byte Players[10 * 0x58];
|
||||||
@ -144,7 +144,7 @@ internal sealed unsafe class GameHooks : IDisposable
|
|||||||
public Span<SocialListPlayer> PlayerSpan => new(Unsafe.AsPointer(ref Players[0]), 10);
|
public Span<SocialListPlayer> PlayerSpan => new(Unsafe.AsPointer(ref Players[0]), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 0x58)]
|
[StructLayout(LayoutKind.Explicit, Size = 0x68, Pack = 1)]
|
||||||
internal struct SocialListPlayer
|
internal struct SocialListPlayer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -156,6 +156,6 @@ internal sealed unsafe class GameHooks : IDisposable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This *can* be empty, e.g. if you're querying your friend list, the names are ONLY set for characters on the same world.
|
/// This *can* be empty, e.g. if you're querying your friend list, the names are ONLY set for characters on the same world.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[FieldOffset(0x31)] public fixed byte CharacterName[32];
|
[FieldOffset(0x3C)] public fixed byte CharacterName[32];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,29 +89,43 @@ internal sealed class PersistenceContext
|
|||||||
WorldId = worldId,
|
WorldId = worldId,
|
||||||
OwnerLocalContentId = l.RetainerOwnerId,
|
OwnerLocalContentId = l.RetainerOwnerId,
|
||||||
})
|
})
|
||||||
|
.Where(mapping =>
|
||||||
|
{
|
||||||
|
if (mapping.Name == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var currentWorldCache = _worldRetainerCache.GetOrAdd(mapping.WorldId, _ => new());
|
||||||
|
if (currentWorldCache.TryGetValue(mapping.Name, out ulong playerContentId))
|
||||||
|
return mapping.OwnerLocalContentId != playerContentId;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.DistinctBy(x => x.LocalContentId)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
using var scope = _serviceProvider.CreateScope();
|
using var scope = _serviceProvider.CreateScope();
|
||||||
using var dbContext = scope.ServiceProvider.GetRequiredService<RetainerTrackContext>();
|
using var dbContext = scope.ServiceProvider.GetRequiredService<RetainerTrackContext>();
|
||||||
|
|
||||||
var ids = updates.Select(x => x.LocalContentId).ToList();
|
|
||||||
var dbRetainers = dbContext.Retainers.Where(x => ids.Contains(x.LocalContentId))
|
|
||||||
.ToDictionary(x => x.LocalContentId, x => x);
|
|
||||||
foreach (var retainer in updates)
|
foreach (var retainer in updates)
|
||||||
{
|
{
|
||||||
if (dbRetainers.TryGetValue(retainer.LocalContentId, out var dbRetainer))
|
Retainer? dbRetainer = dbContext.Retainers.Find(retainer.LocalContentId);
|
||||||
|
if (dbRetainer != null)
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("Updating retainer {RetainerName} with {LocalContentId}", retainer.Name, retainer.LocalContentId);
|
||||||
dbRetainer.Name = retainer.Name;
|
dbRetainer.Name = retainer.Name;
|
||||||
dbRetainer.WorldId = retainer.WorldId;
|
dbRetainer.WorldId = retainer.WorldId;
|
||||||
dbRetainer.OwnerLocalContentId = retainer.OwnerLocalContentId;
|
dbRetainer.OwnerLocalContentId = retainer.OwnerLocalContentId;
|
||||||
dbContext.Retainers.Update(dbRetainer);
|
dbContext.Retainers.Update(dbRetainer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Adding retainer {RetainerName} with {LocalContentId}", retainer.Name, retainer.LocalContentId);
|
||||||
dbContext.Retainers.Add(retainer);
|
dbContext.Retainers.Add(retainer);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_playerNameCache.TryGetValue(retainer.OwnerLocalContentId, out string? ownerName))
|
if (!_playerNameCache.TryGetValue(retainer.OwnerLocalContentId, out string? ownerName))
|
||||||
ownerName = retainer.OwnerLocalContentId.ToString(CultureInfo.InvariantCulture);
|
ownerName = retainer.OwnerLocalContentId.ToString(CultureInfo.InvariantCulture);
|
||||||
_logger.LogTrace("Retainer {RetainerName} belongs to {OwnerId}", retainer.Name,
|
_logger.LogDebug(" Retainer {RetainerName} belongs to {OwnerName}", retainer.Name,
|
||||||
ownerName);
|
ownerName);
|
||||||
|
|
||||||
if (retainer.Name != null)
|
if (retainer.Name != null)
|
||||||
@ -121,7 +135,9 @@ internal sealed class PersistenceContext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
int changeCount = dbContext.SaveChanges();
|
||||||
|
if (changeCount > 0)
|
||||||
|
_logger.LogDebug("Saved {Count} retainer mappings", changeCount);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -153,17 +169,31 @@ internal sealed class PersistenceContext
|
|||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
if (updates.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
using (var scope = _serviceProvider.CreateScope())
|
using (var scope = _serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
using var dbContext = scope.ServiceProvider.GetRequiredService<RetainerTrackContext>();
|
using var dbContext = scope.ServiceProvider.GetRequiredService<RetainerTrackContext>();
|
||||||
foreach (var update in updates)
|
foreach (var update in updates)
|
||||||
{
|
{
|
||||||
if (!dbContext.Players.Any(x => x.LocalContentId == update.LocalContentId))
|
var dbPlayer = dbContext.Players.Find(update.LocalContentId);
|
||||||
dbContext.Players.AddRange(updates);
|
if (dbPlayer == null)
|
||||||
|
dbContext.Players.Add(update);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dbPlayer.Name = update.Name;
|
||||||
|
dbContext.Players.Update(dbPlayer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
int changeCount = dbContext.SaveChanges();
|
||||||
|
if (changeCount > 0)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Saved {Count} player mappings", changeCount);
|
||||||
|
foreach (var update in updates)
|
||||||
|
_logger.LogTrace(" {ContentId} = {Name}", update.LocalContentId, update.Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var player in updates)
|
foreach (var player in updates)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<Version>3.1</Version>
|
<Version>3.2</Version>
|
||||||
<LangVersion>12.0</LangVersion>
|
<LangVersion>12.0</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
Loading…
Reference in New Issue
Block a user