diff --git a/src/Randomizer.Multiplayer.Server/GameManager.cs b/src/Randomizer.Multiplayer.Server/GameManager.cs
index 18ae2e07d..52e2fc7d1 100644
--- a/src/Randomizer.Multiplayer.Server/GameManager.cs
+++ b/src/Randomizer.Multiplayer.Server/GameManager.cs
@@ -54,7 +54,7 @@ private async Task CheckGames()
expiredGuids = await _dbService.DeleteOldGameStates(_databaseExpirationDays);
_logger.LogInformation("Removed {Amount} inactive games(s) from database", expiredGuids.Count);
- _logger.LogInformation("Current active games: {GameCount} | Current connected players: {PlayerCount}", MultiplayerGame.GameCount, MultiplayerGame.PlayerCount);
+ _logger.LogInformation("[{Date}] Current active games: {GameCount} | Current connected players: {PlayerCount}", DateTime.Now, MultiplayerGame.GameCount, MultiplayerGame.PlayerCount);
await Task.Delay(TimeSpan.FromMinutes(_checkFrequencyMinutes));
}
diff --git a/src/Randomizer.Multiplayer.Server/Migrations/20230621133443_DeathLink.Designer.cs b/src/Randomizer.Multiplayer.Server/Migrations/20230621133443_DeathLink.Designer.cs
new file mode 100644
index 000000000..0153b32fd
--- /dev/null
+++ b/src/Randomizer.Multiplayer.Server/Migrations/20230621133443_DeathLink.Designer.cs
@@ -0,0 +1,350 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Randomizer.Multiplayer.Server;
+
+#nullable disable
+
+namespace Randomizer.Multiplayer.Server.Migrations
+{
+ [DbContext(typeof(MultiplayerDbContext))]
+ [Migration("20230621133443_DeathLink")]
+ partial class DeathLink
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "6.0.11");
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerBossState", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Boss")
+ .HasColumnType("INTEGER");
+
+ b.Property("GameId")
+ .HasColumnType("INTEGER");
+
+ b.Property("PlayerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Tracked")
+ .HasColumnType("INTEGER");
+
+ b.Property("TrackedTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GameId");
+
+ b.HasIndex("PlayerId");
+
+ b.ToTable("MultiplayerBossStates");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerDungeonState", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Dungeon")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("GameId")
+ .HasColumnType("INTEGER");
+
+ b.Property("PlayerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Tracked")
+ .HasColumnType("INTEGER");
+
+ b.Property("TrackedTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GameId");
+
+ b.HasIndex("PlayerId");
+
+ b.ToTable("MultiplayerDungeonStates");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerGameState", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CreatedDate")
+ .HasColumnType("TEXT");
+
+ b.Property("DeathLink")
+ .HasColumnType("INTEGER");
+
+ b.Property("Guid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("LastMessage")
+ .HasColumnType("TEXT");
+
+ b.Property("SaveToDatabase")
+ .HasColumnType("INTEGER");
+
+ b.Property("Seed")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("SendItemsOnComplete")
+ .HasColumnType("INTEGER");
+
+ b.Property("Status")
+ .HasColumnType("INTEGER");
+
+ b.Property("Type")
+ .HasColumnType("INTEGER");
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("ValidationHash")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Version")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("MultiplayerGameStates");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerItemState", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("GameId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Item")
+ .HasColumnType("INTEGER");
+
+ b.Property("PlayerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("TrackedTime")
+ .HasColumnType("TEXT");
+
+ b.Property("TrackingValue")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GameId");
+
+ b.HasIndex("PlayerId");
+
+ b.ToTable("MultiplayerItemStates");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerLocationState", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("GameId")
+ .HasColumnType("INTEGER");
+
+ b.Property("LocationId")
+ .HasColumnType("INTEGER");
+
+ b.Property("PlayerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Tracked")
+ .HasColumnType("INTEGER");
+
+ b.Property("TrackedTime")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GameId");
+
+ b.HasIndex("PlayerId");
+
+ b.ToTable("MultiplayerLocationStates");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerPlayerState", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AdditionalData")
+ .HasColumnType("TEXT");
+
+ b.Property("Config")
+ .HasColumnType("TEXT");
+
+ b.Property("GameId")
+ .HasColumnType("INTEGER");
+
+ b.Property("GenerationData")
+ .HasColumnType("TEXT");
+
+ b.Property("Guid")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("IsAdmin")
+ .HasColumnType("INTEGER");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("PhoneticName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("PlayerName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Status")
+ .HasColumnType("INTEGER");
+
+ b.Property("WorldId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GameId");
+
+ b.ToTable("MultiplayerPlayerStates");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerBossState", b =>
+ {
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerGameState", "Game")
+ .WithMany()
+ .HasForeignKey("GameId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerPlayerState", "Player")
+ .WithMany("Bosses")
+ .HasForeignKey("PlayerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Game");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerDungeonState", b =>
+ {
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerGameState", "Game")
+ .WithMany()
+ .HasForeignKey("GameId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerPlayerState", "Player")
+ .WithMany("Dungeons")
+ .HasForeignKey("PlayerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Game");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerItemState", b =>
+ {
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerGameState", "Game")
+ .WithMany()
+ .HasForeignKey("GameId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerPlayerState", "Player")
+ .WithMany("Items")
+ .HasForeignKey("PlayerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Game");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerLocationState", b =>
+ {
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerGameState", "Game")
+ .WithMany()
+ .HasForeignKey("GameId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerPlayerState", "Player")
+ .WithMany("Locations")
+ .HasForeignKey("PlayerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Game");
+
+ b.Navigation("Player");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerPlayerState", b =>
+ {
+ b.HasOne("Randomizer.Shared.Multiplayer.MultiplayerGameState", "Game")
+ .WithMany("Players")
+ .HasForeignKey("GameId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Game");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerGameState", b =>
+ {
+ b.Navigation("Players");
+ });
+
+ modelBuilder.Entity("Randomizer.Shared.Multiplayer.MultiplayerPlayerState", b =>
+ {
+ b.Navigation("Bosses");
+
+ b.Navigation("Dungeons");
+
+ b.Navigation("Items");
+
+ b.Navigation("Locations");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Randomizer.Multiplayer.Server/Migrations/20230621133443_DeathLink.cs b/src/Randomizer.Multiplayer.Server/Migrations/20230621133443_DeathLink.cs
new file mode 100644
index 000000000..196698104
--- /dev/null
+++ b/src/Randomizer.Multiplayer.Server/Migrations/20230621133443_DeathLink.cs
@@ -0,0 +1,26 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Randomizer.Multiplayer.Server.Migrations
+{
+ public partial class DeathLink : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "DeathLink",
+ table: "MultiplayerGameStates",
+ type: "INTEGER",
+ nullable: false,
+ defaultValue: false);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "DeathLink",
+ table: "MultiplayerGameStates");
+ }
+ }
+}
diff --git a/src/Randomizer.Multiplayer.Server/Migrations/MultiplayerDbContextModelSnapshot.cs b/src/Randomizer.Multiplayer.Server/Migrations/MultiplayerDbContextModelSnapshot.cs
index fef6ee340..d201a4587 100644
--- a/src/Randomizer.Multiplayer.Server/Migrations/MultiplayerDbContextModelSnapshot.cs
+++ b/src/Randomizer.Multiplayer.Server/Migrations/MultiplayerDbContextModelSnapshot.cs
@@ -87,6 +87,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property("CreatedDate")
.HasColumnType("TEXT");
+ b.Property("DeathLink")
+ .HasColumnType("INTEGER");
+
b.Property("Guid")
.IsRequired()
.HasColumnType("TEXT");
diff --git a/src/Randomizer.Multiplayer.Server/MultiplayerDbService.cs b/src/Randomizer.Multiplayer.Server/MultiplayerDbService.cs
index 87797da6c..b0cccd844 100644
--- a/src/Randomizer.Multiplayer.Server/MultiplayerDbService.cs
+++ b/src/Randomizer.Multiplayer.Server/MultiplayerDbService.cs
@@ -27,9 +27,16 @@ public MultiplayerDbService(IDbContextFactory contextFacto
public async Task AddGameToDatabase(MultiplayerGameState state)
{
if (!_isDatabaseEnabled || !state.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- dbContext.MultiplayerGameStates.Add(state);
- await SaveChanges(dbContext, "Unable add game to the database");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ dbContext.MultiplayerGameStates.Add(state);
+ await SaveChanges(dbContext, $"Unable add game {state.Guid} to the database");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to add game {Game} to the database", state.Guid);
+ }
}
///
@@ -78,7 +85,7 @@ public async Task AddGameToDatabase(MultiplayerGameState state)
}
catch (Exception ex)
{
- _logger.LogCritical(ex, "Unable to load game from database");
+ _logger.LogCritical(ex, "Unable to load game {Game} from database", guid);
return null;
}
}
@@ -91,9 +98,16 @@ public async Task AddGameToDatabase(MultiplayerGameState state)
public async Task AddPlayerToGame(MultiplayerGameState gameState, MultiplayerPlayerState playerState)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- dbContext.MultiplayerPlayerStates.Add(playerState);
- await SaveChanges(dbContext, $"Unable add player {playerState.Guid} to the database");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ dbContext.MultiplayerPlayerStates.Add(playerState);
+ await SaveChanges(dbContext, $"Unable to add player {playerState.Guid} to the database");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to add player {Player} to database", playerState.Guid);
+ }
}
///
@@ -103,12 +117,19 @@ public async Task AddPlayerToGame(MultiplayerGameState gameState, MultiplayerPla
public async Task SaveGameState(MultiplayerGameState gameState)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var dbState = dbContext.MultiplayerGameStates
- .FirstOrDefault(x => x.Id == gameState.Id);
- if (dbState == null) return;
- dbState.Copy(gameState);
- await SaveChanges(dbContext, $"Unable to save game state {gameState.Guid}");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var dbState = dbContext.MultiplayerGameStates
+ .FirstOrDefault(x => x.Id == gameState.Id);
+ if (dbState == null) return;
+ dbState.Copy(gameState);
+ await SaveChanges(dbContext, $"Unable to save game state {gameState.Guid}");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to save game state {Game}", gameState.Guid);
+ }
}
///
@@ -118,15 +139,22 @@ public async Task SaveGameState(MultiplayerGameState gameState)
public async Task SaveGameStates(IEnumerable gameStates)
{
if (!_isDatabaseEnabled) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var gameIds = gameStates.Where(x => x.SaveToDatabase).Select(x => x.Id).ToList();
- var dbStates = dbContext.MultiplayerGameStates
- .Where(x => gameIds.Contains(x.Id));
- foreach (var dbState in dbStates)
+ try
{
- dbState.Copy(gameStates.First(x => x.Id == dbState.Id));
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var gameIds = gameStates.Where(x => x.SaveToDatabase).Select(x => x.Id).ToList();
+ var dbStates = dbContext.MultiplayerGameStates
+ .Where(x => gameIds.Contains(x.Id));
+ foreach (var dbState in dbStates)
+ {
+ dbState.Copy(gameStates.First(x => x.Id == dbState.Id));
+ }
+ await SaveChanges(dbContext, "Unable to save game states");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to save game states");
}
- await SaveChanges(dbContext, "Unable to save game states");
}
///
@@ -137,11 +165,18 @@ public async Task SaveGameStates(IEnumerable gameStates)
public async Task SavePlayerState(MultiplayerGameState gameState, MultiplayerPlayerState playerState)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var dbState = await dbContext.MultiplayerPlayerStates.FindAsync(playerState.Id);
- if (dbState == null) return;
- dbState.Copy(playerState);
- await SaveChanges(dbContext, $"Unable to save player state for player {playerState.Guid}");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var dbState = await dbContext.MultiplayerPlayerStates.FindAsync(playerState.Id);
+ if (dbState == null) return;
+ dbState.Copy(playerState);
+ await SaveChanges(dbContext, $"Unable to save player state for player {playerState.Guid}");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to save player state {Player}", playerState.Guid);
+ }
}
///
@@ -152,15 +187,22 @@ public async Task SavePlayerState(MultiplayerGameState gameState, MultiplayerPla
public async Task SavePlayerStates(MultiplayerGameState gameState, IEnumerable playerStates)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var playerIds = playerStates.Select(x => x.Id).ToList();
- var dbStates = dbContext.MultiplayerPlayerStates
- .Where(x => playerIds.Contains(x.Id));
- foreach (var dbState in dbStates)
+ try
{
- dbState.Copy(playerStates.First(x => x.Id == dbState.Id));
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var playerIds = playerStates.Select(x => x.Id).ToList();
+ var dbStates = dbContext.MultiplayerPlayerStates
+ .Where(x => playerIds.Contains(x.Id));
+ foreach (var dbState in dbStates)
+ {
+ dbState.Copy(playerStates.First(x => x.Id == dbState.Id));
+ }
+ await SaveChanges(dbContext, $"Unable to save player states for game {gameState.Guid}");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to save player states for game {Game}", gameState.Guid);
}
- await SaveChanges(dbContext, "Unable to save player states");
}
///
@@ -171,12 +213,19 @@ public async Task SavePlayerStates(MultiplayerGameState gameState, IEnumerable
@@ -187,12 +236,20 @@ public async Task SaveLocationState(MultiplayerGameState gameState, MultiplayerL
public async Task SaveItemState(MultiplayerGameState gameState, MultiplayerItemState itemState)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var dbState = await dbContext.MultiplayerItemStates.FindAsync(itemState.Id);
- if (dbState == null) return;
- dbState.TrackingValue = itemState.TrackingValue;
- dbState.TrackedTime = itemState.TrackedTime;
- await SaveChanges(dbContext, "Unable to save item state");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var dbState = await dbContext.MultiplayerItemStates.FindAsync(itemState.Id);
+ if (dbState == null) return;
+ dbState.TrackingValue = itemState.TrackingValue;
+ dbState.TrackedTime = itemState.TrackedTime;
+ await SaveChanges(dbContext, $"Unable to save item state for player {itemState.Player.Guid}");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to save item state for player {Player}", itemState.Player.Guid);
+ }
+
}
///
@@ -203,12 +260,20 @@ public async Task SaveItemState(MultiplayerGameState gameState, MultiplayerItemS
public async Task SaveDungeonState(MultiplayerGameState gameState, MultiplayerDungeonState dungeonState)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var dbState = await dbContext.MultiplayerDungeonStates.FindAsync(dungeonState.Id);
- if (dbState == null) return;
- dbState.Tracked = dungeonState.Tracked;
- dbState.TrackedTime = dungeonState.TrackedTime;
- await SaveChanges(dbContext, "Unable to save dungeon state");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var dbState = await dbContext.MultiplayerDungeonStates.FindAsync(dungeonState.Id);
+ if (dbState == null) return;
+ dbState.Tracked = dungeonState.Tracked;
+ dbState.TrackedTime = dungeonState.TrackedTime;
+ await SaveChanges(dbContext, $"Unable to save dungeon state for player {dungeonState.Player.Guid}");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to save dungeon state for player {Player}", dungeonState.Player.Guid);
+ }
+
}
///
@@ -219,12 +284,19 @@ public async Task SaveDungeonState(MultiplayerGameState gameState, MultiplayerDu
public async Task SaveBossState(MultiplayerGameState gameState, MultiplayerBossState bossState)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var dbState = await dbContext.MultiplayerBossStates.FindAsync(bossState.Id);
- if (dbState == null) return;
- dbState.Tracked = bossState.Tracked;
- dbState.TrackedTime = bossState.TrackedTime;
- await SaveChanges(dbContext, $"Unable to save boss state");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var dbState = await dbContext.MultiplayerBossStates.FindAsync(bossState.Id);
+ if (dbState == null) return;
+ dbState.Tracked = bossState.Tracked;
+ dbState.TrackedTime = bossState.TrackedTime;
+ await SaveChanges(dbContext, $"Unable to save boss state for player {bossState.Player.Guid}");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to save boss state for player {Player}", bossState.Player.Guid);
+ }
}
///
@@ -236,85 +308,93 @@ public async Task SaveBossState(MultiplayerGameState gameState, MultiplayerBossS
public async Task SavePlayerWorld(MultiplayerGameState gameState, MultiplayerPlayerState playerState, PlayerWorldUpdates updates)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase || !updates.HasUpdates) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
-
- // Update locations
- var updateIds = updates.Locations.Select(x => x.Id).ToList();
- var dbLocations = dbContext.MultiplayerLocationStates
- .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
- .ToDictionary(x => x.Id, x => x);
- foreach (var updateData in updates.Locations)
- {
- if (dbLocations.ContainsKey(updateData.Id))
- {
- var dbData = dbLocations[updateData.Id];
- dbData.Tracked = updateData.Tracked;
- dbData.TrackedTime = updateData.TrackedTime;
- }
- else
- {
- dbContext.MultiplayerLocationStates.Add(updateData);
- }
- }
- // Update items
- updateIds = updates.Items.Select(x => x.Id).ToList();
- var dbItems = dbContext.MultiplayerItemStates
- .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
- .ToDictionary(x => x.Id, x => x);
- foreach (var updateData in updates.Items)
+ try
{
- if (dbItems.ContainsKey(updateData.Id))
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+
+ // Update locations
+ var updateIds = updates.Locations.Select(x => x.Id).ToList();
+ var dbLocations = dbContext.MultiplayerLocationStates
+ .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
+ .ToDictionary(x => x.Id, x => x);
+ foreach (var updateData in updates.Locations)
{
- var dbData = dbItems[updateData.Id];
- dbData.TrackingValue = updateData.TrackingValue;
- dbData.TrackedTime = updateData.TrackedTime;
+ if (dbLocations.ContainsKey(updateData.Id))
+ {
+ var dbData = dbLocations[updateData.Id];
+ dbData.Tracked = updateData.Tracked;
+ dbData.TrackedTime = updateData.TrackedTime;
+ }
+ else
+ {
+ dbContext.MultiplayerLocationStates.Add(updateData);
+ }
}
- else
+
+ // Update items
+ updateIds = updates.Items.Select(x => x.Id).ToList();
+ var dbItems = dbContext.MultiplayerItemStates
+ .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
+ .ToDictionary(x => x.Id, x => x);
+ foreach (var updateData in updates.Items)
{
- dbContext.MultiplayerItemStates.Add(updateData);
+ if (dbItems.ContainsKey(updateData.Id))
+ {
+ var dbData = dbItems[updateData.Id];
+ dbData.TrackingValue = updateData.TrackingValue;
+ dbData.TrackedTime = updateData.TrackedTime;
+ }
+ else
+ {
+ dbContext.MultiplayerItemStates.Add(updateData);
+ }
}
- }
- // Update dungeons
- updateIds = updates.Dungeons.Select(x => x.Id).ToList();
- var dbDungeons = dbContext.MultiplayerDungeonStates
- .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
- .ToDictionary(x => x.Id, x => x);
- foreach (var updateData in updates.Dungeons)
- {
- if (dbDungeons.ContainsKey(updateData.Id))
+ // Update dungeons
+ updateIds = updates.Dungeons.Select(x => x.Id).ToList();
+ var dbDungeons = dbContext.MultiplayerDungeonStates
+ .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
+ .ToDictionary(x => x.Id, x => x);
+ foreach (var updateData in updates.Dungeons)
{
- var dbData = dbDungeons[updateData.Id];
- dbData.Tracked = updateData.Tracked;
- dbData.TrackedTime = updateData.TrackedTime;
+ if (dbDungeons.ContainsKey(updateData.Id))
+ {
+ var dbData = dbDungeons[updateData.Id];
+ dbData.Tracked = updateData.Tracked;
+ dbData.TrackedTime = updateData.TrackedTime;
+ }
+ else
+ {
+ dbContext.MultiplayerDungeonStates.Add(updateData);
+ }
}
- else
+
+ // Update bosses
+ updateIds = updates.Bosses.Select(x => x.Id).ToList();
+ var dbBosses = dbContext.MultiplayerBossStates
+ .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
+ .ToDictionary(x => x.Id, x => x);
+ foreach (var updateData in updates.Bosses)
{
- dbContext.MultiplayerDungeonStates.Add(updateData);
+ if (dbBosses.ContainsKey(updateData.Id))
+ {
+ var dbData = dbBosses[updateData.Id];
+ dbData.Tracked = updateData.Tracked;
+ dbData.TrackedTime = updateData.TrackedTime;
+ }
+ else
+ {
+ dbContext.MultiplayerBossStates.Add(updateData);
+ }
}
- }
- // Update bosses
- updateIds = updates.Bosses.Select(x => x.Id).ToList();
- var dbBosses = dbContext.MultiplayerBossStates
- .Where(x => x.PlayerId == playerState.Id && updateIds.Contains(x.Id))
- .ToDictionary(x => x.Id, x => x);
- foreach (var updateData in updates.Bosses)
+ await SaveChanges(dbContext, $"Unable to save player world {playerState.Guid}");
+ }
+ catch (Exception e)
{
- if (dbBosses.ContainsKey(updateData.Id))
- {
- var dbData = dbBosses[updateData.Id];
- dbData.Tracked = updateData.Tracked;
- dbData.TrackedTime = updateData.TrackedTime;
- }
- else
- {
- dbContext.MultiplayerBossStates.Add(updateData);
- }
+ _logger.LogError(e, "Unable to save player world {Player}", playerState.Guid);
}
-
- await SaveChanges(dbContext, $"Unable to save player world {playerState.Guid}");
}
///
@@ -325,11 +405,18 @@ public async Task SavePlayerWorld(MultiplayerGameState gameState, MultiplayerPla
public async Task DeletePlayerState(MultiplayerGameState gameState, MultiplayerPlayerState playerState)
{
if (!_isDatabaseEnabled || !gameState.SaveToDatabase) return;
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var dbState = await dbContext.MultiplayerPlayerStates.FindAsync(playerState.Id);
- if (dbState == null) return;
- dbContext.MultiplayerPlayerStates.Remove(dbState);
- await SaveChanges(dbContext, $"Unable to delete player state {playerState.Guid}");
+ try
+ {
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var dbState = await dbContext.MultiplayerPlayerStates.FindAsync(playerState.Id);
+ if (dbState == null) return;
+ dbContext.MultiplayerPlayerStates.Remove(dbState);
+ await SaveChanges(dbContext, $"Unable to delete player state {playerState.Guid}");
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to delete player state {Player}", playerState.Guid);
+ }
}
///
@@ -340,18 +427,26 @@ public async Task DeletePlayerState(MultiplayerGameState gameState, MultiplayerP
public async Task> DeleteOldGameStates(int expirationDays)
{
if (!_isDatabaseEnabled) return new List();
- await using var dbContext = await _contextFactory.CreateDbContextAsync();
- var expirationDate = DateTimeOffset.Now - TimeSpan.FromDays(expirationDays);
- var dbStates = dbContext.MultiplayerGameStates.Where(x => x.LastMessage.CompareTo(expirationDate) < 0);
- var deletedGuids = new List();
- foreach (var dbState in dbStates)
+ try
{
- dbContext.Remove(dbState);
- deletedGuids.Add(dbState.Guid);
- }
+ await using var dbContext = await _contextFactory.CreateDbContextAsync();
+ var expirationDate = DateTimeOffset.Now - TimeSpan.FromDays(expirationDays);
+ var dbStates = dbContext.MultiplayerGameStates.Where(x => x.LastMessage.CompareTo(expirationDate) < 0);
+ var deletedGuids = new List();
+ foreach (var dbState in dbStates)
+ {
+ dbContext.Remove(dbState);
+ deletedGuids.Add(dbState.Guid);
+ }
- await SaveChanges(dbContext, "Unable to delete old game saves");
- return deletedGuids;
+ await SaveChanges(dbContext, "Unable to delete old game saves");
+ return deletedGuids;
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Unable to delete old game saves");
+ return new List();
+ }
}
private async Task SaveChanges(MultiplayerDbContext dbContext, string errorMessage)
diff --git a/src/Randomizer.Multiplayer.Server/Randomizer.Multiplayer.Server.csproj b/src/Randomizer.Multiplayer.Server/Randomizer.Multiplayer.Server.csproj
index 4c0f31254..f2593917a 100644
--- a/src/Randomizer.Multiplayer.Server/Randomizer.Multiplayer.Server.csproj
+++ b/src/Randomizer.Multiplayer.Server/Randomizer.Multiplayer.Server.csproj
@@ -4,7 +4,7 @@
net6.0
enable
enable
- 2.0.0
+ 2.1.0
False