Compare commits

...

47 Commits
v4.0 ... master

Author SHA1 Message Date
d239a6e4b0
API 10 2024-07-06 13:26:39 +02:00
9d5e4a797b
Update Dockerfile 2024-07-06 13:20:17 +02:00
3e2f917c14
API 10 2024-07-06 13:14:59 +02:00
2fdf9b1e4d
Remove GitInfo dependency 2024-01-16 11:41:13 +01:00
18ffd66086
Update icon URL 2024-01-16 07:03:56 +01:00
64e576a004
Render: Ensure RenderElement is null if we don't recreate it 2023-11-30 14:01:59 +01:00
0d1882d97f
Render: Performance fix 2023-11-26 22:14:04 +01:00
964119cfd2
Render: Use enabled instead of color for showing/hiding elements 2023-11-26 20:13:17 +01:00
309edfcd17
Bump version/recompile 2023-11-14 20:21:40 +01:00
8fbd3fbc0d
Update docker build 2023-11-11 01:56:09 +01:00
ce9be45e8f
Update docker build 2023-11-11 01:54:43 +01:00
8def5e28a4
Update dependencies 2023-11-11 01:41:15 +01:00
ba06576c2d
Update dependencies 2023-11-11 01:39:17 +01:00
f259f03534
Update server submodule structure 2023-11-11 01:39:10 +01:00
cf3a24afe8
Update header icon logic for Dalamud changes 2023-11-09 11:32:32 +01:00
2a180345eb
Update submodule URL 2023-10-14 00:02:21 +02:00
345c9c59a3
Add LLib, remove outdated info, add config window constraints 2023-10-11 03:56:18 +02:00
5c4e9f30e0
API 9 2023-10-03 22:05:19 +02:00
d337413b82 Update docker-build.sh 2023-10-03 17:54:53 +00:00
5a5d7fecfd
Change nuget lib path 2023-10-03 11:10:43 +02:00
1ee86d378f
API 9 2023-10-03 11:08:38 +02:00
cd52192d15
Setup server/test submodules 2023-09-17 22:28:37 +02:00
6260f35b61 Update repo location 2023-07-31 02:58:24 +02:00
79ad7fbc39 Update README 2023-07-30 23:53:47 +02:00
1bdcc7179c Update image location 2023-07-30 23:26:15 +02:00
5ba18477b4 Update repo url 2023-07-30 23:22:33 +02:00
5f506bda8a Update server url 2023-07-30 22:32:39 +02:00
bbec57c3ad Update actions 2023-07-30 21:49:14 +02:00
58404b9728 Fix floor change regex (for pomanders)
Not sure how or why that even broke, the string doesn't seem to have changed in the LogMessage sheet.

Fixes #18.
2023-04-13 09:17:06 +02:00
8042aee951 Use file-scoped namespaces 2023-03-30 22:02:51 +02:00
0b07e8b8f6 Code cleanup 2023-03-27 20:00:30 +02:00
7e73430179 Add palace service tests, remove standalone client 2023-03-27 18:02:18 +02:00
cec3597629 Update dependencies 2023-03-26 15:57:50 +02:00
ae29eaa52f Update ECommons 2023-03-26 15:49:52 +02:00
b81ced33e8 Code style tweaks 2023-03-26 15:47:43 +02:00
87806397d1 Configure GHA caching 2023-03-26 14:26:12 +02:00
d645aa9ea7 Configure GHA dotnet test timeout 2023-03-26 13:55:30 +02:00
4288440e6c Add export tests 2023-03-26 03:11:01 +02:00
36b328c29e Add simple account test 2023-03-25 19:14:32 +01:00
232ab164be Update DE localization 2023-03-25 02:47:21 +01:00
a4890c0159 Fix duplicate seen location errors 2023-03-25 02:39:54 +01:00
7bdf97411c Hide occasional FileLoadException (temporary error) 2023-03-11 01:50:26 +01:00
3e9f14419c Update gRPC packages 2023-03-10 03:08:44 +01:00
a21e9335aa GHA: Add workflow_dispatch to docker build 2023-03-10 02:44:04 +01:00
1b415d7a7f Improve repo exception handling 2023-03-08 01:27:10 +01:00
c5acb2ca54 Eureka Orthos: Add owlet trap to pomander of sight 2023-03-07 23:28:58 +01:00
7a514fad2a Add debug feature for object table 2023-03-07 21:55:50 +01:00
99 changed files with 5482 additions and 5091 deletions

View File

@ -4,4 +4,6 @@
.gitignore
Dockerfile
.dockerignore
docker-build.sh
.vs/
.idea/

31
.editorconfig Normal file
View File

@ -0,0 +1,31 @@
root = true
[*]
indent_style = space
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[{*.cs}]
charset = utf-8-bom
indent_size = 4
dotnet_sort_system_directives_first = true
csharp_style_implicit_object_creation_when_type_is_apparent = true
csharp_trailing_comma_in_multiline_lists = true
csharp_place_simple_embedded_block_on_same_line = false
csharp_place_attribute_on_same_line = false
resharper_indent_text = ZeroIndent
# methods
csharp_style_expression_bodied_methods = true
# namespaces
csharp_style_namespace_declarations = file_scoped
# braces
csharp_prefer_braces = when_multiline
[{*.resx,*.Designer.cs,packages.lock.json}]
generated_code = true
ij_formatter_enabled = false

View File

@ -1,32 +0,0 @@
name: dotnet build
on:
push:
paths-ignore:
- '**.md'
- 'Dockerfile'
jobs:
build:
runs-on: windows-latest
env:
DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0
- name: Download Dalamud
run: |
Invoke-WebRequest -Uri https://goatcorp.github.io/dalamud-distrib/latest.zip -OutFile latest.zip
Expand-Archive -Force latest.zip "$env:AppData\XIVLauncher\addon\Hooks\dev\"
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore

View File

@ -1,30 +0,0 @@
name: docker build
on:
push:
branches:
- master
paths:
- '.github/workflows/server.yml'
- 'Pal.Common/**'
- 'Pal.Server/**'
- 'Dockerfile'
permissions:
packages: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to GitHub Package Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
push: true
tags: ghcr.io/${{ github.repository_owner }}/palace-pal:latest

View File

@ -1,24 +0,0 @@
name: Upload to Crowdin
on:
push:
branches:
- master
paths:
- 'Pal.Client/Properties/*.resx'
- 'crowdin.yml'
workflow_dispatch: {}
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Crowdin Action
uses: crowdin/github-action@1.4.9
with:
upload_sources: true
upload_translations: true
download_translations: false
crowdin_branch_name: ${{ github.ref_name }}
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

6
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "vendor/ECommons"]
path = vendor/ECommons
url = https://github.com/NightmareXIV/ECommons
[submodule "vendor/LLib"]
path = vendor/LLib
url = https://git.carvel.li/liza/LLib.git
[submodule "Server"]
path = Server
url = https://git.carvel.li/liza/PalacePal.Server.git

View File

@ -5,6 +5,6 @@
</PropertyGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(SignToolPath)' != '' And Exists('$(SolutionDir)codesigning.pfx')">
<Exec Command="&quot;$(SignToolPath)signtool.exe&quot; sign /f $(SolutionDir)codesigning.pfx /t http://timestamp.digicert.com /fd SHA256 &quot;$(TargetPath)&quot;" />
<Exec Command="&quot;$(SignToolPath)signtool.exe&quot; sign /f $(SolutionDir)codesigning.pfx /t http://timestamp.digicert.com /fd SHA256 &quot;$(TargetPath)&quot;"/>
</Target>
</Project>

View File

@ -1,13 +1,19 @@
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
ARG TARGETARCH
WORKDIR /build
COPY Pal.Common/Pal.Common.csproj Pal.Common/
COPY Pal.Server/Pal.Server.csproj Pal.Server/
RUN dotnet restore Pal.Server/Pal.Server.csproj
COPY Server/Server/Pal.Server.csproj Server/Server/
RUN dotnet restore Server/Server/Pal.Server.csproj -a $TARGETARCH
COPY . ./
RUN dotnet publish Pal.Server/Pal.Server.csproj --configuration Release --no-restore -o /dist
RUN dotnet publish Server/Server/Pal.Server.csproj -a $TARGETARCH --no-restore -o /dist
FROM mcr.microsoft.com/dotnet/aspnet:8.0
# fix later
ENV DOTNET_ROLL_FORWARD=Major
ENV DOTNET_ROLL_FORWARD_PRE_RELEASE=1
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
EXPOSE 5415
ENV DOTNET_ENVIRONMENT=Production
ENV ASPNETCORE_URLS=

View File

@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
namespace Pal.Client.Commands
namespace Pal.Client.Commands;
public interface ISubCommand
{
public interface ISubCommand
{
IReadOnlyDictionary<string, Action<string>> GetHandlers();
}
}

View File

@ -3,10 +3,10 @@ using System.Collections.Generic;
using Pal.Client.Configuration;
using Pal.Client.Windows;
namespace Pal.Client.Commands
namespace Pal.Client.Commands;
internal class PalConfigCommand : ISubCommand
{
internal class PalConfigCommand : ISubCommand
{
private readonly IPalacePalConfiguration _configuration;
private readonly AgreementWindow _agreementWindow;
private readonly ConfigWindow _configWindow;
@ -36,5 +36,4 @@ namespace Pal.Client.Commands
else
_configWindow.Toggle();
}
}
}

View File

@ -1,22 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dalamud.Game.ClientState;
using Dalamud.Plugin.Services;
using Pal.Client.DependencyInjection;
using Pal.Client.Extensions;
using Pal.Client.Floors;
using Pal.Client.Rendering;
namespace Pal.Client.Commands
namespace Pal.Client.Commands;
internal sealed class PalNearCommand : ISubCommand
{
internal sealed class PalNearCommand : ISubCommand
{
private readonly Chat _chat;
private readonly ClientState _clientState;
private readonly IClientState _clientState;
private readonly TerritoryState _territoryState;
private readonly FloorService _floorService;
public PalNearCommand(Chat chat, ClientState clientState, TerritoryState territoryState,
public PalNearCommand(Chat chat, IClientState clientState, TerritoryState territoryState,
FloorService floorService)
{
_chat = chat;
@ -50,7 +50,7 @@ namespace Pal.Client.Commands
var nearbyMarkers = state.Locations
.Where(m => predicate(m))
.Where(m => m.RenderElement != null && m.RenderElement.Color != RenderData.ColorInvisible)
.Where(m => m.RenderElement != null && m.RenderElement.Enabled)
.Select(m => new { m, distance = (playerPosition.Value - m.Position).Length() })
.OrderBy(m => m.distance)
.Take(5)
@ -59,5 +59,4 @@ namespace Pal.Client.Commands
_chat.UnformattedMessage(
$"{nearbyMarker.distance:F2} - {nearbyMarker.m.Type} {nearbyMarker.m.NetworkId?.ToPartialId(length: 8)} - {nearbyMarker.m.Position}");
}
}
}

View File

@ -2,10 +2,10 @@
using System.Collections.Generic;
using Pal.Client.DependencyInjection;
namespace Pal.Client.Commands
namespace Pal.Client.Commands;
internal sealed class PalStatsCommand : ISubCommand
{
internal sealed class PalStatsCommand : ISubCommand
{
private readonly StatisticsService _statisticsService;
public PalStatsCommand(StatisticsService statisticsService)
@ -21,5 +21,4 @@ namespace Pal.Client.Commands
private void Execute()
=> _statisticsService.ShowGlobalStatistics();
}
}

View File

@ -3,10 +3,10 @@ using System.Collections.Generic;
using ECommons.Schedulers;
using Pal.Client.Windows;
namespace Pal.Client.Commands
namespace Pal.Client.Commands;
internal sealed class PalTestConnectionCommand : ISubCommand
{
internal sealed class PalTestConnectionCommand : ISubCommand
{
private readonly ConfigWindow _configWindow;
public PalTestConnectionCommand(ConfigWindow configWindow)
@ -26,5 +26,4 @@ namespace Pal.Client.Commands
_configWindow.IsOpen = true;
var _ = new TickScheduler(() => _configWindow.TestConnection());
}
}
}

View File

@ -4,14 +4,11 @@ using System.Security.Cryptography;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
namespace Pal.Client.Configuration
{
public sealed class AccountConfigurationV7 : IAccountConfiguration
{
private const int DefaultEntropyLength = 16;
namespace Pal.Client.Configuration;
private static readonly ILogger _logger =
DependencyInjectionContext.LoggerProvider.CreateLogger<AccountConfigurationV7>();
public sealed class AccountConfigurationV7 : IAccountConfiguration
{
private const int DefaultEntropyLength = 16;
[JsonConstructor]
public AccountConfigurationV7()
@ -75,9 +72,8 @@ namespace Pal.Client.Configuration
byte[] guidBytes = ProtectedData.Unprotect(Convert.FromBase64String(EncryptedId), Entropy, DataProtectionScope.CurrentUser);
return new Guid(guidBytes);
}
catch (Exception e)
catch (Exception)
{
_logger.LogTrace(e, "Could not load account id {Id}", EncryptedId);
return null;
}
}
@ -145,5 +141,4 @@ namespace Pal.Client.Configuration
/// </summary>
ProtectedDataUnsupported = 3,
}
}
}

View File

@ -3,19 +3,17 @@ using System.Linq;
using System.Security.Cryptography;
using Microsoft.Extensions.Logging;
namespace Pal.Client.Configuration
{
internal static class ConfigurationData
{
private static readonly ILogger _logger =
DependencyInjectionContext.LoggerProvider.CreateLogger(typeof(ConfigurationData));
namespace Pal.Client.Configuration;
internal static class ConfigurationData
{
[Obsolete("for V1 import")]
internal static readonly byte[] FixedV1Entropy = { 0x22, 0x4b, 0xe7, 0x21, 0x44, 0x83, 0x69, 0x55, 0x80, 0x38 };
public const string ConfigFileName = "palace-pal.config.json";
private static bool? _supportsDpapi = null;
private static bool? _supportsDpapi;
public static bool SupportsDpapi
{
get
@ -34,11 +32,9 @@ namespace Pal.Client.Configuration
{
_supportsDpapi = false;
}
_logger.LogTrace("DPAPI support: {Supported}", _supportsDpapi);
}
return _supportsDpapi.Value;
}
}
}
}

View File

@ -13,17 +13,17 @@ using Pal.Client.Configuration.Legacy;
using Pal.Client.Database;
using NJson = Newtonsoft.Json;
namespace Pal.Client.Configuration
namespace Pal.Client.Configuration;
internal sealed class ConfigurationManager
{
internal sealed class ConfigurationManager
{
private readonly ILogger<ConfigurationManager> _logger;
private readonly DalamudPluginInterface _pluginInterface;
private readonly IDalamudPluginInterface _pluginInterface;
private readonly IServiceProvider _serviceProvider;
public event EventHandler<IPalacePalConfiguration>? Saved;
public ConfigurationManager(ILogger<ConfigurationManager> logger, DalamudPluginInterface pluginInterface,
public ConfigurationManager(ILogger<ConfigurationManager> logger, IDalamudPluginInterface pluginInterface,
IServiceProvider serviceProvider)
{
_logger = logger;
@ -87,7 +87,9 @@ namespace Pal.Client.Configuration
dbContext.Imports.Add(new ImportHistory
{
Id = importHistory.Id,
RemoteUrl = importHistory.RemoteUrl?.Replace(".μ.tv", ".liza.sh"),
RemoteUrl = importHistory.RemoteUrl
?.Replace(".μ.tv", ".liza.sh")
.Replace("pal.liza.sh", "connect.palacepal.com"),
ExportedAt = importHistory.ExportedAt,
ImportedAt = importHistory.ImportedAt
});
@ -98,6 +100,17 @@ namespace Pal.Client.Configuration
File.Move(_pluginInterface.ConfigFile.FullName, _pluginInterface.ConfigFile.FullName + ".old", true);
}
IPalacePalConfiguration? currentConfig = Load();
IAccountConfiguration? legacyAccount = currentConfig?.FindAccount("https://pal.liza.sh");
if (currentConfig != null && legacyAccount != null)
{
IAccountConfiguration newAccount = currentConfig.CreateAccount("https://connect.palacepal.com", legacyAccount.AccountId);
newAccount.CachedRoles = legacyAccount.CachedRoles;
currentConfig.RemoveAccount(legacyAccount.Server);
Save(currentConfig, false);
}
}
private ConfigurationV7 MigrateToV7(ConfigurationV1 v1)
@ -141,7 +154,9 @@ namespace Pal.Client.Configuration
if (string.IsNullOrEmpty(accountId))
continue;
string serverName = server.Replace(".μ.tv", ".liza.sh");
string serverName = server
.Replace(".μ.tv", ".liza.sh")
.Replace("pal.liza.sh", "connect.palacepal.com");
IAccountConfiguration newAccount = v7.CreateAccount(serverName, accountId);
newAccount.CachedRoles = oldAccount.CachedRoles.ToList();
}
@ -152,5 +167,4 @@ namespace Pal.Client.Configuration
}
#pragma warning restore CS0618
#pragma warning restore CS0612
}
}

View File

@ -2,10 +2,10 @@
using System.Collections.Generic;
using System.Linq;
namespace Pal.Client.Configuration
namespace Pal.Client.Configuration;
public sealed class ConfigurationV7 : IPalacePalConfiguration, IConfigurationInConfigDirectory
{
public sealed class ConfigurationV7 : IPalacePalConfiguration, IConfigurationInConfigDirectory
{
public int Version { get; set; } = 7;
public bool FirstUse { get; set; } = true;
@ -50,5 +50,4 @@ namespace Pal.Client.Configuration
var account = FindAccount(server);
return account == null || account.CachedRoles.Contains(role);
}
}
}

View File

@ -1,15 +1,14 @@
namespace Pal.Client.Configuration
namespace Pal.Client.Configuration;
public enum EMode
{
public enum EMode
{
/// <summary>
/// Fetches trap locations from remote server.
/// </summary>
Online = 1,
/// <summary>
/// Only shows traps found by yourself uisng a pomander of sight.
/// Only shows traps found by yourself using a pomander of sight.
/// </summary>
Offline = 2,
}
}

View File

@ -1,11 +1,10 @@
namespace Pal.Client.Configuration
namespace Pal.Client.Configuration;
public enum ERenderer
{
public enum ERenderer
{
/// <see cref="Rendering.SimpleRenderer"/>
Simple = 0,
/// <see cref="Rendering.SplatoonRenderer"/>
Splatoon = 1,
}
}

View File

@ -4,21 +4,22 @@ using System.Numerics;
using ImGuiNET;
using Newtonsoft.Json;
namespace Pal.Client.Configuration
{
public interface IVersioned
{
int Version { get; set; }
}
public interface IConfigurationInConfigDirectory : IVersioned
{
}
namespace Pal.Client.Configuration;
public interface IPalacePalConfiguration : IConfigurationInConfigDirectory
{
public interface IVersioned
{
int Version { get; set; }
}
public interface IConfigurationInConfigDirectory : IVersioned
{
}
public interface IPalacePalConfiguration : IConfigurationInConfigDirectory
{
bool FirstUse { get; set; }
EMode Mode { get; set; }
string BetaKey { get; }
bool HasBetaFeature(string feature) => BetaKey.Contains(feature);
DeepDungeonConfiguration DeepDungeons { get; set; }
RendererConfiguration Renderer { get; set; }
@ -29,10 +30,10 @@ namespace Pal.Client.Configuration
void RemoveAccount(string server);
bool HasRoleOnCurrentServer(string server, string role);
}
}
public class DeepDungeonConfiguration
{
public class DeepDungeonConfiguration
{
public MarkerConfiguration Traps { get; set; } = new()
{
Show = true,
@ -64,10 +65,10 @@ namespace Pal.Client.Configuration
OnlyVisibleAfterPomander = false,
Fill = true
};
}
}
public class MarkerConfiguration
{
public class MarkerConfiguration
{
[JsonRequired]
public bool Show { get; set; }
@ -76,15 +77,15 @@ namespace Pal.Client.Configuration
public bool OnlyVisibleAfterPomander { get; set; }
public bool Fill { get; set; }
}
}
public class RendererConfiguration
{
public class RendererConfiguration
{
public ERenderer SelectedRenderer { get; set; } = ERenderer.Splatoon;
}
}
public interface IAccountConfiguration
{
public interface IAccountConfiguration
{
bool IsUsable { get; }
string Server { get; }
Guid AccountId { get; }
@ -100,11 +101,10 @@ namespace Pal.Client.Configuration
List<string> CachedRoles { get; set; }
bool EncryptIfNeeded();
}
}
public class BackupConfiguration
{
public class BackupConfiguration
{
public int MinimumBackupsToKeep { get; set; } = 3;
public int DaysToDeleteAfter { get; set; } = 21;
}
}

View File

@ -8,11 +8,11 @@ using Dalamud.Plugin;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Pal.Client.Configuration.Legacy
namespace Pal.Client.Configuration.Legacy;
[Obsolete]
public sealed class ConfigurationV1
{
[Obsolete]
public sealed class ConfigurationV1
{
public int Version { get; set; } = 6;
#region Saved configuration values
@ -50,7 +50,7 @@ namespace Pal.Client.Configuration.Legacy
public string BetaKey { get; set; } = "";
#endregion
public void Migrate(DalamudPluginInterface pluginInterface, ILogger<ConfigurationV1> logger)
public void Migrate(IDalamudPluginInterface pluginInterface, ILogger<ConfigurationV1> logger)
{
if (Version == 1)
{
@ -137,7 +137,7 @@ namespace Pal.Client.Configuration.Legacy
}
}
public void Save(DalamudPluginInterface pluginInterface)
public void Save(IDalamudPluginInterface pluginInterface)
{
File.WriteAllText(pluginInterface.ConfigFile.FullName, JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings
{
@ -163,5 +163,4 @@ namespace Pal.Client.Configuration.Legacy
/// </summary>
public DateTime ImportedAt { get; set; }
}
}
}

View File

@ -7,19 +7,18 @@ using System.Text.Json;
using Pal.Client.Extensions;
using Pal.Common;
namespace Pal.Client.Configuration.Legacy
namespace Pal.Client.Configuration.Legacy;
/// <summary>
/// Legacy JSON file for marker locations.
/// </summary>
[Obsolete]
public sealed class JsonFloorState
{
/// <summary>
/// Legacy JSON file for marker locations.
/// </summary>
[Obsolete]
public sealed class JsonFloorState
{
private static readonly JsonSerializerOptions JsonSerializerOptions = new() { IncludeFields = true };
private const int CurrentVersion = 4;
private static string _pluginConfigDirectory = null!;
private static readonly EMode _mode = EMode.Online; // might not be true, but this is 'less strict filtering' for migrations
internal static void SetContextProperties(string pluginConfigDirectory)
{
@ -36,11 +35,6 @@ namespace Pal.Client.Configuration.Legacy
private void ApplyFilters()
{
if (_mode == EMode.Offline)
Markers = new ConcurrentBag<JsonMarker>(Markers.Where(x => x.Seen || (x.WasImported && x.Imports.Count > 0)));
else
// ensure old import markers are removed if they are no longer part of a "current" import
// this MAY remove markers the server sent you (and that you haven't seen), but this should be fixed the next time you enter the zone
Markers = new ConcurrentBag<JsonMarker>(Markers.Where(x => x.Seen || !x.WasImported || x.Imports.Count > 0));
}
@ -164,5 +158,4 @@ namespace Pal.Client.Configuration.Legacy
public int Version { get; set; }
public HashSet<JsonMarker> Markers { get; set; } = new();
}
}
}

View File

@ -2,11 +2,11 @@
using System.Collections.Generic;
using System.Numerics;
namespace Pal.Client.Configuration.Legacy
namespace Pal.Client.Configuration.Legacy;
[Obsolete]
public class JsonMarker
{
[Obsolete]
public class JsonMarker
{
public EType Type { get; set; } = EType.Unknown;
public Vector3 Position { get; set; }
public bool Seen { get; set; }
@ -22,5 +22,4 @@ namespace Pal.Client.Configuration.Legacy
Hoard = 2,
Debug = 3,
}
}
}

View File

@ -12,19 +12,19 @@ using Microsoft.Extensions.Logging;
using Pal.Client.Database;
using Pal.Common;
namespace Pal.Client.Configuration.Legacy
namespace Pal.Client.Configuration.Legacy;
/// <summary>
/// Imports legacy territoryType.json files into the database if it exists, and no markers for that territory exist.
/// </summary>
internal sealed class JsonMigration
{
/// <summary>
/// Imports legacy territoryType.json files into the database if it exists, and no markers for that territory exist.
/// </summary>
internal sealed class JsonMigration
{
private readonly ILogger<JsonMigration> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly DalamudPluginInterface _pluginInterface;
private readonly IDalamudPluginInterface _pluginInterface;
public JsonMigration(ILogger<JsonMigration> logger, IServiceScopeFactory serviceScopeFactory,
DalamudPluginInterface pluginInterface)
IDalamudPluginInterface pluginInterface)
{
_logger = logger;
_serviceScopeFactory = serviceScopeFactory;
@ -143,5 +143,4 @@ namespace Pal.Client.Configuration.Legacy
};
}
#pragma warning restore CS0612
}
}

View File

@ -6,10 +6,10 @@ using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
using Pal.Common;
namespace Pal.Client.Database
namespace Pal.Client.Database;
internal sealed class Cleanup
{
internal sealed class Cleanup
{
private readonly ILogger<Cleanup> _logger;
private readonly IPalacePalConfiguration _configuration;
@ -63,5 +63,4 @@ namespace Pal.Client.Database
// keep downloaded markers
return o => o.Source != ClientLocation.ESource.Download;
}
}
}

View File

@ -1,10 +1,10 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Pal.Client.Database
namespace Pal.Client.Database;
internal sealed class ClientLocation
{
internal sealed class ClientLocation
{
[Key] public int LocalId { get; set; }
public ushort TerritoryType { get; set; }
public EType Type { get; set; }
@ -55,5 +55,4 @@ namespace Pal.Client.Database
Import = 3,
Download = 4,
}
}
}

View File

@ -1,15 +1,14 @@
using System;
using System.Collections.Generic;
namespace Pal.Client.Database
namespace Pal.Client.Database;
internal sealed class ImportHistory
{
internal sealed class ImportHistory
{
public Guid Id { get; set; }
public string? RemoteUrl { get; set; }
public DateTime ExportedAt { get; set; }
public DateTime ImportedAt { get; set; }
public List<ClientLocation> ImportedLocations { get; set; } = new();
}
}

View File

@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore;
namespace Pal.Client.Database
namespace Pal.Client.Database;
internal class PalClientContext : DbContext
{
internal class PalClientContext : DbContext
{
public DbSet<ClientLocation> Locations { get; set; } = null!;
public DbSet<ImportHistory> Imports { get; set; } = null!;
public DbSet<RemoteEncounter> RemoteEncounters { get; set; } = null!;
@ -20,5 +20,4 @@ namespace Pal.Client.Database
.WithMany(o => o.ImportedLocations)
.UsingEntity(o => o.ToTable("LocationImports"));
}
}
}

View File

@ -2,17 +2,17 @@
using Pal.Client.Extensions;
using Pal.Client.Net;
namespace Pal.Client.Database
namespace Pal.Client.Database;
/// <summary>
/// To avoid sending too many requests to the server, we cache which locations have been seen
/// locally. These never expire, and locations which have been seen with a specific account
/// are never sent to the server again.
///
/// To be marked as seen, it needs to be essentially processed by <see cref="RemoteApi.MarkAsSeen"/>.
/// </summary>
internal sealed class RemoteEncounter
{
/// <summary>
/// To avoid sending too many requests to the server, we cache which locations have been seen
/// locally. These never expire, and locations which have been seen with a specific account
/// are never sent to the server again.
///
/// To be marked as seen, it needs to be essentially processed by <see cref="RemoteApi.MarkAsSeen"/>.
/// </summary>
internal sealed class RemoteEncounter
{
[Key]
public int Id { get; private set; }
@ -37,5 +37,4 @@ namespace Pal.Client.Database
ClientLocation = clientLocation;
AccountId = accountId.ToPartialId();
}
}
}

View File

@ -19,14 +19,14 @@ using Pal.Client.DependencyInjection;
using Pal.Client.Floors;
using Pal.Client.Windows;
namespace Pal.Client
namespace Pal.Client;
/// <summary>
/// Takes care of async plugin init - this is mostly everything that requires either the config or the database to
/// be available.
/// </summary>
internal sealed class DependencyContextInitializer
{
/// <summary>
/// Takes care of async plugin init - this is mostly everything that requires either the config or the database to
/// be available.
/// </summary>
internal sealed class DependencyContextInitializer
{
private readonly ILogger<DependencyContextInitializer> _logger;
private readonly IServiceProvider _serviceProvider;
@ -73,13 +73,18 @@ namespace Pal.Client
cancellationToken.ThrowIfCancellationRequested();
if (_serviceProvider.GetRequiredService<IPalacePalConfiguration>().HasBetaFeature(ObjectTableDebug.FeatureName))
_serviceProvider.GetRequiredService<ObjectTableDebug>();
cancellationToken.ThrowIfCancellationRequested();
_logger.LogInformation("Async init complete");
}
private async Task RemoveOldBackups()
{
await using var scope = _serviceProvider.CreateAsyncScope();
var pluginInterface = scope.ServiceProvider.GetRequiredService<DalamudPluginInterface>();
var pluginInterface = scope.ServiceProvider.GetRequiredService<IDalamudPluginInterface>();
var configuration = scope.ServiceProvider.GetRequiredService<IPalacePalConfiguration>();
var paths = Directory.GetFiles(pluginInterface.GetPluginConfigDirectory(), "backup-*.data.sqlite3",
@ -131,7 +136,7 @@ namespace Pal.Client
{
await using var scope = _serviceProvider.CreateAsyncScope();
var pluginInterface = scope.ServiceProvider.GetRequiredService<DalamudPluginInterface>();
var pluginInterface = scope.ServiceProvider.GetRequiredService<IDalamudPluginInterface>();
string backupPath = Path.Join(pluginInterface.GetPluginConfigDirectory(),
$"backup-{DateTime.Now.ToUniversalTime():yyyy-MM-dd}.data.sqlite3");
string sourcePath = Path.Join(pluginInterface.GetPluginConfigDirectory(),
@ -187,5 +192,4 @@ namespace Pal.Client
await dbContext.SaveChangesAsync();
}
}
}

View File

@ -1,15 +1,16 @@
using Dalamud.Game.Gui;
using Dalamud.Game.Text;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
using ECommons.DalamudServices.Legacy;
using Pal.Client.Properties;
namespace Pal.Client.DependencyInjection
{
internal sealed class Chat
{
private readonly ChatGui _chatGui;
namespace Pal.Client.DependencyInjection;
public Chat(ChatGui chatGui)
internal sealed class Chat
{
private readonly IChatGui _chatGui;
public Chat(IChatGui chatGui)
{
_chatGui = chatGui;
}
@ -34,5 +35,4 @@ namespace Pal.Client.DependencyInjection
public void UnformattedMessage(string message)
=> _chatGui.Print(message);
}
}

View File

@ -1,25 +1,25 @@
using System;
using System.Text;
using System.Text.RegularExpressions;
using Dalamud.Data;
using Dalamud.Game.Gui;
using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Plugin.Services;
using Lumina.Excel.GeneratedSheets;
using Pal.Client.Configuration;
using Pal.Client.Floors;
namespace Pal.Client.DependencyInjection
namespace Pal.Client.DependencyInjection;
internal sealed class ChatService : IDisposable
{
internal sealed class ChatService : IDisposable
{
private readonly ChatGui _chatGui;
private readonly IChatGui _chatGui;
private readonly TerritoryState _territoryState;
private readonly IPalacePalConfiguration _configuration;
private readonly DataManager _dataManager;
private readonly IDataManager _dataManager;
private readonly LocalizedChatMessages _localizedChatMessages;
public ChatService(ChatGui chatGui, TerritoryState territoryState, IPalacePalConfiguration configuration,
DataManager dataManager)
public ChatService(IChatGui chatGui, TerritoryState territoryState, IPalacePalConfiguration configuration,
IDataManager dataManager)
{
_chatGui = chatGui;
_territoryState = territoryState;
@ -34,7 +34,7 @@ namespace Pal.Client.DependencyInjection
public void Dispose()
=> _chatGui.ChatMessage -= OnChatMessage;
private void OnChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString seMessage,
private void OnChatMessage(XivChatType type, int senderId, ref SeString sender, ref SeString seMessage,
ref bool isHandled)
{
if (_configuration.FirstUse)
@ -82,14 +82,21 @@ namespace Pal.Client.DependencyInjection
HoardNotOnCurrentFloor = GetLocalizedString(7273),
HoardCofferOpened = GetLocalizedString(7274),
FloorChanged =
new Regex("^" + GetLocalizedString(7270).Replace("\u0002 \u0003\ufffd\u0002\u0003", @"(\d+)") +
new Regex("^" + GetLocalizedString(7270, true).Replace("\u0002 \u0003\ufffd\u0002\u0003", @"(\d+)") +
"$"),
};
}
private string GetLocalizedString(uint id)
private string GetLocalizedString(uint id, bool asRawData = false)
{
return _dataManager.GetExcelSheet<LogMessage>()?.GetRow(id)?.Text?.ToString() ?? "Unknown";
var text = _dataManager.GetExcelSheet<LogMessage>()?.GetRow(id)?.Text;
if (text == null)
return "Unknown";
if (asRawData)
return Encoding.UTF8.GetString(text.RawData);
else
return text.ToString();
}
private sealed class LocalizedChatMessages
@ -106,5 +113,4 @@ namespace Pal.Client.DependencyInjection
public Regex FloorChanged { get; init; } =
new(@"This isn't a game message, but will be replaced"); // new Regex(@"^Floor (\d+)$");
}
}
}

View File

@ -1,9 +1,9 @@
using System;
namespace Pal.Client.DependencyInjection
namespace Pal.Client.DependencyInjection;
internal sealed class DebugState
{
internal sealed class DebugState
{
public string? DebugMessage { get; set; }
public void SetFromException(Exception e)
@ -11,5 +11,4 @@ namespace Pal.Client.DependencyInjection
public void Reset()
=> DebugMessage = null;
}
}

View File

@ -4,16 +4,17 @@ using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Hooking;
using Dalamud.Memory;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using Microsoft.Extensions.Logging;
using Pal.Client.Floors;
namespace Pal.Client.DependencyInjection
namespace Pal.Client.DependencyInjection;
internal sealed unsafe class GameHooks : IDisposable
{
internal sealed unsafe class GameHooks : IDisposable
{
private readonly ILogger<GameHooks> _logger;
private readonly ObjectTable _objectTable;
private readonly IObjectTable _objectTable;
private readonly TerritoryState _territoryState;
private readonly FrameworkService _frameworkService;
@ -24,7 +25,7 @@ namespace Pal.Client.DependencyInjection
private Hook<ActorVfxCreateDelegate> ActorVfxCreateHook { get; init; } = null!;
#pragma warning restore CS0649
public GameHooks(ILogger<GameHooks> logger, ObjectTable objectTable, TerritoryState territoryState, FrameworkService frameworkService)
public GameHooks(ILogger<GameHooks> logger, IObjectTable objectTable, TerritoryState territoryState, FrameworkService frameworkService, IGameInteropProvider gameInteropProvider)
{
_logger = logger;
_objectTable = objectTable;
@ -32,7 +33,7 @@ namespace Pal.Client.DependencyInjection
_frameworkService = frameworkService;
_logger.LogDebug("Initializing game hooks");
SignatureHelper.Initialise(this);
gameInteropProvider.InitializeFromAttributes(this);
ActorVfxCreateHook.Enable();
_logger.LogDebug("Game hooks initialized");
@ -80,7 +81,7 @@ namespace Pal.Client.DependencyInjection
_chat.PalPrint($"{vfxPath} on {obj}");
*/
if (obj is BattleChara bc && (bc.NameId == /* potd */ 5042 || bc.NameId == /* hoh */ 7395))
if (obj is IBattleChara bc && (bc.NameId == /* potd */ 5042 || bc.NameId == /* hoh */ 7395))
{
if (vfxPath == "vfx/common/eff/dk05th_stdn0t.avfx" || vfxPath == "vfx/common/eff/dk05ht_ipws0t.avfx")
{
@ -102,5 +103,4 @@ namespace Pal.Client.DependencyInjection
_logger.LogDebug("Disposing game hooks");
ActorVfxCreateHook.Dispose();
}
}
}

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Account;
using Export;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Pal.Client.Database;
@ -12,10 +12,10 @@ using Pal.Client.Floors;
using Pal.Client.Floors.Tasks;
using Pal.Common;
namespace Pal.Client.DependencyInjection
namespace Pal.Client.DependencyInjection;
internal sealed class ImportService
{
internal sealed class ImportService
{
private readonly IServiceProvider _serviceProvider;
private readonly FloorService _floorService;
private readonly Cleanup _cleanup;
@ -162,5 +162,4 @@ namespace Pal.Client.DependencyInjection
_floorService.ResetAll();
}
}
}
}

View File

@ -6,21 +6,22 @@ using Microsoft.Extensions.Logging;
using Pal.Client.Extensions;
using Pal.Client.Properties;
namespace Pal.Client.DependencyInjection
namespace Pal.Client.DependencyInjection;
internal sealed class RepoVerification
{
internal sealed class RepoVerification
{
public RepoVerification(ILogger<RepoVerification> logger, DalamudPluginInterface pluginInterface, Chat chat)
public RepoVerification(ILogger<RepoVerification> logger, IDalamudPluginInterface pluginInterface, Chat chat)
{
logger.LogInformation("Install source: {Repo}", pluginInterface.SourceRepository);
if (!pluginInterface.IsDev
&& !pluginInterface.SourceRepository.StartsWith("https://raw.githubusercontent.com/carvelli/")
&& !pluginInterface.SourceRepository.StartsWith("https://github.com/carvelli/"))
if (!pluginInterface.IsDev && pluginInterface.SourceRepository.TrimEnd('/') != "https://plugins.carvel.li")
{
chat.Error(string.Format(Localization.Error_WrongRepository,
"https://github.com/carvelli/Dalamud-Plugins"));
throw new InvalidOperationException();
"https://plugins.carvel.li"));
throw new RepoVerificationFailedException();
}
}
internal sealed class RepoVerificationFailedException : Exception
{
}
}

View File

@ -9,10 +9,10 @@ using Pal.Client.Net;
using Pal.Client.Properties;
using Pal.Client.Windows;
namespace Pal.Client.DependencyInjection
namespace Pal.Client.DependencyInjection;
internal sealed class StatisticsService
{
internal sealed class StatisticsService
{
private readonly IPalacePalConfiguration _configuration;
private readonly ILogger<StatisticsService> _logger;
private readonly RemoteApi _remoteApi;
@ -71,5 +71,4 @@ namespace Pal.Client.DependencyInjection
$"{e.GetType()} - {e.Message}"));
}
}
}
}

View File

@ -10,6 +10,7 @@ using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
@ -25,37 +26,40 @@ using Pal.Client.Rendering;
using Pal.Client.Scheduled;
using Pal.Client.Windows;
namespace Pal.Client
namespace Pal.Client;
/// <summary>
/// DI-aware Plugin.
/// </summary>
internal sealed class DependencyInjectionContext : IDisposable
{
/// <summary>
/// DI-aware Plugin.
/// </summary>
internal sealed class DependencyInjectionContext : IDisposable
{
public const string DatabaseFileName = "palace-pal.data.sqlite3";
public static DalamudLoggerProvider LoggerProvider { get; } = new(typeof(Plugin).Assembly);
/// <summary>
/// Initialized as temporary logger, will be overriden once context is ready with a logger that supports scopes.
/// </summary>
private ILogger _logger = LoggerProvider.CreateLogger<DependencyInjectionContext>();
private ILogger _logger;
private readonly string _sqliteConnectionString;
private readonly ServiceCollection _serviceCollection = new();
private ServiceProvider? _serviceProvider;
public DependencyInjectionContext(
DalamudPluginInterface pluginInterface,
ClientState clientState,
GameGui gameGui,
ChatGui chatGui,
ObjectTable objectTable,
Framework framework,
Condition condition,
CommandManager commandManager,
DataManager dataManager,
IDalamudPluginInterface pluginInterface,
IClientState clientState,
IGameGui gameGui,
IChatGui chatGui,
IObjectTable objectTable,
IFramework framework,
ICondition condition,
ICommandManager commandManager,
IDataManager dataManager,
IGameInteropProvider gameInteropProvider,
IPluginLog pluginLog,
Plugin plugin)
{
var loggerProvider = new DalamudLoggerProvider(pluginLog);
_logger = loggerProvider.CreateLogger<DependencyInjectionContext>();
_logger.LogInformation("Building dalamud service container for {Assembly}",
typeof(DependencyInjectionContext).Assembly.FullName);
@ -70,7 +74,7 @@ namespace Pal.Client
.AddFilter("Microsoft.EntityFrameworkCore.Database", LogLevel.Warning)
.AddFilter("Grpc", LogLevel.Debug)
.ClearProviders()
.AddDalamudLogger(plugin));
.AddDalamudLogger(pluginLog));
// dalamud
_serviceCollection.AddSingleton<IDalamudPlugin>(plugin);
@ -84,6 +88,7 @@ namespace Pal.Client
_serviceCollection.AddSingleton(condition);
_serviceCollection.AddSingleton(commandManager);
_serviceCollection.AddSingleton(dataManager);
_serviceCollection.AddSingleton(gameInteropProvider);
_serviceCollection.AddSingleton(new WindowSystem(typeof(DependencyInjectionContext).AssemblyQualifiedName));
_sqliteConnectionString =
@ -125,6 +130,7 @@ namespace Pal.Client
_serviceCollection.AddScoped<ChatService>();
_serviceCollection.AddScoped<FloorService>();
_serviceCollection.AddScoped<ImportService>();
_serviceCollection.AddScoped<ObjectTableDebug>();
// windows & related services
_serviceCollection.AddScoped<AgreementWindow>();
@ -185,5 +191,4 @@ namespace Pal.Client
using (SqliteConnection sqliteConnection = new(_sqliteConnectionString))
SqliteConnection.ClearPool(sqliteConnection);
}
}
}

View File

@ -1,13 +1,12 @@
using System;
namespace Pal.Client.Extensions
namespace Pal.Client.Extensions;
public static class GuidExtensions
{
public static class GuidExtensions
{
public static string ToPartialId(this Guid g, int length = 13)
=> g.ToString().ToPartialId();
public static string ToPartialId(this string s, int length = 13)
=> s.PadRight(length + 1).Substring(0, length);
}
}

View File

@ -3,10 +3,10 @@ using System.Runtime.InteropServices;
using System.Text;
using ImGuiNET;
namespace Pal.Client.Extensions
namespace Pal.Client.Extensions;
internal static class PalImGui
{
internal static class PalImGui
{
/// <summary>
/// None of the default BeginTabItem methods allow using flags without making the tab have a close button for some reason.
/// </summary>
@ -32,5 +32,4 @@ namespace Pal.Client.Extensions
if (ImGui.IsItemClicked())
choice = value;
}
}
}

View File

@ -1,12 +1,12 @@
using System;
namespace Pal.Client.Floors
namespace Pal.Client.Floors;
/// <summary>
/// This is a currently-visible marker.
/// </summary>
internal sealed class EphemeralLocation : MemoryLocation
{
/// <summary>
/// This is a currently-visible marker.
/// </summary>
internal sealed class EphemeralLocation : MemoryLocation
{
public override bool Equals(object? obj) => obj is EphemeralLocation && base.Equals(obj);
public override int GetHashCode() => base.GetHashCode();
@ -25,5 +25,4 @@ namespace Pal.Client.Floors
{
return $"EphemeralLocation(Position={Position}, Type={Type})";
}
}
}

View File

@ -10,10 +10,10 @@ using Pal.Client.Floors.Tasks;
using Pal.Client.Net;
using Pal.Common;
namespace Pal.Client.Floors
namespace Pal.Client.Floors;
internal sealed class FloorService
{
internal sealed class FloorService
{
private readonly IPalacePalConfiguration _configuration;
private readonly Cleanup _cleanup;
private readonly IServiceScopeFactory _serviceScopeFactory;
@ -159,5 +159,4 @@ namespace Pal.Client.Floors
memoryTerritory.ReadyState = MemoryTerritory.EReadyState.Importing;
}
}
}
}

View File

@ -4,10 +4,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
@ -18,21 +16,21 @@ using Pal.Client.Rendering;
using Pal.Client.Scheduled;
using Pal.Common;
namespace Pal.Client.Floors
namespace Pal.Client.Floors;
internal sealed class FrameworkService : IDisposable
{
internal sealed class FrameworkService : IDisposable
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<FrameworkService> _logger;
private readonly Framework _framework;
private readonly IFramework _framework;
private readonly ConfigurationManager _configurationManager;
private readonly IPalacePalConfiguration _configuration;
private readonly ClientState _clientState;
private readonly IClientState _clientState;
private readonly TerritoryState _territoryState;
private readonly FloorService _floorService;
private readonly DebugState _debugState;
private readonly RenderAdapter _renderAdapter;
private readonly ObjectTable _objectTable;
private readonly IObjectTable _objectTable;
private readonly RemoteApi _remoteApi;
internal Queue<IQueueOnFrameworkThread> EarlyEventQueue { get; } = new();
@ -42,15 +40,15 @@ namespace Pal.Client.Floors
public FrameworkService(
IServiceProvider serviceProvider,
ILogger<FrameworkService> logger,
Framework framework,
IFramework framework,
ConfigurationManager configurationManager,
IPalacePalConfiguration configuration,
ClientState clientState,
IClientState clientState,
TerritoryState territoryState,
FloorService floorService,
DebugState debugState,
RenderAdapter renderAdapter,
ObjectTable objectTable,
IObjectTable objectTable,
RemoteApi remoteApi)
{
_serviceProvider = serviceProvider;
@ -79,7 +77,7 @@ namespace Pal.Client.Floors
private void OnSaved(object? sender, IPalacePalConfiguration? config)
=> EarlyEventQueue.Enqueue(new QueuedConfigUpdate());
private void OnUpdate(Framework framework)
private void OnUpdate(IFramework framework)
{
if (_configuration.FirstUse)
return;
@ -177,12 +175,20 @@ namespace Pal.Client.Floors
{
foreach (var location in memoryTerritory.Locations)
{
uint desiredColor = DetermineColor(location, visibleLocations);
if (location.RenderElement == null || !location.RenderElement.IsValid)
bool isEnabled = DetermineVisibility(location, visibleLocations);
if (location.RenderElement == null)
{
if (isEnabled)
return true;
else
continue;
}
if (!location.RenderElement.IsValid)
return true;
if (location.RenderElement.Color != desiredColor)
location.RenderElement.Color = desiredColor;
if (location.RenderElement.Enabled != isEnabled)
location.RenderElement.Enabled = isEnabled;
}
}
catch (Exception e)
@ -227,12 +233,12 @@ namespace Pal.Client.Floors
{
if (location.Type == MemoryLocation.EType.Trap)
{
CreateRenderElement(location, elements, DetermineColor(location, visibleMarkers),
CreateRenderElement(location, elements, DetermineVisibility(location, visibleMarkers),
_configuration.DeepDungeons.Traps);
}
else if (location.Type == MemoryLocation.EType.Hoard)
{
CreateRenderElement(location, elements, DetermineColor(location, visibleMarkers),
CreateRenderElement(location, elements, DetermineVisibility(location, visibleMarkers),
_configuration.DeepDungeons.HoardCoffers);
}
}
@ -253,14 +259,12 @@ namespace Pal.Client.Floors
if (location.Type == MemoryLocation.EType.SilverCoffer &&
_configuration.DeepDungeons.SilverCoffers.Show)
{
CreateRenderElement(location, elements, DetermineColor(location),
_configuration.DeepDungeons.SilverCoffers);
CreateRenderElement(location, elements, true, _configuration.DeepDungeons.SilverCoffers);
}
else if (location.Type == MemoryLocation.EType.GoldCoffer &&
_configuration.DeepDungeons.GoldCoffers.Show)
{
CreateRenderElement(location, elements, DetermineColor(location),
_configuration.DeepDungeons.GoldCoffers);
CreateRenderElement(location, elements, true, _configuration.DeepDungeons.GoldCoffers);
}
}
@ -270,7 +274,7 @@ namespace Pal.Client.Floors
_renderAdapter.SetLayer(ELayer.RegularCoffers, elements);
}
private uint DetermineColor(PersistentLocation location, IReadOnlyList<PersistentLocation> visibleLocations)
private bool DetermineVisibility(PersistentLocation location, IReadOnlyList<PersistentLocation> visibleLocations)
{
switch (location.Type)
{
@ -278,34 +282,28 @@ namespace Pal.Client.Floors
when _territoryState.PomanderOfSight == PomanderState.Inactive ||
!_configuration.DeepDungeons.Traps.OnlyVisibleAfterPomander ||
visibleLocations.Any(x => x == location):
return _configuration.DeepDungeons.Traps.Color;
return true;
case MemoryLocation.EType.Hoard
when _territoryState.PomanderOfIntuition == PomanderState.Inactive ||
!_configuration.DeepDungeons.HoardCoffers.OnlyVisibleAfterPomander ||
visibleLocations.Any(x => x == location):
return _configuration.DeepDungeons.HoardCoffers.Color;
return true;
default:
return RenderData.ColorInvisible;
return false;
}
}
private uint DetermineColor(EphemeralLocation location)
{
return location.Type switch
{
MemoryLocation.EType.SilverCoffer => _configuration.DeepDungeons.SilverCoffers.Color,
MemoryLocation.EType.GoldCoffer => _configuration.DeepDungeons.GoldCoffers.Color,
_ => RenderData.ColorInvisible
};
}
private void CreateRenderElement(MemoryLocation location, List<IRenderElement> elements, uint color,
private void CreateRenderElement(MemoryLocation location, List<IRenderElement> elements, bool enabled,
MarkerConfiguration config)
{
if (!config.Show)
{
location.RenderElement = null;
return;
}
var element = _renderAdapter.CreateElement(location.Type, location.Position, color, config.Fill);
var element =
_renderAdapter.CreateElement(location.Type, location.Position, enabled, config.Color, config.Fill);
location.RenderElement = element;
elements.Add(element);
}
@ -385,7 +383,7 @@ namespace Pal.Client.Floors
List<EphemeralLocation> ephemeralLocations = new();
for (int i = 246; i < _objectTable.Length; i++)
{
GameObject? obj = _objectTable[i];
IGameObject? obj = _objectTable[i];
if (obj == null)
continue;
@ -397,6 +395,7 @@ namespace Pal.Client.Floors
case 2007185:
case 2007186:
case 2009504:
case 2013284:
persistentLocations.Add(new PersistentLocation
{
Type = MemoryLocation.EType.Trap,
@ -448,7 +447,6 @@ namespace Pal.Client.Floors
Position = obj.Position,
Seen = true,
Source = ClientLocation.ESource.ExplodedLocally,
});
}
}
@ -463,5 +461,4 @@ namespace Pal.Client.Floors
handler.RunIfCompatible(queued, ref recreateLayout);
}
}
}

View File

@ -5,13 +5,13 @@ using Pal.Client.Rendering;
using Pal.Common;
using Palace;
namespace Pal.Client.Floors
namespace Pal.Client.Floors;
/// <summary>
/// Base class for <see cref="MemoryLocation"/> and <see cref="EphemeralLocation"/>.
/// </summary>
internal abstract class MemoryLocation
{
/// <summary>
/// Base class for <see cref="MemoryLocation"/> and <see cref="EphemeralLocation"/>.
/// </summary>
internal abstract class MemoryLocation
{
public required EType Type { get; init; }
public required Vector3 Position { get; init; }
public bool Seen { get; set; }
@ -40,10 +40,10 @@ namespace Pal.Client.Floors
{
return HashCode.Combine(Type, PalaceMath.GetHashCode(Position));
}
}
}
internal static class ETypeExtensions
{
internal static class ETypeExtensions
{
public static MemoryLocation.EType ToMemoryType(this ObjectType objectType)
{
return objectType switch
@ -63,5 +63,4 @@ namespace Pal.Client.Floors
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
}
}
}

View File

@ -5,13 +5,13 @@ using Pal.Client.Configuration;
using Pal.Client.Scheduled;
using Pal.Common;
namespace Pal.Client.Floors
namespace Pal.Client.Floors;
/// <summary>
/// A single set of floors loaded entirely in memory, can be e.g. POTD 51-60.
/// </summary>
internal sealed class MemoryTerritory
{
/// <summary>
/// A single set of floors loaded entirely in memory, can be e.g. POTD 51-60.
/// </summary>
internal sealed class MemoryTerritory
{
public MemoryTerritory(ETerritoryType territoryType)
{
TerritoryType = territoryType;
@ -59,5 +59,4 @@ namespace Pal.Client.Floors
/// </summary>
Importing,
}
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using ImGuiNET;
namespace Pal.Client.Floors;
/// <summary>
/// This isn't very useful for running deep dungeons normally, but it is for plugin dev.
///
/// Needs the corresponding beta feature to be enabled.
/// </summary>
internal sealed class ObjectTableDebug : IDisposable
{
public const string FeatureName = nameof(ObjectTableDebug);
private readonly IDalamudPluginInterface _pluginInterface;
private readonly IObjectTable _objectTable;
private readonly IGameGui _gameGui;
private readonly IClientState _clientState;
public ObjectTableDebug(IDalamudPluginInterface pluginInterface, IObjectTable objectTable, IGameGui gameGui,
IClientState clientState)
{
_pluginInterface = pluginInterface;
_objectTable = objectTable;
_gameGui = gameGui;
_clientState = clientState;
_pluginInterface.UiBuilder.Draw += Draw;
}
private void Draw()
{
int index = 0;
foreach (IGameObject obj in _objectTable)
{
if (obj is IEventObj eventObj && string.IsNullOrEmpty(eventObj.Name.ToString()))
{
++index;
int model = Marshal.ReadInt32(obj.Address + 128);
if (_gameGui.WorldToScreen(obj.Position, out var screenCoords))
{
// So, while WorldToScreen will return false if the point is off of game client screen, to
// to avoid performance issues, we have to manually determine if creating a window would
// produce a new viewport, and skip rendering it if so
float distance = DistanceToPlayer(obj.Position);
var objectText =
$"{obj.Address.ToInt64():X}:{obj.EntityId:X}[{index}]\nkind: {obj.ObjectKind} sub: {obj.SubKind}\nmodel: {model}\nname: {obj.Name}\ndata id: {obj.DataId}";
var screenPos = ImGui.GetMainViewport().Pos;
var screenSize = ImGui.GetMainViewport().Size;
var windowSize = ImGui.CalcTextSize(objectText);
// Add some extra safety padding
windowSize.X += ImGui.GetStyle().WindowPadding.X + 10;
windowSize.Y += ImGui.GetStyle().WindowPadding.Y + 10;
if (screenCoords.X + windowSize.X > screenPos.X + screenSize.X ||
screenCoords.Y + windowSize.Y > screenPos.Y + screenSize.Y)
continue;
if (distance > 50f)
continue;
ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y));
ImGui.SetNextWindowBgAlpha(Math.Max(1f - (distance / 50f), 0.2f));
if (ImGui.Begin(
$"PalacePal_{nameof(ObjectTableDebug)}_{index}",
ImGuiWindowFlags.NoDecoration |
ImGuiWindowFlags.AlwaysAutoResize |
ImGuiWindowFlags.NoSavedSettings |
ImGuiWindowFlags.NoMove |
ImGuiWindowFlags.NoMouseInputs |
ImGuiWindowFlags.NoDocking |
ImGuiWindowFlags.NoFocusOnAppearing |
ImGuiWindowFlags.NoNav))
ImGui.Text(objectText);
ImGui.End();
}
}
}
}
private float DistanceToPlayer(Vector3 center)
=> Vector3.Distance(_clientState.LocalPlayer?.Position ?? Vector3.Zero, center);
public void Dispose()
{
_pluginInterface.UiBuilder.Draw -= Draw;
}
}

View File

@ -2,13 +2,13 @@
using System.Collections.Generic;
using Pal.Client.Database;
namespace Pal.Client.Floors
namespace Pal.Client.Floors;
/// <summary>
/// A <see cref="ClientLocation"/> loaded in memory, with certain extra attributes as needed.
/// </summary>
internal sealed class PersistentLocation : MemoryLocation
{
/// <summary>
/// A <see cref="ClientLocation"/> loaded in memory, with certain extra attributes as needed.
/// </summary>
internal sealed class PersistentLocation : MemoryLocation
{
/// <see cref="ClientLocation.LocalId"/>
public int? LocalId { get; set; }
@ -51,5 +51,4 @@ namespace Pal.Client.Floors
{
return $"PersistentLocation(Position={Position}, Type={Type})";
}
}
}

View File

@ -4,11 +4,11 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Database;
namespace Pal.Client.Floors.Tasks
{
internal abstract class DbTask<T>
namespace Pal.Client.Floors.Tasks;
internal abstract class DbTask<T>
where T : DbTask<T>
{
{
private readonly IServiceScopeFactory _serviceScopeFactory;
protected DbTask(IServiceScopeFactory serviceScopeFactory)
@ -24,18 +24,23 @@ namespace Pal.Client.Floors.Tasks
{
using var scope = _serviceScopeFactory.CreateScope();
ILogger<T> logger = scope.ServiceProvider.GetRequiredService<ILogger<T>>();
try
{
using var dbContext = scope.ServiceProvider.GetRequiredService<PalClientContext>();
Run(dbContext, logger);
}
catch (Exception e)
{
DependencyInjectionContext.LoggerProvider.CreateLogger<DbTask<T>>()
.LogError(e, "Failed to run DbTask");
logger.LogError(e, "Failed to run DbTask");
}
}
catch (Exception)
{
// nothing we can do here but catch it, if we don't we crash the game
}
});
}
protected abstract void Run(PalClientContext dbContext, ILogger<T> logger);
}
}

View File

@ -7,10 +7,10 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Database;
namespace Pal.Client.Floors.Tasks
namespace Pal.Client.Floors.Tasks;
internal sealed class LoadTerritory : DbTask<LoadTerritory>
{
internal sealed class LoadTerritory : DbTask<LoadTerritory>
{
private readonly Cleanup _cleanup;
private readonly MemoryTerritory _territory;
@ -75,5 +75,4 @@ namespace Pal.Client.Floors.Tasks
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
}
}
}

View File

@ -5,10 +5,10 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Database;
namespace Pal.Client.Floors.Tasks
namespace Pal.Client.Floors.Tasks;
internal sealed class MarkLocalSeen : DbTask<MarkLocalSeen>
{
internal sealed class MarkLocalSeen : DbTask<MarkLocalSeen>
{
private readonly MemoryTerritory _territory;
private readonly IReadOnlyList<PersistentLocation> _locations;
@ -24,7 +24,8 @@ namespace Pal.Client.Floors.Tasks
{
lock (_territory.LockObj)
{
logger.LogInformation("Marking {Count} locations as seen locally in territory {Territory}", _locations.Count,
logger.LogInformation("Marking {Count} locations as seen locally in territory {Territory}",
_locations.Count,
_territory.TerritoryType);
List<int> localIds = _locations.Select(l => l.LocalId).Where(x => x != null).Cast<int>().ToList();
dbContext.Locations
@ -33,5 +34,4 @@ namespace Pal.Client.Floors.Tasks
dbContext.SaveChanges();
}
}
}
}

View File

@ -5,10 +5,10 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Database;
namespace Pal.Client.Floors.Tasks
namespace Pal.Client.Floors.Tasks;
internal sealed class MarkRemoteSeen : DbTask<MarkRemoteSeen>
{
internal sealed class MarkRemoteSeen : DbTask<MarkRemoteSeen>
{
private readonly MemoryTerritory _territory;
private readonly IReadOnlyList<PersistentLocation> _locations;
private readonly string _accountId;
@ -47,5 +47,4 @@ namespace Pal.Client.Floors.Tasks
dbContext.SaveChanges();
}
}
}
}

View File

@ -6,10 +6,10 @@ using Microsoft.Extensions.Logging;
using Pal.Client.Database;
using Pal.Common;
namespace Pal.Client.Floors.Tasks
namespace Pal.Client.Floors.Tasks;
internal sealed class SaveNewLocations : DbTask<SaveNewLocations>
{
internal sealed class SaveNewLocations : DbTask<SaveNewLocations>
{
private readonly MemoryTerritory _territory;
private readonly List<PersistentLocation> _newLocations;
@ -73,5 +73,4 @@ namespace Pal.Client.Floors.Tasks
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
}
}
}

View File

@ -1,15 +1,15 @@
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Plugin.Services;
using Pal.Common;
namespace Pal.Client.Floors
{
public sealed class TerritoryState
{
private readonly ClientState _clientState;
private readonly Condition _condition;
namespace Pal.Client.Floors;
public TerritoryState(ClientState clientState, Condition condition)
public sealed class TerritoryState
{
private readonly IClientState _clientState;
private readonly ICondition _condition;
public TerritoryState(IClientState clientState, ICondition condition)
{
_clientState = clientState;
_condition = condition;
@ -23,14 +23,12 @@ namespace Pal.Client.Floors
_clientState.IsLoggedIn
&& _condition[ConditionFlag.InDeepDungeon]
&& typeof(ETerritoryType).IsEnumDefined(_clientState.TerritoryType);
}
}
public enum PomanderState
{
public enum PomanderState
{
Inactive,
Active,
FoundOnCurrentFloor,
PomanderOfSafetyUsed,
}
}

View File

@ -4,10 +4,9 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pal.Client
namespace Pal.Client;
internal interface ILanguageChanged
{
internal interface ILanguageChanged
{
void LanguageChanged();
}
}

View File

@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
using System.Text.Json.Serialization;
namespace Pal.Client.Net
namespace Pal.Client.Net;
internal sealed class JwtClaims
{
internal sealed class JwtClaims
{
[JsonPropertyName("nameid")]
public Guid NameId { get; set; }
@ -42,12 +40,13 @@ namespace Pal.Client.Net
payload += "=";
string content = Encoding.UTF8.GetString(Convert.FromBase64String(payload));
return JsonSerializer.Deserialize<JwtClaims>(content) ?? throw new InvalidOperationException("token deserialization returned null");
}
return JsonSerializer.Deserialize<JwtClaims>(content) ??
throw new InvalidOperationException("token deserialization returned null");
}
}
internal sealed class JwtRoleConverter : JsonConverter<List<string>>
{
internal sealed class JwtRoleConverter : JsonConverter<List<string>>
{
public override List<string> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
@ -75,21 +74,6 @@ namespace Pal.Client.Net
throw new JsonException("bad token type");
}
public override void Write(Utf8JsonWriter writer, List<string> value, JsonSerializerOptions options) => throw new NotImplementedException();
}
public sealed class JwtDateConverter : JsonConverter<DateTimeOffset>
{
static readonly DateTimeOffset Zero = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.Number)
throw new JsonException("bad token type");
return Zero.AddSeconds(reader.GetInt64());
}
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) => throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, List<string> value, JsonSerializerOptions options) =>
throw new NotImplementedException();
}

View File

@ -0,0 +1,21 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Pal.Client.Net;
public sealed class JwtDateConverter : JsonConverter<DateTimeOffset>
{
static readonly DateTimeOffset Zero = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.Number)
throw new JsonException("bad token type");
return Zero.AddSeconds(reader.GetInt64());
}
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) =>
throw new NotImplementedException();
}

View File

@ -1,21 +1,23 @@
using Account;
using Grpc.Core;
using Grpc.Net.Client;
using Microsoft.Extensions.Logging;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Account;
using Grpc.Core;
using Grpc.Net.Client;
using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
using Pal.Client.Extensions;
using Pal.Client.Properties;
using Pal.Client.Configuration;
using Version = System.Version;
namespace Pal.Client.Net
namespace Pal.Client.Net;
internal partial class RemoteApi
{
internal partial class RemoteApi
{
private static readonly Version PluginVersion = typeof(Plugin).Assembly.GetName().Version!;
private readonly SemaphoreSlim _connectLock = new(1, 1);
private async Task<(bool Success, string Error)> TryConnect(CancellationToken cancellationToken,
@ -73,7 +75,14 @@ namespace Pal.Client.Net
if (configuredAccount == null)
{
_logger.LogInformation("No account information saved for {Url}, creating new account", RemoteUrl);
var createAccountReply = await accountClient.CreateAccountAsync(new CreateAccountRequest(),
var createAccountReply = await accountClient.CreateAccountAsync(new CreateAccountRequest
{
Version = new()
{
Major = PluginVersion.Major,
Minor = PluginVersion.Minor,
},
},
headers: UnauthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10),
cancellationToken: cancellationToken);
if (createAccountReply.Success)
@ -115,7 +124,15 @@ namespace Pal.Client.Net
_logger.LogInformation("Logging in with account id {AccountId}",
configuredAccount.AccountId.ToPartialId());
LoginReply loginReply = await accountClient.LoginAsync(
new LoginRequest { AccountId = configuredAccount.AccountId.ToString() },
new LoginRequest
{
AccountId = configuredAccount.AccountId.ToString(),
Version = new()
{
Major = PluginVersion.Major,
Minor = PluginVersion.Minor,
},
},
headers: UnauthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10),
cancellationToken: cancellationToken);
@ -228,5 +245,4 @@ namespace Pal.Client.Net
public bool IsValid => IsLoggedIn && !IsExpired;
}
}
}

View File

@ -1,12 +1,12 @@
using Account;
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using Export;
namespace Pal.Client.Net
namespace Pal.Client.Net;
internal partial class RemoteApi
{
internal partial class RemoteApi
{
public async Task<(bool, ExportRoot)> DoExport(CancellationToken cancellationToken = default)
{
if (!await Connect(cancellationToken))
@ -16,8 +16,8 @@ namespace Pal.Client.Net
var exportReply = await exportClient.ExportAsync(new ExportRequest
{
ServerUrl = RemoteUrl,
}, headers: AuthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(120), cancellationToken: cancellationToken);
}, headers: AuthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(120),
cancellationToken: cancellationToken);
return (exportReply.Success, exportReply.Data);
}
}
}

View File

@ -1,5 +1,4 @@
using Palace;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
@ -7,22 +6,27 @@ using System.Threading;
using System.Threading.Tasks;
using Pal.Client.Database;
using Pal.Client.Floors;
using Palace;
namespace Pal.Client.Net
namespace Pal.Client.Net;
internal partial class RemoteApi
{
internal partial class RemoteApi
{
public async Task<(bool, List<PersistentLocation>)> DownloadRemoteMarkers(ushort territoryId, CancellationToken cancellationToken = default)
public async Task<(bool, List<PersistentLocation>)> DownloadRemoteMarkers(ushort territoryId,
CancellationToken cancellationToken = default)
{
if (!await Connect(cancellationToken))
return (false, new());
var palaceClient = new PalaceService.PalaceServiceClient(_channel);
var downloadReply = await palaceClient.DownloadFloorsAsync(new DownloadFloorsRequest { TerritoryType = territoryId }, headers: AuthorizedHeaders(), cancellationToken: cancellationToken);
var downloadReply = await palaceClient.DownloadFloorsAsync(
new DownloadFloorsRequest { TerritoryType = territoryId }, headers: AuthorizedHeaders(),
cancellationToken: cancellationToken);
return (downloadReply.Success, downloadReply.Objects.Select(CreateLocationFromNetworkObject).ToList());
}
public async Task<(bool, List<PersistentLocation>)> UploadLocations(ushort territoryType, IReadOnlyList<PersistentLocation> locations, CancellationToken cancellationToken = default)
public async Task<(bool, List<PersistentLocation>)> UploadLocations(ushort territoryType,
IReadOnlyList<PersistentLocation> locations, CancellationToken cancellationToken = default)
{
if (locations.Count == 0)
return (true, new());
@ -42,11 +46,13 @@ namespace Pal.Client.Net
Y = m.Position.Y,
Z = m.Position.Z
}));
var uploadReply = await palaceClient.UploadFloorsAsync(uploadRequest, headers: AuthorizedHeaders(), cancellationToken: cancellationToken);
var uploadReply = await palaceClient.UploadFloorsAsync(uploadRequest, headers: AuthorizedHeaders(),
cancellationToken: cancellationToken);
return (uploadReply.Success, uploadReply.Objects.Select(CreateLocationFromNetworkObject).ToList());
}
public async Task<bool> MarkAsSeen(ushort territoryType, IReadOnlyList<PersistentLocation> locations, CancellationToken cancellationToken = default)
public async Task<bool> MarkAsSeen(ushort territoryType, IReadOnlyList<PersistentLocation> locations,
CancellationToken cancellationToken = default)
{
if (locations.Count == 0)
return true;
@ -59,7 +65,8 @@ namespace Pal.Client.Net
foreach (var marker in locations)
seenRequest.NetworkIds.Add(marker.NetworkId.ToString());
var seenReply = await palaceClient.MarkObjectsSeenAsync(seenRequest, headers: AuthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
var seenReply = await palaceClient.MarkObjectsSeenAsync(seenRequest, headers: AuthorizedHeaders(),
deadline: DateTime.UtcNow.AddSeconds(10), cancellationToken: cancellationToken);
return seenReply.Success;
}
@ -80,8 +87,9 @@ namespace Pal.Client.Net
return new(false, new List<FloorStatistics>());
var palaceClient = new PalaceService.PalaceServiceClient(_channel);
var statisticsReply = await palaceClient.FetchStatisticsAsync(new StatisticsRequest(), headers: AuthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(30), cancellationToken: cancellationToken);
var statisticsReply = await palaceClient.FetchStatisticsAsync(new StatisticsRequest(),
headers: AuthorizedHeaders(), deadline: DateTime.UtcNow.AddSeconds(30),
cancellationToken: cancellationToken);
return (statisticsReply.Success, statisticsReply.FloorStatistics.ToList());
}
}
}

View File

@ -1,14 +1,14 @@
using System;
using Dalamud.Logging;
using Grpc.Core;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using Dalamud.Logging;
using Grpc.Core;
using Microsoft.Extensions.Logging;
namespace Pal.Client.Net
namespace Pal.Client.Net;
internal partial class RemoteApi
{
internal partial class RemoteApi
{
private Metadata UnauthorizedHeaders() => new()
{
{ "User-Agent", _userAgent },
@ -54,5 +54,4 @@ namespace Pal.Client.Net
return null;
#endif
}
}
}

View File

@ -1,19 +1,19 @@
using Dalamud.Logging;
using System;
using Dalamud.Game.Gui;
using Dalamud.Logging;
using Grpc.Net.Client;
using Microsoft.Extensions.Logging;
using System;
using Dalamud.Game.Gui;
using Pal.Client.Configuration;
using Pal.Client.DependencyInjection;
namespace Pal.Client.Net
namespace Pal.Client.Net;
internal sealed partial class RemoteApi : IDisposable
{
internal sealed partial class RemoteApi : IDisposable
{
#if DEBUG
public const string RemoteUrl = "http://localhost:5415";
#else
public const string RemoteUrl = "https://pal.liza.sh";
public const string RemoteUrl = "https://connect.palacepal.com";
#endif
private readonly string _userAgent =
$"{typeof(RemoteApi).Assembly.GetName().Name?.Replace(" ", "")}/{typeof(RemoteApi).Assembly.GetName().Version?.ToString(2)}";
@ -48,5 +48,4 @@ namespace Pal.Client.Net
_channel?.Dispose();
_channel = null;
}
}
}

View File

@ -1,106 +1,54 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Dalamud.NET.Sdk/9.0.2">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
<LangVersion>11.0</LangVersion>
<Nullable>enable</Nullable>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<PlatformTarget>x64</PlatformTarget>
<Version>6.0</Version>
<AssemblyName>Palace Pal</AssemblyName>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<PlatformTarget>x64</PlatformTarget>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>portable</DebugType>
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
<GitVersion>false</GitVersion>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
</PropertyGroup>
<Import Project="..\vendor\LLib\LLib.targets"/>
<Import Project="..\vendor\LLib\RenameZip.targets"/>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<OutputPath>dist</OutputPath>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release' And Exists('Certificate.pfx')">
<None Remove="Certificate.pfx" />
<None Remove="Certificate.pfx"/>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release' And Exists('Certificate.pfx')">
<EmbeddedResource Include="Certificate.pfx" />
<EmbeddedResource Include="Certificate.pfx"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.10" />
<PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="1.0.0" />
<PackageReference Include="Google.Protobuf" Version="3.21.12" />
<PackageReference Include="Grpc.Net.Client" Version="2.51.0" />
<PackageReference Include="GitInfo" Version="2.3.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Grpc.Tools" Version="2.51.0">
<PackageReference Include="Dalamud.Extensions.MicrosoftLogging" Version="4.0.1"/>
<PackageReference Include="Google.Protobuf" Version="3.27.2" />
<PackageReference Include="Grpc.Net.Client" Version="2.63.0"/>
<PackageReference Include="Grpc.Tools" Version="2.64.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.3">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.6" Condition="'$(Configuration)' == 'EF'">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0"/>
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Pal.Common\Pal.Common.csproj" />
<ProjectReference Include="..\vendor\ECommons\ECommons\ECommons.csproj" />
<ProjectReference Include="..\Pal.Common\Pal.Common.csproj"/>
<ProjectReference Include="..\vendor\ECommons\ECommons\ECommons.csproj"/>
<ProjectReference Include="..\vendor\LLib\LLib.csproj" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="..\Pal.Common\Protos\account.proto" Link="Protos\account.proto" GrpcServices="Client" Access="Internal" />
<Protobuf Include="..\Pal.Common\Protos\palace.proto" Link="Protos\palace.proto" GrpcServices="Client" Access="Internal" />
<Protobuf Include="..\Pal.Common\Protos\export.proto" Link="Protos\export.proto" GrpcServices="Client" Access="Internal" />
</ItemGroup>
<ItemGroup>
<!--You may need to adjust these paths yourself. These point to a Dalamud assembly in AppData.-->
<Reference Include="Dalamud">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Reference Include="ImGui.NET">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\ImGui.NET.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Reference Include="ImGuiScene">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\ImGuiScene.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Reference Include="Lumina">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Reference Include="Lumina.Excel">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Newtonsoft.Json.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Reference Include="FFXIVClientStructs">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\FFXIVClientStructs.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Reference Include="Serilog">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Serilog.dll</HintPath>
<Private Condition="'$(Configuration)' != 'EF'">false</Private>
</Reference>
<Protobuf Include="..\Pal.Common\Protos\account.proto" Link="Protos\account.proto" GrpcServices="Client" Access="Internal"/>
<Protobuf Include="..\Pal.Common\Protos\palace.proto" Link="Protos\palace.proto" GrpcServices="Client" Access="Internal"/>
<Protobuf Include="..\Pal.Common\Protos\export.proto" Link="Protos\export.proto" GrpcServices="Client" Access="Internal"/>
</ItemGroup>
<ItemGroup>
@ -115,18 +63,7 @@
</Compile>
</ItemGroup>
<Target Name="PopulateInfo" DependsOnTargets="GitVersion" BeforeTargets="GetAssemblyVersion;GenerateNuspec;GetPackageContents">
<PropertyGroup>
<Version>$(GitSemVerMajor).$(GitSemVerMinor)</Version>
<PackageVersion>$(Version)</PackageVersion>
</PropertyGroup>
</Target>
<Target Name="RenameLatestZip" AfterTargets="PackagePlugin" Condition="'$(Configuration)' == 'Release'">
<Exec Command="rename &quot;$(OutDir)$(AssemblyName)\latest.zip&quot; &quot;$(AssemblyName)-$(Version).zip&quot;" />
</Target>
<Target Name="Clean">
<RemoveDir Directories="dist" />
<RemoveDir Directories="dist"/>
</Target>
</Project>

View File

@ -3,7 +3,12 @@
"Author": "Liza Carvelli",
"Punchline": "Shows possible trap & hoard coffer locations in Palace of the Dead & Heaven on High.",
"Description": "Shows possible trap & hoard coffer locations in Palace of the Dead & Heaven on High.\n\nThe default configuration requires Splatoon to be installed. If you do not wish to install Splatoon, you can switch to the experimental 'Simple' renderer in the configuration.",
"RepoUrl": "https://github.com/carvelli/PalacePal",
"IconUrl": "https://raw.githubusercontent.com/carvelli/Dalamud-Plugins/master/dist/Palace Pal.png",
"Tags": [ "potd", "palace", "hoh", "splatoon" ]
"RepoUrl": "https://git.carvel.li/liza/PalacePal",
"IconUrl": "https://plugins.carvel.li/icons/PalacePal.png",
"Tags": [
"potd",
"palace",
"hoh",
"splatoon"
]
}

View File

@ -1,17 +1,15 @@
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Pal.Client.Rendering;
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Extensions.MicrosoftLogging;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Pal.Client.Properties;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using ECommons;
using ECommons.DalamudServices;
using Microsoft.Extensions.DependencyInjection;
@ -19,45 +17,49 @@ using Microsoft.Extensions.Logging;
using Pal.Client.Commands;
using Pal.Client.Configuration;
using Pal.Client.DependencyInjection;
using Pal.Client.Properties;
using Pal.Client.Rendering;
namespace Pal.Client
namespace Pal.Client;
/// <summary>
/// With all DI logic elsewhere, this plugin shell really only takes care of a few things around events that
/// need to be sent to different receivers depending on priority or configuration .
/// </summary>
/// <see cref="DependencyInjectionContext"/>
internal sealed class Plugin : IDalamudPlugin
{
/// <summary>
/// With all DI logic elsewhere, this plugin shell really only takes care of a few things around events that
/// need to be sent to different receivers depending on priority or configuration .
/// </summary>
/// <see cref="DependencyInjectionContext"/>
internal sealed class Plugin : IDalamudPlugin
{
private readonly CancellationTokenSource _initCts = new();
private readonly DalamudPluginInterface _pluginInterface;
private readonly CommandManager _commandManager;
private readonly ClientState _clientState;
private readonly ChatGui _chatGui;
private readonly Framework _framework;
private readonly IDalamudPluginInterface _pluginInterface;
private readonly ICommandManager _commandManager;
private readonly IClientState _clientState;
private readonly IChatGui _chatGui;
private readonly IFramework _framework;
private readonly TaskCompletionSource<IServiceScope> _rootScopeCompletionSource = new();
private ELoadState _loadState = ELoadState.Initializing;
private DependencyInjectionContext? _dependencyInjectionContext;
private ILogger _logger = DependencyInjectionContext.LoggerProvider.CreateLogger<Plugin>();
private ILogger _logger;
private WindowSystem? _windowSystem;
private IServiceScope? _rootScope;
private Action? _loginAction;
public Plugin(
DalamudPluginInterface pluginInterface,
CommandManager commandManager,
ClientState clientState,
ChatGui chatGui,
Framework framework)
IDalamudPluginInterface pluginInterface,
ICommandManager commandManager,
IClientState clientState,
IChatGui chatGui,
IFramework framework,
IPluginLog pluginLog)
{
_pluginInterface = pluginInterface;
_commandManager = commandManager;
_clientState = clientState;
_chatGui = chatGui;
_framework = framework;
_logger = new DalamudLoggerProvider(pluginLog).CreateLogger<Plugin>();
// set up the current UI language before creating anything
Localization.Culture = new CultureInfo(_pluginInterface.UiLanguage);
@ -74,8 +76,6 @@ namespace Pal.Client
Task.Run(async () => await CreateDependencyContext());
}
public string Name => Localization.Palace_Pal;
private async Task CreateDependencyContext()
{
try
@ -102,12 +102,10 @@ namespace Pal.Client
_rootScopeCompletionSource.SetResult(_rootScope);
_loadState = ELoadState.Loaded;
}
catch (ObjectDisposedException e)
{
_rootScopeCompletionSource.SetException(e);
_loadState = ELoadState.Error;
}
catch (OperationCanceledException e)
catch (Exception e) when (e is ObjectDisposedException
or OperationCanceledException
or RepoVerification.RepoVerificationFailedException
|| (e is FileLoadException && _pluginInterface.IsDev))
{
_rootScopeCompletionSource.SetException(e);
_loadState = ELoadState.Error;
@ -135,7 +133,7 @@ namespace Pal.Client
_loginAction = loginAction;
}
private void Login(object? sender, EventArgs eventArgs)
private void Login()
{
_loginAction?.Invoke();
_loginAction = null;
@ -234,5 +232,4 @@ namespace Pal.Client
Loaded,
Error
}
}
}

View File

@ -1,8 +0,0 @@
using System.Reflection;
[assembly: AssemblyVersion(ThisAssembly.Git.SemVer.Major + "." + ThisAssembly.Git.SemVer.Minor)]
[assembly: AssemblyFileVersion(ThisAssembly.Git.SemVer.Major + "." + ThisAssembly.Git.SemVer.Minor)]
[assembly: AssemblyInformationalVersion(
ThisAssembly.Git.SemVer.Major + "." +
ThisAssembly.Git.SemVer.Minor + "+" +
ThisAssembly.Git.Commit)]

View File

@ -33,14 +33,24 @@
<!-- Generic Errors -->
<!-- /pal commands -->
<!-- Messages while connecting to the server. These are typically only visible when clicking 'Test connection'. -->
<data name="ConnectionSuccessful" xml:space="preserve">
<value>Verbindung erfolgreich.</value>
</data>
<data name="ConnectionError_NotOnline" xml:space="preserve">
<value>Sie sind nicht online.</value>
<comment>Shown if you attempt to connect to the server while you have selected 'never upload discoveries, only show traps and coffers i found myself'</comment>
</data>
<data name="ConnectionError_OldVersion" xml:space="preserve">
<value>Ihre Version von Palace Pal ist veraltet, bitte aktualisieren Sie das Plugin mit Hilfe des Plugin Installers.</value>
<comment>Shown if the version is too old to create an account or log in.</comment>
</data>
<!-- Config Window: Deep Dungeons -->
<data name="ConfigTab_DeepDungeons" xml:space="preserve">
<value>Tiefe Gewölbe</value>
</data>
<data name="Config_Traps_Show" xml:space="preserve">
<value>Fallen anzeigen</value>
</data>
<!-- Config Window: Community -->
<!-- Config Window: Import -->
<!-- Config Window: Export -->

View File

@ -15,6 +15,7 @@ dotnet ef migrations add MigrationName --configuration EF
```
To rebuild the compiled model:
```shell
dotnet ef dbcontext optimize --output-dir Database/Compiled --namespace Pal.Client.Database.Compiled --configuration EF
```

View File

@ -1,9 +1,8 @@
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
internal enum ELayer
{
internal enum ELayer
{
TrapHoard,
RegularCoffers,
Test,
}
}

View File

@ -1,9 +1,8 @@
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
public interface IRenderElement
{
public interface IRenderElement
{
bool IsValid { get; }
uint Color { get; set; }
}
bool Enabled { get; set; }
}

View File

@ -3,18 +3,17 @@ using System.Numerics;
using Pal.Client.Configuration;
using Pal.Client.Floors;
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
internal interface IRenderer
{
internal interface IRenderer
{
ERenderer GetConfigValue();
void SetLayer(ELayer layer, IReadOnlyList<IRenderElement> elements);
void ResetLayer(ELayer layer);
IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, uint color, bool fill = false);
IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, bool enabled, uint color, bool fill = false);
void DrawDebugItems(uint trapColor, uint hoardColor);
}
}

View File

@ -1,10 +1,10 @@
using System.Collections.Generic;
using Pal.Client.Floors;
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
internal sealed class MarkerConfig
{
internal sealed class MarkerConfig
{
private static readonly MarkerConfig EmptyConfig = new();
private static readonly Dictionary<MemoryLocation.EType, MarkerConfig> MarkerConfigs = new()
@ -20,5 +20,4 @@ namespace Pal.Client.Rendering
public static MarkerConfig ForType(MemoryLocation.EType type) =>
MarkerConfigs.GetValueOrDefault(type, EmptyConfig);
}
}

View File

@ -6,10 +6,10 @@ using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
using Pal.Client.Floors;
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
internal sealed class RenderAdapter : IRenderer, IDisposable
{
internal sealed class RenderAdapter : IRenderer, IDisposable
{
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly ILogger<RenderAdapter> _logger;
private readonly IPalacePalConfiguration _configuration;
@ -60,8 +60,9 @@ namespace Pal.Client.Rendering
public void ResetLayer(ELayer layer)
=> _implementation.ResetLayer(layer);
public IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, uint color, bool fill = false)
=> _implementation.CreateElement(type, pos, color, fill);
public IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, bool enabled, uint color,
bool fill = false)
=> _implementation.CreateElement(type, pos, enabled, color, fill);
public ERenderer GetConfigValue()
=> throw new NotImplementedException();
@ -74,5 +75,4 @@ namespace Pal.Client.Rendering
if (_implementation is SimpleRenderer sr)
sr.DrawLayers();
}
}
}

View File

@ -1,8 +1,6 @@
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
internal static class RenderData
{
internal static class RenderData
{
public static readonly uint ColorInvisible = 0;
public static readonly long TestLayerTimeout = 10_000;
}
}

View File

@ -1,36 +1,34 @@
using Dalamud.Interface;
using ImGuiNET;
using System;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState;
using Dalamud.Game.Gui;
using Dalamud.Interface.Utility;
using Dalamud.Plugin.Services;
using ImGuiNET;
using Pal.Client.Configuration;
using Pal.Client.DependencyInjection;
using Pal.Client.Floors;
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
/// <summary>
/// Simple renderer that only draws basic stuff.
///
/// This is based on what SliceIsRight uses, and what PalacePal used before it was
/// remade into PalacePal (which is the third or fourth iteration on the same idea
/// I made, just with a clear vision).
/// </summary>
internal sealed class SimpleRenderer : IRenderer, IDisposable
{
/// <summary>
/// Simple renderer that only draws basic stuff.
///
/// This is based on what SliceIsRight uses, and what PalacePal used before it was
/// remade into PalacePal (which is the third or fourth iteration on the same idea
/// I made, just with a clear vision).
/// </summary>
internal sealed class SimpleRenderer : IRenderer, IDisposable
{
private const int SegmentCount = 20;
private readonly ClientState _clientState;
private readonly GameGui _gameGui;
private readonly IClientState _clientState;
private readonly IGameGui _gameGui;
private readonly IPalacePalConfiguration _configuration;
private readonly TerritoryState _territoryState;
private readonly ConcurrentDictionary<ELayer, SimpleLayer> _layers = new();
public SimpleRenderer(ClientState clientState, GameGui gameGui, IPalacePalConfiguration configuration,
public SimpleRenderer(IClientState clientState, IGameGui gameGui, IPalacePalConfiguration configuration,
TerritoryState territoryState)
{
_clientState = clientState;
@ -54,13 +52,15 @@ namespace Pal.Client.Rendering
l.Dispose();
}
public IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, uint color, bool fill = false)
public IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, bool enabled, uint color,
bool fill = false)
{
var config = MarkerConfig.ForType(type);
return new SimpleElement
{
Type = type,
Position = pos + new Vector3(0, config.OffsetY, 0),
Enabled = enabled,
Color = color,
Radius = config.Radius,
Fill = fill,
@ -77,10 +77,12 @@ namespace Pal.Client.Rendering
(SimpleElement)CreateElement(
MemoryLocation.EType.Trap,
_clientState.LocalPlayer?.Position ?? default,
true,
trapColor),
(SimpleElement)CreateElement(
MemoryLocation.EType.Hoard,
_clientState.LocalPlayer?.Position ?? default,
true,
hoardColor)
},
ExpiresAt = Environment.TickCount64 + RenderData.TestLayerTimeout
@ -120,7 +122,7 @@ namespace Pal.Client.Rendering
private void Draw(SimpleElement e)
{
if (e.Color == RenderData.ColorInvisible)
if (!e.Enabled)
return;
switch (e.Type)
@ -181,7 +183,7 @@ namespace Pal.Client.Rendering
public required IReadOnlyList<SimpleElement> Elements { get; init; }
public long ExpiresAt { get; init; } = long.MaxValue;
public bool IsValid(ClientState clientState) =>
public bool IsValid(IClientState clientState) =>
TerritoryType == clientState.TerritoryType && ExpiresAt >= Environment.TickCount64;
public void Dispose()
@ -196,9 +198,9 @@ namespace Pal.Client.Rendering
public bool IsValid { get; set; } = true;
public required MemoryLocation.EType Type { get; init; }
public required Vector3 Position { get; init; }
public required bool Enabled { get; set; }
public required uint Color { get; set; }
public required float Radius { get; init; }
public required bool Fill { get; init; }
}
}
}

View File

@ -1,37 +1,37 @@
using Dalamud.Plugin;
using ECommons;
using ECommons.Reflection;
using ECommons.Schedulers;
using ECommons.SplatoonAPI;
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Reflection;
using Dalamud.Game.ClientState;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using ECommons;
using ECommons.Reflection;
using ECommons.Schedulers;
using ECommons.SplatoonAPI;
using Microsoft.Extensions.Logging;
using Pal.Client.Configuration;
using Pal.Client.DependencyInjection;
using Pal.Client.Floors;
namespace Pal.Client.Rendering
namespace Pal.Client.Rendering;
internal sealed class SplatoonRenderer : IRenderer, IDisposable
{
internal sealed class SplatoonRenderer : IRenderer, IDisposable
{
private const long OnTerritoryChange = -2;
private readonly ILogger<SplatoonRenderer> _logger;
private readonly DebugState _debugState;
private readonly ClientState _clientState;
private readonly IClientState _clientState;
private readonly Chat _chat;
public SplatoonRenderer(
ILogger<SplatoonRenderer> logger,
DalamudPluginInterface pluginInterface,
IDalamudPluginInterface pluginInterface,
IDalamudPlugin dalamudPlugin,
DebugState debugState,
ClientState clientState,
IClientState clientState,
Chat chat)
{
_logger = logger;
@ -80,7 +80,7 @@ namespace Pal.Client.Rendering
private string ToLayerName(ELayer layer)
=> $"PalacePal.{layer}";
public IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, uint color, bool fill = false)
public IRenderElement CreateElement(MemoryLocation.EType type, Vector3 pos, bool enabled, uint color, bool fill = false)
{
MarkerConfig config = MarkerConfig.ForType(type);
Element element = new Element(ElementType.CircleAtFixedCoordinates)
@ -96,6 +96,7 @@ namespace Pal.Client.Rendering
FillStep = 1,
color = color,
thicc = 2,
Enabled = enabled,
};
return new SplatoonElement(this, element);
}
@ -111,8 +112,8 @@ namespace Pal.Client.Rendering
var elements = new List<IRenderElement>
{
CreateElement(MemoryLocation.EType.Trap, pos.Value, trapColor),
CreateElement(MemoryLocation.EType.Hoard, pos.Value, hoardColor),
CreateElement(MemoryLocation.EType.Trap, pos.Value, true, trapColor),
CreateElement(MemoryLocation.EType.Hoard, pos.Value, true, hoardColor),
};
if (!Splatoon.AddDynamicElements(ToLayerName(ELayer.Test),
@ -186,11 +187,10 @@ namespace Pal.Client.Rendering
public bool IsValid => !_renderer.IsDisposed && Delegate.IsValid();
public uint Color
public bool Enabled
{
get => Delegate.color;
set => Delegate.color = value;
}
get => Delegate.Enabled;
set => Delegate.Enabled = value;
}
}
}

View File

@ -2,10 +2,10 @@
using Dalamud.Logging;
using Microsoft.Extensions.Logging;
namespace Pal.Client.Scheduled
namespace Pal.Client.Scheduled;
internal interface IQueueOnFrameworkThread
{
internal interface IQueueOnFrameworkThread
{
internal interface IHandler
{
void RunIfCompatible(IQueueOnFrameworkThread queued, ref bool recreateLayout);
@ -36,5 +36,4 @@ namespace Pal.Client.Scheduled
}
}
}
}
}

View File

@ -4,10 +4,10 @@ using Pal.Client.DependencyInjection;
using Pal.Client.Floors;
using Pal.Client.Rendering;
namespace Pal.Client.Scheduled
namespace Pal.Client.Scheduled;
internal sealed class QueuedConfigUpdate : IQueueOnFrameworkThread
{
internal sealed class QueuedConfigUpdate : IQueueOnFrameworkThread
{
internal sealed class Handler : IQueueOnFrameworkThread.Handler<QueuedConfigUpdate>
{
private readonly RenderAdapter _renderAdapter;
@ -25,5 +25,4 @@ namespace Pal.Client.Scheduled
_renderAdapter.ConfigUpdated();
}
}
}
}

View File

@ -1,19 +1,19 @@
using Account;
using Pal.Common;
using System;
using System;
using System.IO;
using System.Threading.Tasks;
using Export;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Pal.Client.Database;
using Pal.Client.DependencyInjection;
using Pal.Client.Properties;
using Pal.Client.Windows;
using Pal.Common;
namespace Pal.Client.Scheduled
namespace Pal.Client.Scheduled;
internal sealed class QueuedImport : IQueueOnFrameworkThread
{
internal sealed class QueuedImport : IQueueOnFrameworkThread
{
private ExportRoot Export { get; }
private Guid ExportId { get; set; }
private int ImportedTraps { get; set; }
@ -119,5 +119,4 @@ namespace Pal.Client.Scheduled
return true;
}
}
}
}

View File

@ -11,10 +11,10 @@ using Pal.Client.Floors.Tasks;
using Pal.Client.Net;
using Pal.Common;
namespace Pal.Client.Scheduled
namespace Pal.Client.Scheduled;
internal sealed class QueuedSyncResponse : IQueueOnFrameworkThread
{
internal sealed class QueuedSyncResponse : IQueueOnFrameworkThread
{
public required SyncType Type { get; init; }
public required ushort TerritoryType { get; init; }
public required bool Success { get; init; }
@ -141,21 +141,20 @@ namespace Pal.Client.Scheduled
}
}
}
}
}
public enum ESyncState
{
public enum ESyncState
{
NotAttempted,
NotNeeded,
Started,
Complete,
Failed,
}
}
public enum SyncType
{
public enum SyncType
{
Upload,
Download,
MarkSeen,
}
}

View File

@ -7,10 +7,10 @@ using Pal.Client.Floors;
using Pal.Client.Windows;
using Pal.Common;
namespace Pal.Client.Scheduled
namespace Pal.Client.Scheduled;
internal sealed class QueuedUndoImport : IQueueOnFrameworkThread
{
internal sealed class QueuedUndoImport : IQueueOnFrameworkThread
{
public QueuedUndoImport(Guid exportId)
{
ExportId = exportId;
@ -38,5 +38,4 @@ namespace Pal.Client.Scheduled
_configWindow.UpdateLastImport();
}
}
}
}

View File

@ -1,17 +1,17 @@
using System;
using System.Numerics;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Windowing;
using ECommons;
using ImGuiNET;
using System.Numerics;
using Pal.Client.Configuration;
using Pal.Client.Extensions;
using Pal.Client.Properties;
namespace Pal.Client.Windows
namespace Pal.Client.Windows;
internal sealed class AgreementWindow : Window, IDisposable, ILanguageChanged
{
internal sealed class AgreementWindow : Window, IDisposable, ILanguageChanged
{
private const string WindowId = "###PalPalaceAgreement";
private readonly WindowSystem _windowSystem;
private readonly ConfigurationManager _configurationManager;
@ -99,7 +99,6 @@ namespace Pal.Client.Windows
ImGui.Separator();
if (ImGui.Button(Localization.Agreement_ViewPluginAndServerSourceCode))
GenericHelpers.ShellStart("https://github.com/carvelli/PalPalace");
}
GenericHelpers.ShellStart("https://git.carvel.li/liza/PalacePal");
}
}

View File

@ -1,32 +1,34 @@
using Account;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface.Windowing;
using ECommons;
using Google.Protobuf;
using ImGuiNET;
using Pal.Client.Net;
using Pal.Client.Rendering;
using Pal.Client.Scheduled;
using System;
using System;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Interface;
using Dalamud.Interface.Components;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface.Windowing;
using ECommons;
using Export;
using Google.Protobuf;
using ImGuiNET;
using LLib;
using LLib.ImGui;
using Microsoft.Extensions.Logging;
using Pal.Client.Extensions;
using Pal.Client.Properties;
using Pal.Client.Configuration;
using Pal.Client.Database;
using Pal.Client.DependencyInjection;
using Pal.Client.Extensions;
using Pal.Client.Floors;
using Pal.Client.Net;
using Pal.Client.Properties;
using Pal.Client.Rendering;
using Pal.Client.Scheduled;
namespace Pal.Client.Windows
namespace Pal.Client.Windows;
internal sealed class ConfigWindow : LWindow, ILanguageChanged, IDisposable
{
internal sealed class ConfigWindow : Window, ILanguageChanged, IDisposable
{
private const string WindowId = "###PalPalaceConfig";
private readonly ILogger<ConfigWindow> _logger;
@ -97,6 +99,12 @@ namespace Pal.Client.Windows
Position = new Vector2(300, 300);
PositionCondition = ImGuiCond.FirstUseEver;
SizeConstraints = new WindowSizeConstraints
{
MinimumSize = new Vector2(300, 300),
MaximumSize = new Vector2(9999, 9999),
};
_importDialog = new FileDialogManager
{ AddedWindowFlags = ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoDocking };
_exportDialog = new FileDialogManager
@ -284,11 +292,13 @@ namespace Pal.Client.Windows
ImGui.TextWrapped(Localization.Config_ImportExplanation1);
ImGui.TextWrapped(Localization.Config_ImportExplanation2);
ImGui.TextWrapped(Localization.Config_ImportExplanation3);
/* FIXME
ImGui.Separator();
ImGui.TextWrapped(string.Format(Localization.Config_ImportDownloadLocation,
"https://github.com/carvelli/PalacePal/releases/"));
if (ImGui.Button(Localization.Config_Import_VisitGitHub))
GenericHelpers.ShellStart("https://github.com/carvelli/PalacePal/releases/latest");
*/
ImGui.Separator();
ImGui.Text(Localization.Config_SelectImportFile);
ImGui.SameLine();
@ -575,5 +585,4 @@ namespace Pal.Client.Windows
};
}
}
}
}

View File

@ -1,17 +1,17 @@
using Dalamud.Interface.Windowing;
using ImGuiNET;
using Pal.Common;
using Palace;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface.Windowing;
using ImGuiNET;
using Pal.Client.Properties;
using Pal.Common;
using Palace;
namespace Pal.Client.Windows
namespace Pal.Client.Windows;
internal sealed class StatisticsWindow : Window, IDisposable, ILanguageChanged
{
internal sealed class StatisticsWindow : Window, IDisposable, ILanguageChanged
{
private const string WindowId = "###PalacePalStats";
private readonly WindowSystem _windowSystem;
private readonly SortedDictionary<ETerritoryType, TerritoryStatistics> _territoryStatistics = new();
@ -122,5 +122,4 @@ namespace Pal.Client.Windows
TerritoryName = territoryName;
}
}
}
}

View File

@ -0,0 +1,344 @@
{
"version": 1,
"dependencies": {
"net8.0-windows7.0": {
"Dalamud.Extensions.MicrosoftLogging": {
"type": "Direct",
"requested": "[4.0.1, )",
"resolved": "4.0.1",
"contentHash": "fMEL2ajtF/30SBBku7vMyG0yye5eHN/A9fgT//1CEjUth/Wz2CYco5Ehye21T8KN1IuAPwoqJuu49rB71j+8ug==",
"dependencies": {
"Microsoft.Extensions.Logging": "8.0.0"
}
},
"DalamudPackager": {
"type": "Direct",
"requested": "[2.1.13, )",
"resolved": "2.1.13",
"contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ=="
},
"DotNet.ReproducibleBuilds": {
"type": "Direct",
"requested": "[1.1.1, )",
"resolved": "1.1.1",
"contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==",
"dependencies": {
"Microsoft.SourceLink.AzureRepos.Git": "1.1.1",
"Microsoft.SourceLink.Bitbucket.Git": "1.1.1",
"Microsoft.SourceLink.GitHub": "1.1.1",
"Microsoft.SourceLink.GitLab": "1.1.1"
}
},
"Google.Protobuf": {
"type": "Direct",
"requested": "[3.27.2, )",
"resolved": "3.27.2",
"contentHash": "0wdgA3LO9mBS477jieBFs4pU1sWhVtwv/P+i9nAEiFDQyUA7PPHDBbJL1CeqYtV18jLiq9og4n7wSVCO171OBg=="
},
"Grpc.Net.Client": {
"type": "Direct",
"requested": "[2.63.0, )",
"resolved": "2.63.0",
"contentHash": "847zG24daOP1242OpbnjhbKtplH/EfV/76QReQA3cbS5SL78uIXsWMe9IN9JlIb4+kT3eE4fjMCXTn8BAQ91Ng==",
"dependencies": {
"Grpc.Net.Common": "2.63.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.0"
}
},
"Grpc.Tools": {
"type": "Direct",
"requested": "[2.64.0, )",
"resolved": "2.64.0",
"contentHash": "W5RrhDFHUhioASktxfuDs5fTjWUxwegljZAig9zFL8nWNskeyQA6OXN2choWKYxGrljer25VqCJCMbWz7XHvqg=="
},
"Microsoft.EntityFrameworkCore.Sqlite": {
"type": "Direct",
"requested": "[8.0.6, )",
"resolved": "8.0.6",
"contentHash": "nC4cZN4zReTb22qd9WDU0eDmlXvkyf2g2pqQ3VIHJbkpJcdWSY/PDgwGpbpShsVcAjXbkjGiUcv9aGwa61xQPw==",
"dependencies": {
"Microsoft.EntityFrameworkCore.Sqlite.Core": "8.0.6",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.6"
}
},
"Microsoft.Extensions.Logging": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "8.0.0",
"Microsoft.Extensions.Logging.Abstractions": "8.0.0",
"Microsoft.Extensions.Options": "8.0.0"
}
},
"Microsoft.SourceLink.Gitea": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "KOBodmDnlWGIqZt2hT47Q69TIoGhIApDVLCyyj9TT5ct8ju16AbHYcB4XeknoHX562wO1pMS/1DfBIZK+V+sxg==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"System.Security.Cryptography.ProtectedData": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "+TUFINV2q2ifyXauQXRwy4CiBhqvDEDZeVJU7qfxya4aRYOKzVBpN+4acx25VcPB9ywUN6C0n8drWl110PhZEg=="
},
"Grpc.Core.Api": {
"type": "Transitive",
"resolved": "2.63.0",
"contentHash": "t3+/MF8AxIqKq5UmPB9EWAnM9C/+lXOB8TRFfeVMDntf6dekfJmjpKDebaT4t2bbuwVwwvthxxox9BuGr59kYA=="
},
"Grpc.Net.Common": {
"type": "Transitive",
"resolved": "2.63.0",
"contentHash": "RLt6p31ZMsXRcHNeu1dQuIFLYZvnwP6LUzoDPlV3KoR4w9btmwrXIvz9Jbp1SOmxW7nXw9zShAeIt5LsqFAx5w==",
"dependencies": {
"Grpc.Core.Api": "2.63.0"
}
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
"resolved": "8.0.6",
"contentHash": "umhZ0ZF2RI81rGFTnYmCxI+Euj4Aqe/6Y4+8CxN9OVJNGDNIqB5laJ3wxQTU8zXCcm2k9F7FL+/6RVoOT4z1Fw==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.6"
}
},
"Microsoft.EntityFrameworkCore": {
"type": "Transitive",
"resolved": "8.0.6",
"contentHash": "Ms5e5QuBAjVIuQsGumeLvkgMiOpnj6wxPvwBIoe1NfTkseWK4NZYztnhgDlpkCPkrUmJEXLv69kl349Ours30Q==",
"dependencies": {
"Microsoft.EntityFrameworkCore.Abstractions": "8.0.6",
"Microsoft.EntityFrameworkCore.Analyzers": "8.0.6",
"Microsoft.Extensions.Caching.Memory": "8.0.0",
"Microsoft.Extensions.Logging": "8.0.0"
}
},
"Microsoft.EntityFrameworkCore.Abstractions": {
"type": "Transitive",
"resolved": "8.0.6",
"contentHash": "X7wSSBNFRuN8j8M9HDYG7rPpEeyhY+PdJZR9rftmgvsZH0eK5+bZ3b3As8iO4rLEpjsBzDnrgSIY6q2F3HQatw=="
},
"Microsoft.EntityFrameworkCore.Analyzers": {
"type": "Transitive",
"resolved": "8.0.6",
"contentHash": "fDNtuQ4lAaPaCOlsrwUck/GvnF4QLeDpMmE1L5QtxZpMSmWfnL2/vk8sDL9OVTWcfprooI9V5MNpIx3/Tq5ehg=="
},
"Microsoft.EntityFrameworkCore.Relational": {
"type": "Transitive",
"resolved": "8.0.6",
"contentHash": "chhfmLusCGLGvNYtvMji6KGQlduPDnJsStG/LjS8qJhFWJDDzTZpSr2LHowewcxMrMo/Axc6Jwe+WwSi/vlkTg==",
"dependencies": {
"Microsoft.EntityFrameworkCore": "8.0.6",
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
}
},
"Microsoft.EntityFrameworkCore.Sqlite.Core": {
"type": "Transitive",
"resolved": "8.0.6",
"contentHash": "87xfPtqSouxWWdynYZv/rubd0rOUeiN9+XeoMWQzpZm/5svH1TuvzFODGIY0zKuXS18NiOFyHl9N6///eaEs/Q==",
"dependencies": {
"Microsoft.Data.Sqlite.Core": "8.0.6",
"Microsoft.EntityFrameworkCore.Relational": "8.0.6",
"Microsoft.Extensions.DependencyModel": "8.0.0"
}
},
"Microsoft.Extensions.Caching.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "3KuSxeHoNYdxVYfg2IRZCThcrlJ1XJqIXkAWikCsbm5C/bCjv7G0WoKDyuR98Q+T607QT2Zl5GsbGRkENcV2yQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Caching.Memory": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "7pqivmrZDzo1ADPkRwjy+8jtRKWRCPag9qPI+p7sgu7Q4QreWhcvbiWXsbhP+yY8XSiDvZpu2/LWdBv7PnmOpQ==",
"dependencies": {
"Microsoft.Extensions.Caching.Abstractions": "8.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Logging.Abstractions": "8.0.0",
"Microsoft.Extensions.Options": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.DependencyInjection": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg=="
},
"Microsoft.Extensions.DependencyModel": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "NSmDw3K0ozNDgShSIpsZcbFIzBX4w28nDag+TfaQujkXGazBm+lid5onlWoCBy4VsLxqnnKjEBbGSJVWJMf43g==",
"dependencies": {
"System.Text.Encodings.Web": "8.0.0",
"System.Text.Json": "8.0.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
}
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
},
"Microsoft.SourceLink.AzureRepos.Git": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.Bitbucket.Git": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Microsoft.SourceLink.GitHub": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"Microsoft.SourceLink.GitLab": {
"type": "Transitive",
"resolved": "1.1.1",
"contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1"
}
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.6",
"contentHash": "BmAf6XWt4TqtowmiWe4/5rRot6GerAeklmOPfviOvwLoF5WwgxcJHAxZtySuyW9r9w+HLILnm8VfJFLCUJYW8A==",
"dependencies": {
"SQLitePCLRaw.lib.e_sqlite3": "2.1.6",
"SQLitePCLRaw.provider.e_sqlite3": "2.1.6"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
"resolved": "2.1.6",
"contentHash": "wO6v9GeMx9CUngAet8hbO7xdm+M42p1XeJq47ogyRoYSvNSp0NGLI+MgC0bhrMk9C17MTVFlLiN6ylyExLCc5w==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.6",
"contentHash": "2ObJJLkIUIxRpOUlZNGuD4rICpBnrBR5anjyfUFQep4hMOIeqW+XGQYzrNmHSVz5xSWZ3klSbh7sFR6UyDj68Q=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.6",
"contentHash": "PQ2Oq3yepLY4P7ll145P3xtx2bX8xF4PzaKPRpw9jZlKvfe4LE/saAV82inND9usn1XRpmxXk7Lal3MTI+6CNg==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.6"
}
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.3",
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
},
"System.Text.Encodings.Web": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
},
"System.Text.Json": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==",
"dependencies": {
"System.Text.Encodings.Web": "8.0.0"
}
},
"ecommons": {
"type": "Project"
},
"llib": {
"type": "Project",
"dependencies": {
"DalamudPackager": "[2.1.13, )"
}
},
"pal.common": {
"type": "Project"
}
},
"net8.0-windows7.0/win-x64": {
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.6",
"contentHash": "2ObJJLkIUIxRpOUlZNGuD4rICpBnrBR5anjyfUFQep4hMOIeqW+XGQYzrNmHSVz5xSWZ3klSbh7sFR6UyDj68Q=="
},
"System.Text.Encodings.Web": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
}
}
}
}

View File

@ -1,12 +1,12 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
namespace Pal.Common
namespace Pal.Common;
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ETerritoryType : ushort
{
[SuppressMessage("ReSharper", "UnusedMember.Global")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum ETerritoryType : ushort
{
Palace_1_10 = 561,
Palace_11_20,
Palace_21_30,
@ -59,5 +59,4 @@ namespace Pal.Common
EurekaOrthos_71_80,
EurekaOrthos_81_90,
EurekaOrthos_91_100
}
}

View File

@ -1,10 +1,12 @@
using System.ComponentModel.DataAnnotations;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
namespace Pal.Common
namespace Pal.Common;
public static class EnumExtensions
{
public static class EnumExtensions
{
public static int? GetOrder(this Enum e)
{
Type type = e.GetType();
@ -12,5 +14,4 @@ namespace Pal.Common
DisplayAttribute? attribute = field.GetCustomAttributes(typeof(DisplayAttribute), false).Cast<DisplayAttribute>().FirstOrDefault();
return attribute?.Order;
}
}
}

View File

@ -4,10 +4,9 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pal.Common
namespace Pal.Common;
public static class ExportConfig
{
public static class ExportConfig
{
public static int ExportVersion => 2;
}
}

View File

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<LangVersion>11.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
<DebugType>portable</DebugType>
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
</Project>

View File

@ -1,9 +1,10 @@
using System.Numerics;
using System;
using System.Numerics;
namespace Pal.Common
namespace Pal.Common;
public class PalaceMath
{
public class PalaceMath
{
private static readonly Vector3 ScaleFactor = new(5);
public static bool IsNearlySamePosition(Vector3 a, Vector3 b)
@ -18,5 +19,4 @@ namespace Pal.Common
v *= ScaleFactor;
return HashCode.Combine((int)v.X, (int)v.Y, (int)v.Z);
}
}
}

View File

@ -18,6 +18,7 @@ service AccountService {
}
message CreateAccountRequest {
Version version = 1;
}
message CreateAccountReply {
@ -35,6 +36,7 @@ enum CreateAccountError {
message LoginRequest {
string accountId = 1;
Version version = 2;
}
message LoginReply {
@ -56,3 +58,8 @@ message VerifyRequest {
message VerifyReply {
}
message Version {
int32 major = 1;
int32 minor = 2;
}

View File

@ -1,6 +1,6 @@
syntax = "proto3";
package account;
package export;
import "google/protobuf/timestamp.proto";

View File

@ -0,0 +1,6 @@
{
"version": 1,
"dependencies": {
"net8.0": {}
}
}

23
Pal.sln
View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32929.385
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pal.Server", "Pal.Server\Pal.Server.csproj", "{AB3E2849-DB06-46F6-8457-9AC1096B4125}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pal.Server", "Server\Server\Pal.Server.csproj", "{AB3E2849-DB06-46F6-8457-9AC1096B4125}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pal.Client", "Pal.Client\Pal.Client.csproj", "{7F1985B3-D376-4A91-BC9B-46C2A860F9EF}"
EndProject
@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
Dockerfile = Dockerfile
README.md = README.md
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ECommons", "vendor\ECommons\ECommons\ECommons.csproj", "{D0B37096-5BC3-41B0-8D81-203CBA3932B0}"
@ -24,6 +25,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github-workflows", "github-
.github\workflows\upload-crowdin.yml = .github\workflows\upload-crowdin.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pal.Server.Tests", "Server\Tests\Pal.Server.Tests.csproj", "{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LLib", "vendor\LLib\LLib.csproj", "{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -64,6 +69,22 @@ Global
{D0B37096-5BC3-41B0-8D81-203CBA3932B0}.Release|Any CPU.Build.0 = Release|x64
{D0B37096-5BC3-41B0-8D81-203CBA3932B0}.Release|x64.ActiveCfg = Release|x64
{D0B37096-5BC3-41B0-8D81-203CBA3932B0}.Release|x64.Build.0 = Release|x64
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Debug|x64.ActiveCfg = Debug|Any CPU
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Debug|x64.Build.0 = Debug|Any CPU
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Release|Any CPU.Build.0 = Release|Any CPU
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Release|x64.ActiveCfg = Release|Any CPU
{AEC052FA-F178-492C-9A09-ED28DBE1EF5E}.Release|x64.Build.0 = Release|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Debug|x64.ActiveCfg = Debug|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Debug|x64.Build.0 = Debug|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Release|Any CPU.Build.0 = Release|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Release|x64.ActiveCfg = Release|Any CPU
{B1321FD5-7BBF-4C9D-83C1-F8D7C394F32A}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -5,15 +5,14 @@ Shows possible trap & hoard coffer locations in Palace of the Dead & Heaven on H
## Installation
To install this plugin from my plugin repository, please check the
[Installation Instructions](https://github.com/carvelli/Dalamud-Plugins#installation).
[Installation Instructions](https://git.carvel.li/liza/plugin-repo/src/branch/master/README.md).
Additionally, you **need to install Splatoon**, which is used to render the visible overlays.
Please check [Splatoon's Installation Instructions](https://github.com/NightmareXIV/MyDalamudPlugins#installation).
## Translation
Please feel free to help by [translating this plugin into your language](https://crowdin.com/project/palace-pal).
If you want to translate the plugin into a language that is currently not enabled,
[please create a new issue](https://github.com/carvelli/PalacePal/issues/new).
[please create a new issue](https://git.carvel.li/liza/PalacePal/issues/new).

1
Server Submodule

@ -0,0 +1 @@
Subproject commit e59583fac353fdd960556ed2fa65220d66db5637

4
docker-build.sh Executable file
View File

@ -0,0 +1,4 @@
git fetch origin master
git reset --hard origin/master
git submodule update --checkout
docker buildx build -t palacepal-server --platform linux/amd64,linux/arm64 .

2
vendor/ECommons vendored

@ -1 +1 @@
Subproject commit 001af17d74ab681f88d92600fa06dc3f98af74de
Subproject commit dcd85f8cca504360eda4b2cb5327632cc500a22c

1
vendor/LLib vendored Submodule

@ -0,0 +1 @@
Subproject commit e206782c1106e1a5292a06af61783faef1ac0c42