Db: lmport

This commit is contained in:
Liza 2023-02-22 20:29:58 +01:00
parent d5dc55a0c4
commit 7bccec0bae
21 changed files with 505 additions and 116 deletions

View File

@ -115,7 +115,10 @@ namespace Pal.Client.Configuration.Legacy
.Distinct()
.ToList(),
Imported = o.WasImported,
// if we have a location not encountered locally, which also wasn't imported,
// it very likely is a download (but we have no information to track this).
Source = o.Seen ? ClientLocation.ESource.SeenLocally :
o.Imports.Count > 0 ? ClientLocation.ESource.Import : ClientLocation.ESource.Download,
SinceVersion = o.SinceVersion ?? "0.0",
};

View File

@ -0,0 +1,67 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
using Pal.Common;
namespace Pal.Client.Database
{
internal sealed class Cleanup
{
private readonly ILogger<Cleanup> _logger;
private readonly IPalacePalConfiguration _configuration;
public Cleanup(ILogger<Cleanup> logger, IPalacePalConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
public void Purge(PalClientContext dbContext)
{
var toDelete = dbContext.Locations
.Include(o => o.ImportedBy)
.Include(o => o.RemoteEncounters)
.AsSplitQuery()
.Where(DefaultPredicate())
.Where(AnyRemoteEncounter())
.ToList();
_logger.LogInformation("Cleaning up {Count} outdated locations", toDelete.Count);
dbContext.Locations.RemoveRange(toDelete);
}
public void Purge(PalClientContext dbContext, ETerritoryType territoryType)
{
var toDelete = dbContext.Locations
.Include(o => o.ImportedBy)
.Include(o => o.RemoteEncounters)
.AsSplitQuery()
.Where(o => o.TerritoryType == (ushort)territoryType)
.Where(DefaultPredicate())
.Where(AnyRemoteEncounter())
.ToList();
_logger.LogInformation("Cleaning up {Count} outdated locations for territory {Territory}", toDelete.Count,
territoryType);
dbContext.Locations.RemoveRange(toDelete);
}
private Expression<Func<ClientLocation, bool>> DefaultPredicate()
{
return o => !o.Seen &&
o.ImportedBy.Count == 0 &&
o.Source != ClientLocation.ESource.SeenLocally &&
o.Source != ClientLocation.ESource.ExplodedLocally;
}
private Expression<Func<ClientLocation, bool>> AnyRemoteEncounter()
{
if (_configuration.Mode == EMode.Offline)
return o => true;
else
// keep downloaded markers
return o => o.Source != ClientLocation.ESource.Download;
}
}
}

View File

@ -31,9 +31,9 @@ namespace Pal.Client.Database
public List<ImportHistory> ImportedBy { get; set; } = new();
/// <summary>
/// Whether this location was originally imported.
/// Determines where this location is originally from.
/// </summary>
public bool Imported { get; set; }
public ESource Source { get; set; }
/// <summary>
@ -46,5 +46,14 @@ namespace Pal.Client.Database
Trap = 1,
Hoard = 2,
}
public enum ESource
{
Unknown = 0,
SeenLocally = 1,
ExplodedLocally = 2,
Import = 3,
Download = 4,
}
}
}

View File

@ -0,0 +1,148 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Pal.Client.Database;
#nullable disable
namespace Pal.Client.Database.Migrations
{
[DbContext(typeof(PalClientContext))]
[Migration("20230222191929_ChangeLocationImportedToSource")]
partial class ChangeLocationImportedToSource
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.3");
modelBuilder.Entity("ClientLocationImportHistory", b =>
{
b.Property<Guid>("ImportedById")
.HasColumnType("TEXT");
b.Property<int>("ImportedLocationsLocalId")
.HasColumnType("INTEGER");
b.HasKey("ImportedById", "ImportedLocationsLocalId");
b.HasIndex("ImportedLocationsLocalId");
b.ToTable("LocationImports", (string)null);
});
modelBuilder.Entity("Pal.Client.Database.ClientLocation", b =>
{
b.Property<int>("LocalId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Seen")
.HasColumnType("INTEGER");
b.Property<string>("SinceVersion")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Source")
.HasColumnType("INTEGER");
b.Property<ushort>("TerritoryType")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.Property<float>("X")
.HasColumnType("REAL");
b.Property<float>("Y")
.HasColumnType("REAL");
b.Property<float>("Z")
.HasColumnType("REAL");
b.HasKey("LocalId");
b.ToTable("Locations");
});
modelBuilder.Entity("Pal.Client.Database.ImportHistory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTime>("ExportedAt")
.HasColumnType("TEXT");
b.Property<DateTime>("ImportedAt")
.HasColumnType("TEXT");
b.Property<string>("RemoteUrl")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Imports");
});
modelBuilder.Entity("Pal.Client.Database.RemoteEncounter", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AccountId")
.IsRequired()
.HasMaxLength(13)
.HasColumnType("TEXT");
b.Property<int>("ClientLocationId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ClientLocationId");
b.ToTable("RemoteEncounters");
});
modelBuilder.Entity("ClientLocationImportHistory", b =>
{
b.HasOne("Pal.Client.Database.ImportHistory", null)
.WithMany()
.HasForeignKey("ImportedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Pal.Client.Database.ClientLocation", null)
.WithMany()
.HasForeignKey("ImportedLocationsLocalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Pal.Client.Database.RemoteEncounter", b =>
{
b.HasOne("Pal.Client.Database.ClientLocation", "ClientLocation")
.WithMany("RemoteEncounters")
.HasForeignKey("ClientLocationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ClientLocation");
});
modelBuilder.Entity("Pal.Client.Database.ClientLocation", b =>
{
b.Navigation("RemoteEncounters");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Pal.Client.Database.Migrations
{
/// <inheritdoc />
public partial class ChangeLocationImportedToSource : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "Imported",
table: "Locations",
newName: "Source");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "Source",
table: "Locations",
newName: "Imported");
}
}
}

View File

@ -38,9 +38,6 @@ namespace Pal.Client.Database.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Imported")
.HasColumnType("INTEGER");
b.Property<bool>("Seen")
.HasColumnType("INTEGER");
@ -48,6 +45,9 @@ namespace Pal.Client.Database.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Source")
.HasColumnType("INTEGER");
b.Property<ushort>("TerritoryType")
.HasColumnType("INTEGER");

View File

@ -14,6 +14,7 @@ using ImGuiNET;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
using Pal.Client.Database;
using Pal.Client.Extensions;
using Pal.Client.Floors;
using Pal.Client.Net;
@ -390,7 +391,8 @@ namespace Pal.Client.DependencyInjection
{
Type = MemoryLocation.EType.Trap,
Position = obj.Position,
Seen = true
Seen = true,
Source = ClientLocation.ESource.SeenLocally,
});
break;
@ -400,7 +402,8 @@ namespace Pal.Client.DependencyInjection
{
Type = MemoryLocation.EType.Hoard,
Position = obj.Position,
Seen = true
Seen = true,
Source = ClientLocation.ESource.SeenLocally,
});
break;
@ -409,7 +412,7 @@ namespace Pal.Client.DependencyInjection
{
Type = MemoryLocation.EType.SilverCoffer,
Position = obj.Position,
Seen = true
Seen = true,
});
break;
}
@ -425,6 +428,8 @@ namespace Pal.Client.DependencyInjection
Type = MemoryLocation.EType.Trap,
Position = obj.Position,
Seen = true,
Source = ClientLocation.ESource.ExplodedLocally,
});
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Account;
@ -17,94 +18,149 @@ namespace Pal.Client.DependencyInjection
{
private readonly IServiceProvider _serviceProvider;
private readonly FloorService _floorService;
private readonly Cleanup _cleanup;
public ImportService(IServiceProvider serviceProvider, FloorService floorService)
public ImportService(
IServiceProvider serviceProvider,
FloorService floorService,
Cleanup cleanup)
{
_serviceProvider = serviceProvider;
_floorService = floorService;
_cleanup = cleanup;
}
/*
public void Add(ImportHistory history)
{
using var scope = _serviceProvider.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
dbContext.Imports.Add(history);
dbContext.SaveChanges();
}
*/
public async Task<ImportHistory?> FindLast(CancellationToken token = default)
{
await using var scope = _serviceProvider.CreateAsyncScope();
await using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
return await dbContext.Imports.OrderByDescending(x => x.ImportedAt).ThenBy(x => x.Id).FirstOrDefaultAsync(cancellationToken: token);
return await dbContext.Imports.OrderByDescending(x => x.ImportedAt).ThenBy(x => x.Id)
.FirstOrDefaultAsync(cancellationToken: token);
}
/*
public List<ImportHistory> FindForServer(string server)
{
if (string.IsNullOrEmpty(server))
return new();
using var scope = _serviceProvider.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
return dbContext.Imports.Where(x => x.RemoteUrl == server).ToList();
}*/
public (int traps, int hoard) Import(ExportRoot import)
{
using var scope = _serviceProvider.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
dbContext.Imports.RemoveRange(dbContext.Imports.Where(x => x.RemoteUrl == import.ServerUrl).ToList());
ImportHistory importHistory = new ImportHistory
try
{
Id = Guid.Parse(import.ExportId),
RemoteUrl = import.ServerUrl,
ExportedAt = import.CreatedAt.ToDateTime(),
ImportedAt = DateTime.UtcNow,
};
dbContext.Imports.Add(importHistory);
_floorService.SetToImportState();
int traps = 0;
int hoard = 0;
foreach (var floor in import.Floors)
{
ETerritoryType territoryType = (ETerritoryType)floor.TerritoryType;
using var scope = _serviceProvider.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
List<PersistentLocation> existingLocations = dbContext.Locations
.Where(loc => loc.TerritoryType == floor.TerritoryType)
.ToList()
.Select(LoadTerritory.ToMemoryLocation)
.ToList();
foreach (var newLocation in floor.Objects)
dbContext.Imports.RemoveRange(dbContext.Imports.Where(x => x.RemoteUrl == import.ServerUrl).ToList());
dbContext.SaveChanges();
ImportHistory importHistory = new ImportHistory
{
throw new NotImplementedException();
}
}
// TODO filter here, update territories
dbContext.SaveChanges();
Id = Guid.Parse(import.ExportId),
RemoteUrl = import.ServerUrl,
ExportedAt = import.CreatedAt.ToDateTime(),
ImportedAt = DateTime.UtcNow,
};
dbContext.Imports.Add(importHistory);
_floorService.ResetAll();
return (traps, hoard);
int traps = 0;
int hoard = 0;
foreach (var floor in import.Floors)
{
ETerritoryType territoryType = (ETerritoryType)floor.TerritoryType;
List<PersistentLocation> existingLocations = dbContext.Locations
.Where(loc => loc.TerritoryType == floor.TerritoryType)
.ToList()
.Select(LoadTerritory.ToMemoryLocation)
.ToList();
foreach (var exportLocation in floor.Objects)
{
PersistentLocation persistentLocation = new PersistentLocation
{
Type = ToMemoryType(exportLocation.Type),
Position = new Vector3(exportLocation.X, exportLocation.Y, exportLocation.Z),
Source = ClientLocation.ESource.Unknown,
};
var existingLocation = existingLocations.FirstOrDefault(x => x == persistentLocation);
if (existingLocation != null)
{
var clientLoc = dbContext.Locations.FirstOrDefault(o => o.LocalId == existingLocation.LocalId);
clientLoc?.ImportedBy.Add(importHistory);
continue;
}
ClientLocation clientLocation = new ClientLocation
{
TerritoryType = (ushort)territoryType,
Type = ToClientLocationType(exportLocation.Type),
X = exportLocation.X,
Y = exportLocation.Y,
Z = exportLocation.Z,
Seen = false,
Source = ClientLocation.ESource.Import,
ImportedBy = new List<ImportHistory> { importHistory },
SinceVersion = typeof(Plugin).Assembly.GetName().Version!.ToString(2),
};
dbContext.Locations.Add(clientLocation);
if (exportLocation.Type == ExportObjectType.Trap)
traps++;
else if (exportLocation.Type == ExportObjectType.Hoard)
hoard++;
}
}
dbContext.SaveChanges();
_cleanup.Purge(dbContext);
dbContext.SaveChanges();
return (traps, hoard);
}
finally
{
_floorService.ResetAll();
}
}
private MemoryLocation.EType ToMemoryType(ExportObjectType exportLocationType)
{
return exportLocationType switch
{
ExportObjectType.Trap => MemoryLocation.EType.Trap,
ExportObjectType.Hoard => MemoryLocation.EType.Hoard,
_ => throw new ArgumentOutOfRangeException(nameof(exportLocationType), exportLocationType, null)
};
}
private ClientLocation.EType ToClientLocationType(ExportObjectType exportLocationType)
{
return exportLocationType switch
{
ExportObjectType.Trap => ClientLocation.EType.Trap,
ExportObjectType.Hoard => ClientLocation.EType.Hoard,
_ => throw new ArgumentOutOfRangeException(nameof(exportLocationType), exportLocationType, null)
};
}
public void RemoveById(Guid id)
{
using var scope = _serviceProvider.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
try
{
_floorService.SetToImportState();
using var scope = _serviceProvider.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
dbContext.RemoveRange(dbContext.Imports.Where(x => x.Id == id));
dbContext.RemoveRange(dbContext.Imports.Where(x => x.Id == id));
dbContext.SaveChanges();
// TODO filter here, update territories
dbContext.SaveChanges();
_floorService.ResetAll();
_cleanup.Purge(dbContext);
dbContext.SaveChanges();
}
finally
{
_floorService.ResetAll();
}
}
}
}

View File

@ -96,6 +96,7 @@ namespace Pal.Client
$"Data Source={Path.Join(pluginInterface.GetPluginConfigDirectory(), "palace-pal.data.sqlite3")}";
services.AddDbContext<PalClientContext>(o => o.UseSqlite(_sqliteConnectionString));
services.AddTransient<JsonMigration>();
services.AddScoped<Cleanup>();
// plugin-specific
services.AddScoped<DependencyInjectionLoader>();

View File

@ -55,7 +55,9 @@ namespace Pal.Client
cancellationToken.ThrowIfCancellationRequested();
await RunMigrations(cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await RunCleanup(_logger);
cancellationToken.ThrowIfCancellationRequested();
// v1 migration: config migration for import history, json migration for markers
@ -174,18 +176,28 @@ namespace Pal.Client
private async Task RunMigrations(CancellationToken cancellationToken)
{
// initialize database
await using (var scope = _serviceProvider.CreateAsyncScope())
{
_logger.LogInformation("Loading database & running migrations");
await using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
await using var scope = _serviceProvider.CreateAsyncScope();
// takes 2-3 seconds with initializing connections, loading driver etc.
await dbContext.Database.MigrateAsync(cancellationToken);
_logger.LogInformation("Completed database migrations");
}
_logger.LogInformation("Loading database & running migrations");
await using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
// takes 2-3 seconds with initializing connections, loading driver etc.
await dbContext.Database.MigrateAsync(cancellationToken);
_logger.LogInformation("Completed database migrations");
}
private async Task RunCleanup(ILogger<DependencyInjectionLoader> logger)
{
await using var scope = _serviceProvider.CreateAsyncScope();
await using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
var cleanup = scope.ServiceProvider.GetRequiredService<Cleanup>();
cleanup.Purge(dbContext);
await dbContext.SaveChangesAsync();
}
public enum ELoadState
{
Initializing,

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Pal.Client.Configuration;
using Pal.Client.Database;
using Pal.Client.Extensions;
using Pal.Client.Floors.Tasks;
using Pal.Client.Net;
@ -14,19 +15,23 @@ namespace Pal.Client.Floors
internal sealed class FloorService
{
private readonly IPalacePalConfiguration _configuration;
private readonly Cleanup _cleanup;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IReadOnlyDictionary<ETerritoryType, MemoryTerritory> _territories;
private ConcurrentBag<EphemeralLocation> _ephemeralLocations = new();
public FloorService(IPalacePalConfiguration configuration, IServiceScopeFactory serviceScopeFactory)
public FloorService(IPalacePalConfiguration configuration, Cleanup cleanup,
IServiceScopeFactory serviceScopeFactory)
{
_configuration = configuration;
_cleanup = cleanup;
_serviceScopeFactory = serviceScopeFactory;
_territories = Enum.GetValues<ETerritoryType>().ToDictionary(o => o, o => new MemoryTerritory(o));
}
public IReadOnlyCollection<EphemeralLocation> EphemeralLocations => _ephemeralLocations;
public bool IsImportRunning { get; private set; }
public void ChangeTerritory(ushort territoryType)
{
@ -39,10 +44,10 @@ namespace Pal.Client.Floors
private void ChangeTerritory(ETerritoryType newTerritory)
{
var territory = _territories[newTerritory];
if (!territory.IsReady && !territory.IsLoading)
if (territory.ReadyState == MemoryTerritory.EReadyState.NotLoaded)
{
territory.IsLoading = true;
new LoadTerritory(_serviceScopeFactory, territory).Start();
territory.ReadyState = MemoryTerritory.EReadyState.Loading;
new LoadTerritory(_serviceScopeFactory, _cleanup, territory).Start();
}
}
@ -57,7 +62,7 @@ namespace Pal.Client.Floors
public MemoryTerritory? GetTerritoryIfReady(ETerritoryType territoryType)
{
var territory = _territories[territoryType];
if (!territory.IsReady)
if (territory.ReadyState != MemoryTerritory.EReadyState.Ready)
return null;
return territory;
@ -137,11 +142,22 @@ namespace Pal.Client.Floors
public void ResetAll()
{
IsImportRunning = false;
foreach (var memoryTerritory in _territories.Values)
{
lock (memoryTerritory.LockObj)
memoryTerritory.Reset();
}
}
public void SetToImportState()
{
IsImportRunning = true;
foreach (var memoryTerritory in _territories.Values)
{
lock (memoryTerritory.LockObj)
memoryTerritory.ReadyState = MemoryTerritory.EReadyState.Importing;
}
}
}
}

View File

@ -18,8 +18,7 @@ namespace Pal.Client.Floors
}
public ETerritoryType TerritoryType { get; }
public bool IsReady { get; set; }
public bool IsLoading { get; set; } // probably merge this with IsReady as enum
public EReadyState ReadyState { get; set; } = EReadyState.NotLoaded;
public ESyncState SyncState { get; set; } = ESyncState.NotAttempted;
public ConcurrentBag<PersistentLocation> Locations { get; } = new();
@ -31,21 +30,34 @@ namespace Pal.Client.Floors
foreach (var location in locations)
Locations.Add(location);
IsReady = true;
IsLoading = false;
}
public IEnumerable<PersistentLocation> GetRemovableLocations(EMode mode)
{
// TODO there was better logic here;
return Locations.Where(x => !x.Seen);
ReadyState = EReadyState.Ready;
}
public void Reset()
{
Locations.Clear();
IsReady = false;
IsLoading = false;
SyncState = ESyncState.NotAttempted;
ReadyState = EReadyState.NotLoaded;
}
public enum EReadyState
{
NotLoaded,
/// <summary>
/// Currently loading from the database.
/// </summary>
Loading,
/// <summary>
/// Locations loaded, no import running.
/// </summary>
Ready,
/// <summary>
/// Import running, should probably not interact with this too much.
/// </summary>
Importing,
}
}
}

View File

@ -31,6 +31,8 @@ namespace Pal.Client.Floors
/// </summary>
public bool RemoteSeenRequested { get; set; }
public ClientLocation.ESource Source { get; init; }
public override bool Equals(object? obj) => obj is PersistentLocation && base.Equals(obj);
public override int GetHashCode() => base.GetHashCode();

View File

@ -1,5 +1,4 @@
using System;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Database;

View File

@ -11,11 +11,15 @@ namespace Pal.Client.Floors.Tasks
{
internal sealed class LoadTerritory : DbTask<LoadTerritory>
{
private readonly Cleanup _cleanup;
private readonly MemoryTerritory _territory;
public LoadTerritory(IServiceScopeFactory serviceScopeFactory, MemoryTerritory territory)
public LoadTerritory(IServiceScopeFactory serviceScopeFactory,
Cleanup cleanup,
MemoryTerritory territory)
: base(serviceScopeFactory)
{
_cleanup = cleanup;
_territory = territory;
}
@ -23,13 +27,19 @@ namespace Pal.Client.Floors.Tasks
{
lock (_territory.LockObj)
{
if (_territory.IsReady)
if (_territory.ReadyState != MemoryTerritory.EReadyState.Loading)
{
logger.LogInformation("Territory {Territory} is already loaded", _territory.TerritoryType);
logger.LogInformation("Territory {Territory} is in state {State}", _territory.TerritoryType,
_territory.ReadyState);
return;
}
logger.LogInformation("Loading territory {Territory}", _territory.TerritoryType);
// purge outdated locations
_cleanup.Purge(dbContext, _territory.TerritoryType);
// load good locations
List<ClientLocation> locations = dbContext.Locations
.Where(o => o.TerritoryType == (ushort)_territory.TerritoryType)
.Include(o => o.ImportedBy)
@ -51,6 +61,7 @@ namespace Pal.Client.Floors.Tasks
Type = ToMemoryLocationType(location.Type),
Position = new Vector3(location.X, location.Y, location.Z),
Seen = location.Seen,
Source = location.Source,
RemoteSeenOn = location.RemoteEncounters.Select(o => o.AccountId).ToList(),
};
}

View File

@ -59,6 +59,7 @@ namespace Pal.Client.Floors.Tasks
Y = location.Position.Y,
Z = location.Position.Z,
Seen = location.Seen,
Source = location.Source,
SinceVersion = typeof(Plugin).Assembly.GetName().Version!.ToString(2),
};
}

View File

@ -5,6 +5,7 @@ using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Pal.Client.Database;
using Pal.Client.Floors;
namespace Pal.Client.Net
@ -69,6 +70,7 @@ namespace Pal.Client.Net
Type = obj.Type.ToMemoryType(),
Position = new Vector3(obj.X, obj.Y, obj.Z),
NetworkId = Guid.Parse(obj.NetworkId),
Source = ClientLocation.ESource.Download,
};
}

View File

@ -13,7 +13,7 @@ namespace Pal.Client.Net
#if DEBUG
public const string RemoteUrl = "http://localhost:5415";
#else
//public const string RemoteUrl = "https://pal.liza.sh";
public const string RemoteUrl = "http://localhost:5415";
#endif
private readonly string _userAgent =
$"{typeof(RemoteApi).Assembly.GetName().Name?.Replace(" ", "")}/{typeof(RemoteApi).Assembly.GetName().Version?.ToString(2)}";

View File

@ -2,11 +2,11 @@
using Pal.Common;
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Database;
using Pal.Client.DependencyInjection;
using Pal.Client.Floors;
using Pal.Client.Properties;
using Pal.Client.Windows;
@ -55,20 +55,31 @@ namespace Pal.Client.Scheduled
if (!Validate(import))
return;
using (var scope = _serviceScopeFactory.CreateScope())
Task.Run(() =>
{
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
(import.ImportedTraps, import.ImportedHoardCoffers) = _importService.Import(import.Export);
}
try
{
using (var scope = _serviceScopeFactory.CreateScope())
{
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
(import.ImportedTraps, import.ImportedHoardCoffers) =
_importService.Import(import.Export);
}
_configWindow.UpdateLastImport();
_configWindow.UpdateLastImport();
_logger.LogInformation(
"Imported {ExportId} for {Traps} traps, {Hoard} hoard coffers", import.ExportId,
import.ImportedTraps, import.ImportedHoardCoffers);
_chat.Message(string.Format(Localization.ImportCompleteStatistics, import.ImportedTraps,
import.ImportedHoardCoffers));
_logger.LogInformation(
"Imported {ExportId} for {Traps} traps, {Hoard} hoard coffers", import.ExportId,
import.ImportedTraps, import.ImportedHoardCoffers);
_chat.Message(string.Format(Localization.ImportCompleteStatistics, import.ImportedTraps,
import.ImportedHoardCoffers));
}
catch (Exception e)
{
_logger.LogError(e, "Import failed in inner task");
_chat.Error(string.Format(Localization.Error_ImportFailed, e));
}
});
}
catch (Exception e)
{

View File

@ -284,7 +284,7 @@ namespace Pal.Client.Windows
null; // only use this once, FileDialogManager will save path between calls
}
ImGui.BeginDisabled(string.IsNullOrEmpty(_openImportPath) || !File.Exists(_openImportPath));
ImGui.BeginDisabled(string.IsNullOrEmpty(_openImportPath) || !File.Exists(_openImportPath) || _floorService.IsImportRunning);
if (ImGui.Button(Localization.Config_StartImport))
DoImport(_openImportPath);
ImGui.EndDisabled();
@ -298,8 +298,11 @@ namespace Pal.Client.Windows
importHistory.RemoteUrl,
importHistory.ExportedAt.ToUniversalTime()));
ImGui.TextWrapped(Localization.Config_UndoImportExplanation2);
ImGui.BeginDisabled(_floorService.IsImportRunning);
if (ImGui.Button(Localization.Config_UndoImport))
UndoImport(importHistory.Id);
ImGui.EndDisabled();
}
ImGui.EndTabItem();

View File

@ -1,7 +1,10 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
namespace Pal.Common
{
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ETerritoryType : ushort
{
Palace_1_10 = 561,