add analyzers and api
This commit is contained in:
102
.editorconfig
Normal file
102
.editorconfig
Normal file
@@ -0,0 +1,102 @@
|
||||
[*.cs]
|
||||
|
||||
# MA0046: Use EventHandler<T> to declare events
|
||||
dotnet_diagnostic.MA0046.severity = silent
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_namespace_declarations = block_scoped:silent
|
||||
csharp_style_prefer_method_group_conversion = true:silent
|
||||
csharp_style_prefer_top_level_statements = true:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_prefer_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||
csharp_style_prefer_tuple_swap = true:suggestion
|
||||
csharp_style_prefer_utf8_string_literals = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
dotnet_diagnostic.MA0016.severity = suggestion
|
||||
dotnet_diagnostic.MA0051.severity = suggestion
|
||||
|
||||
# MA0009: Add regex evaluation timeout
|
||||
dotnet_diagnostic.MA0009.severity = silent
|
||||
|
||||
[*.{cs,vb}]
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
indent_size = 4
|
||||
end_of_line = crlf
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
[*.{cs,vb}]
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
2
MareAPI
2
MareAPI
Submodule MareAPI updated: a2a4d07c04...2d5d9d9d1c
@@ -9,6 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronos.API", "MareA
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumbra\Penumbra.GameData\Penumbra.GameData.csproj", "{89DD407C-B2B7-4BB3-BF26-C550BA1841F8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{585B740D-BA2C-429B-9CF3-B2D223423748}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
@@ -23,21 +23,21 @@ public static class ConfigurationExtensions
|
||||
{
|
||||
return configuration.UidServerComments.ContainsKey(configuration.ApiUri)
|
||||
? configuration.UidServerComments[configuration.ApiUri]
|
||||
: new Dictionary<string, string>();
|
||||
: new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> GetCurrentServerGidComments(this Configuration configuration)
|
||||
{
|
||||
return configuration.GidServerComments.ContainsKey(configuration.ApiUri)
|
||||
? configuration.GidServerComments[configuration.ApiUri]
|
||||
: new Dictionary<string, string>();
|
||||
: new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
public static void SetCurrentServerGidComment(this Configuration configuration, string gid, string comment)
|
||||
{
|
||||
if (!configuration.GidServerComments.ContainsKey(configuration.ApiUri))
|
||||
{
|
||||
configuration.GidServerComments[configuration.ApiUri] = new Dictionary<string, string>();
|
||||
configuration.GidServerComments[configuration.ApiUri] = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
configuration.GidServerComments[configuration.ApiUri][gid] = comment;
|
||||
@@ -47,7 +47,7 @@ public static class ConfigurationExtensions
|
||||
{
|
||||
if (!configuration.UidServerComments.ContainsKey(configuration.ApiUri))
|
||||
{
|
||||
configuration.UidServerComments[configuration.ApiUri] = new Dictionary<string, string>();
|
||||
configuration.UidServerComments[configuration.ApiUri] = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
configuration.UidServerComments[configuration.ApiUri][uid] = comment;
|
||||
@@ -71,8 +71,8 @@ public class Configuration : IPluginConfiguration
|
||||
}
|
||||
|
||||
public string CacheFolder { get; set; } = string.Empty;
|
||||
public Dictionary<string, string> ClientSecret { get; set; } = new();
|
||||
public Dictionary<string, string> CustomServerList { get; set; } = new();
|
||||
public Dictionary<string, string> ClientSecret { get; set; } = new(StringComparer.Ordinal);
|
||||
public Dictionary<string, string> CustomServerList { get; set; } = new(StringComparer.Ordinal);
|
||||
public int MaxLocalCacheInGiB { get; set; } = 20;
|
||||
public bool ReverseUserSort { get; set; } = false;
|
||||
|
||||
@@ -82,10 +82,10 @@ public class Configuration : IPluginConfiguration
|
||||
public bool InitialScanComplete { get; set; } = false;
|
||||
|
||||
public bool FullPause { get; set; } = false;
|
||||
public Dictionary<string, Dictionary<string, string>> UidServerComments { get; set; } = new();
|
||||
public Dictionary<string, Dictionary<string, string>> GidServerComments { get; set; } = new();
|
||||
public Dictionary<string, Dictionary<string, string>> UidServerComments { get; set; } = new(StringComparer.Ordinal);
|
||||
public Dictionary<string, Dictionary<string, string>> GidServerComments { get; set; } = new(StringComparer.Ordinal);
|
||||
|
||||
public Dictionary<string, string> UidComments { get; set; } = new();
|
||||
public Dictionary<string, string> UidComments { get; set; } = new(StringComparer.Ordinal);
|
||||
public int Version { get; set; } = 5;
|
||||
|
||||
public bool ShowTransferWindow { get; set; } = true;
|
||||
@@ -114,10 +114,10 @@ public class Configuration : IPluginConfiguration
|
||||
{
|
||||
Logger.Debug("Migrating Configuration from V0 to V1");
|
||||
Version = 1;
|
||||
ApiUri = ApiUri.Replace("https", "wss");
|
||||
ApiUri = ApiUri.Replace("https", "wss", StringComparison.Ordinal);
|
||||
foreach (var kvp in ClientSecret.ToList())
|
||||
{
|
||||
var newKey = kvp.Key.Replace("https", "wss");
|
||||
var newKey = kvp.Key.Replace("https", "wss", StringComparison.Ordinal);
|
||||
ClientSecret.Remove(kvp.Key);
|
||||
if (ClientSecret.ContainsKey(newKey))
|
||||
{
|
||||
@@ -128,7 +128,7 @@ public class Configuration : IPluginConfiguration
|
||||
ClientSecret.Add(newKey, kvp.Value);
|
||||
}
|
||||
}
|
||||
UidServerComments.Add(ApiUri, UidComments.ToDictionary(k => k.Key, k => k.Value));
|
||||
UidServerComments.Add(ApiUri, UidComments.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal));
|
||||
UidComments.Clear();
|
||||
Save();
|
||||
}
|
||||
@@ -136,10 +136,10 @@ public class Configuration : IPluginConfiguration
|
||||
if (Version == 1)
|
||||
{
|
||||
Logger.Debug("Migrating Configuration from V1 to V2");
|
||||
ApiUri = ApiUri.Replace("5001", "5000");
|
||||
ApiUri = ApiUri.Replace("5001", "5000", StringComparison.Ordinal);
|
||||
foreach (var kvp in ClientSecret.ToList())
|
||||
{
|
||||
var newKey = kvp.Key.Replace("5001", "5000");
|
||||
var newKey = kvp.Key.Replace("5001", "5000", StringComparison.Ordinal);
|
||||
ClientSecret.Remove(kvp.Key);
|
||||
if (ClientSecret.ContainsKey(newKey))
|
||||
{
|
||||
@@ -153,7 +153,7 @@ public class Configuration : IPluginConfiguration
|
||||
|
||||
foreach (var kvp in UidServerComments.ToList())
|
||||
{
|
||||
var newKey = kvp.Key.Replace("5001", "5000");
|
||||
var newKey = kvp.Key.Replace("5001", "5000", StringComparison.Ordinal);
|
||||
UidServerComments.Remove(kvp.Key);
|
||||
UidServerComments.Add(newKey, kvp.Value);
|
||||
}
|
||||
@@ -177,10 +177,10 @@ public class Configuration : IPluginConfiguration
|
||||
{
|
||||
Logger.Debug("Migrating Configuration from V3 to V4");
|
||||
|
||||
ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872");
|
||||
ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872", StringComparison.Ordinal);
|
||||
foreach (var kvp in ClientSecret.ToList())
|
||||
{
|
||||
var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872");
|
||||
var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872", StringComparison.Ordinal);
|
||||
ClientSecret.Remove(kvp.Key);
|
||||
if (ClientSecret.ContainsKey(newKey))
|
||||
{
|
||||
@@ -194,7 +194,7 @@ public class Configuration : IPluginConfiguration
|
||||
|
||||
foreach (var kvp in UidServerComments.ToList())
|
||||
{
|
||||
var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872");
|
||||
var newKey = kvp.Key.Replace("wss://v2202207178628194299.powersrv.de:6871", "wss://v2202207178628194299.powersrv.de:6872", StringComparison.Ordinal);
|
||||
UidServerComments.Remove(kvp.Key);
|
||||
UidServerComments.Add(newKey, kvp.Value);
|
||||
}
|
||||
@@ -207,7 +207,7 @@ public class Configuration : IPluginConfiguration
|
||||
{
|
||||
Logger.Debug("Migrating Configuration from V4 to V5");
|
||||
|
||||
ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6872", "wss://maresynchronos.com");
|
||||
ApiUri = ApiUri.Replace("wss://v2202207178628194299.powersrv.de:6872", "wss://maresynchronos.com", StringComparison.Ordinal);
|
||||
ClientSecret.Remove("wss://v2202207178628194299.powersrv.de:6872");
|
||||
UidServerComments.Remove("wss://v2202207178628194299.powersrv.de:6872");
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ public class CharacterDataFactory
|
||||
|
||||
if (cache.FileReplacements.ContainsKey(objectKind))
|
||||
{
|
||||
if (cache.FileReplacements[objectKind].Any(c => c.ResolvedPath.Contains(mtrlPath)))
|
||||
if (cache.FileReplacements[objectKind].Any(c => c.ResolvedPath.Contains(mtrlPath, StringComparison.Ordinal)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ public class CharacterDataFactory
|
||||
|
||||
if (cache.FileReplacements.ContainsKey(objectKind))
|
||||
{
|
||||
if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(varPath)))
|
||||
if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(varPath, StringComparer.Ordinal)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -214,7 +214,7 @@ public class CharacterDataFactory
|
||||
|
||||
if (cache.FileReplacements.ContainsKey(objectKind))
|
||||
{
|
||||
if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(texPath)))
|
||||
if (cache.FileReplacements[objectKind].Any(c => c.GamePaths.Contains(texPath, StringComparer.Ordinal)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -225,7 +225,7 @@ public class CharacterDataFactory
|
||||
|
||||
cache.AddFileReplacement(objectKind, texFileReplacement);
|
||||
|
||||
if (texPath.Contains("/--")) return;
|
||||
if (texPath.Contains("/--", StringComparison.Ordinal)) return;
|
||||
|
||||
var texDx11Replacement =
|
||||
CreateFileReplacement(texPath.Insert(texPath.LastIndexOf('/') + 1, "--"), doNotReverseResolve);
|
||||
@@ -322,11 +322,11 @@ public class CharacterDataFactory
|
||||
previousData.FileReplacements.Add(objectKind, new());
|
||||
}
|
||||
|
||||
if (!previousData.FileReplacements[objectKind].Any(k => k.GamePaths.Any(p => item.GamePaths.Select(p => p.ToLowerInvariant()).Contains(p.ToLowerInvariant()))))
|
||||
if (!previousData.FileReplacements[objectKind].Any(k => k.GamePaths.Any(p => item.GamePaths.Contains(p, StringComparer.OrdinalIgnoreCase))))
|
||||
{
|
||||
var penumResolve = _ipcManager.PenumbraResolvePath(item.GamePaths.First()).ToLowerInvariant();
|
||||
var gamePath = item.GamePaths.First().ToLowerInvariant();
|
||||
if (penumResolve == gamePath)
|
||||
if (string.Equals(penumResolve, gamePath, StringComparison.Ordinal))
|
||||
{
|
||||
Logger.Debug("PenumResolve was same as GamePath, not adding " + item);
|
||||
transientResourceManager.RemoveTransientResource(charaPointer, item);
|
||||
|
||||
@@ -22,7 +22,7 @@ public class FileCache
|
||||
|
||||
public void SetResolvedFilePath(string filePath)
|
||||
{
|
||||
ResolvedFilepath = filePath.ToLowerInvariant().Replace("\\\\", "\\");
|
||||
ResolvedFilepath = filePath.ToLowerInvariant().Replace("\\\\", "\\", System.StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public string CsvEntry => $"{Hash}{FileCacheManager.CsvSplit}{PrefixedFilePath}{FileCacheManager.CsvSplit}{LastModifiedDateTicks.ToString(CultureInfo.InvariantCulture)}";
|
||||
|
||||
@@ -26,9 +26,9 @@ public class FileCacheManager : IDisposable
|
||||
private readonly Configuration _configuration;
|
||||
private readonly string CsvPath;
|
||||
private string CsvBakPath => CsvPath + ".bak";
|
||||
private readonly ConcurrentDictionary<string, FileCache> FileCaches = new();
|
||||
private readonly ConcurrentDictionary<string, FileCache> FileCaches = new(StringComparer.Ordinal);
|
||||
public const string CsvSplit = "|";
|
||||
private object _fileWriteLock = new object();
|
||||
private object _fileWriteLock = new();
|
||||
|
||||
public FileCacheManager(IpcManager ipcManager, Configuration configuration, string configDirectoryName)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ public class FileCacheManager : IDisposable
|
||||
|
||||
public void WriteOutFullCsv()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new();
|
||||
foreach (var entry in FileCaches.OrderBy(f => f.Value.PrefixedFilePath))
|
||||
{
|
||||
sb.AppendLine(entry.Value.CsvEntry);
|
||||
@@ -91,9 +91,9 @@ public class FileCacheManager : IDisposable
|
||||
|
||||
public FileCache? GetFileCacheByHash(string hash)
|
||||
{
|
||||
if (FileCaches.Any(f => f.Value.Hash == hash))
|
||||
if (FileCaches.Any(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal)))
|
||||
{
|
||||
return GetValidatedFileCache(FileCaches.FirstOrDefault(f => f.Value.Hash == hash).Value);
|
||||
return GetValidatedFileCache(FileCaches.FirstOrDefault(f => string.Equals(f.Value.Hash, hash, StringComparison.Ordinal)).Value);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -107,7 +107,7 @@ public class FileCacheManager : IDisposable
|
||||
{
|
||||
return (FileState.RequireDeletion, fileCache);
|
||||
}
|
||||
if (fi.LastWriteTimeUtc.Ticks.ToString() != fileCache.LastModifiedDateTicks)
|
||||
if (!string.Equals(fi.LastWriteTimeUtc.Ticks.ToString(CultureInfo.InvariantCulture), fileCache.LastModifiedDateTicks, StringComparison.Ordinal))
|
||||
{
|
||||
return (FileState.RequireUpdate, fileCache);
|
||||
}
|
||||
@@ -117,8 +117,8 @@ public class FileCacheManager : IDisposable
|
||||
|
||||
public FileCache? GetFileCacheByPath(string path)
|
||||
{
|
||||
var cleanedPath = path.Replace("/", "\\").ToLowerInvariant().Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), "");
|
||||
var entry = FileCaches.FirstOrDefault(f => f.Value.ResolvedFilepath.EndsWith(cleanedPath)).Value;
|
||||
var cleanedPath = path.Replace("/", "\\", StringComparison.Ordinal).ToLowerInvariant().Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), "", StringComparison.Ordinal);
|
||||
var entry = FileCaches.FirstOrDefault(f => f.Value.ResolvedFilepath.EndsWith(cleanedPath, StringComparison.Ordinal)).Value;
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
@@ -137,9 +137,9 @@ public class FileCacheManager : IDisposable
|
||||
FileInfo fi = new(path);
|
||||
if (!fi.Exists) return null;
|
||||
var fullName = fi.FullName.ToLowerInvariant();
|
||||
if (!fullName.Contains(_configuration.CacheFolder.ToLowerInvariant())) return null;
|
||||
string prefixedPath = fullName.Replace(_configuration.CacheFolder.ToLowerInvariant(), CachePrefix + "\\").Replace("\\\\", "\\");
|
||||
return CreateFileCacheEntity(fi, prefixedPath, fi.Name.ToUpper());
|
||||
if (!fullName.Contains(_configuration.CacheFolder.ToLowerInvariant(), StringComparison.Ordinal)) return null;
|
||||
string prefixedPath = fullName.Replace(_configuration.CacheFolder.ToLowerInvariant(), CachePrefix + "\\", StringComparison.Ordinal).Replace("\\\\", "\\", StringComparison.Ordinal);
|
||||
return CreateFileCacheEntity(fi, prefixedPath, fi.Name.ToUpper(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
public FileCache? CreateFileEntry(string path)
|
||||
@@ -148,8 +148,8 @@ public class FileCacheManager : IDisposable
|
||||
FileInfo fi = new(path);
|
||||
if (!fi.Exists) return null;
|
||||
var fullName = fi.FullName.ToLowerInvariant();
|
||||
if (!fullName.Contains(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant())) return null;
|
||||
string prefixedPath = fullName.Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), PenumbraPrefix + "\\").Replace("\\\\", "\\");
|
||||
if (!fullName.Contains(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), StringComparison.Ordinal)) return null;
|
||||
string prefixedPath = fullName.Replace(_ipcManager.PenumbraModDirectory()!.ToLowerInvariant(), PenumbraPrefix + "\\", StringComparison.Ordinal).Replace("\\\\", "\\", StringComparison.Ordinal);
|
||||
return CreateFileCacheEntity(fi, prefixedPath);
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ public class FileCacheManager : IDisposable
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file.LastWriteTimeUtc.Ticks.ToString() != fileCache.LastModifiedDateTicks)
|
||||
if (!string.Equals(file.LastWriteTimeUtc.Ticks.ToString(), fileCache.LastModifiedDateTicks, StringComparison.Ordinal))
|
||||
{
|
||||
UpdateHash(fileCache);
|
||||
}
|
||||
@@ -211,13 +211,13 @@ public class FileCacheManager : IDisposable
|
||||
|
||||
private FileCache ReplacePathPrefixes(FileCache fileCache)
|
||||
{
|
||||
if (fileCache.PrefixedFilePath.StartsWith(PenumbraPrefix))
|
||||
if (fileCache.PrefixedFilePath.StartsWith(PenumbraPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(PenumbraPrefix, _ipcManager.PenumbraModDirectory()));
|
||||
fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(PenumbraPrefix, _ipcManager.PenumbraModDirectory(), StringComparison.Ordinal));
|
||||
}
|
||||
else if (fileCache.PrefixedFilePath.StartsWith(CachePrefix))
|
||||
else if (fileCache.PrefixedFilePath.StartsWith(CachePrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(CachePrefix, _configuration.CacheFolder));
|
||||
fileCache.SetResolvedFilePath(fileCache.PrefixedFilePath.Replace(CachePrefix, _configuration.CacheFolder, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
return fileCache;
|
||||
|
||||
@@ -20,7 +20,7 @@ public class PeriodicFileScanner : IDisposable
|
||||
private readonly DalamudUtil _dalamudUtil;
|
||||
private CancellationTokenSource? _scanCancellationTokenSource;
|
||||
private Task? _fileScannerTask = null;
|
||||
public ConcurrentDictionary<string, int> haltScanLocks = new();
|
||||
public ConcurrentDictionary<string, int> haltScanLocks = new(StringComparer.Ordinal);
|
||||
public PeriodicFileScanner(IpcManager ipcManager, Configuration pluginConfiguration, FileCacheManager fileDbManager, ApiController apiController, DalamudUtil dalamudUtil)
|
||||
{
|
||||
Logger.Verbose("Creating " + nameof(PeriodicFileScanner));
|
||||
@@ -128,7 +128,7 @@ public class PeriodicFileScanner : IDisposable
|
||||
{
|
||||
while (haltScanLocks.Any(f => f.Value > 0))
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
isForced |= RecalculateFileCacheSize();
|
||||
@@ -144,7 +144,7 @@ public class PeriodicFileScanner : IDisposable
|
||||
_timeUntilNextScan = TimeSpan.FromSeconds(timeBetweenScans);
|
||||
while (_timeUntilNextScan.TotalSeconds >= 0)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), token);
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false);
|
||||
_timeUntilNextScan -= TimeSpan.FromSeconds(1);
|
||||
}
|
||||
}
|
||||
@@ -206,11 +206,14 @@ public class PeriodicFileScanner : IDisposable
|
||||
|
||||
var scannedFiles = new ConcurrentDictionary<string, bool>(Directory.EnumerateFiles(penumbraDir, "*.*", SearchOption.AllDirectories)
|
||||
.Select(s => s.ToLowerInvariant())
|
||||
.Where(f => ext.Any(e => f.EndsWith(e)) && !f.Contains(@"\bg\") && !f.Contains(@"\bgcommon\") && !f.Contains(@"\ui\"))
|
||||
.Where(f => ext.Any(e => f.EndsWith(e, StringComparison.OrdinalIgnoreCase))
|
||||
&& !f.Contains(@"\bg\", StringComparison.OrdinalIgnoreCase)
|
||||
&& !f.Contains(@"\bgcommon\", StringComparison.OrdinalIgnoreCase)
|
||||
&& !f.Contains(@"\ui\", StringComparison.OrdinalIgnoreCase))
|
||||
.Concat(Directory.EnumerateFiles(_pluginConfiguration.CacheFolder, "*.*", SearchOption.TopDirectoryOnly)
|
||||
.Where(f => new FileInfo(f).Name.Length == 40)
|
||||
.Select(s => s.ToLowerInvariant()).ToList())
|
||||
.Select(c => new KeyValuePair<string, bool>(c, false)));
|
||||
.Select(c => new KeyValuePair<string, bool>(c, false)), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
TotalFiles = scannedFiles.Count;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public class CachedPlayer
|
||||
if (characterData.GetHashCode() == _cachedData.GetHashCode()) return;
|
||||
|
||||
bool updateModdedPaths = false;
|
||||
List<ObjectKind> charaDataToUpdate = new List<ObjectKind>();
|
||||
List<ObjectKind> charaDataToUpdate = new();
|
||||
foreach (var objectKind in Enum.GetValues<ObjectKind>())
|
||||
{
|
||||
_cachedData.FileReplacements.TryGetValue(objectKind, out var existingFileReplacements);
|
||||
@@ -108,7 +108,7 @@ public class CachedPlayer
|
||||
|
||||
if (hasNewAndOldGlamourerData)
|
||||
{
|
||||
bool glamourerDataDifferent = _cachedData.GlamourerData[objectKind] != characterData.GlamourerData[objectKind];
|
||||
bool glamourerDataDifferent = !string.Equals(_cachedData.GlamourerData[objectKind], characterData.GlamourerData[objectKind], StringComparison.Ordinal);
|
||||
if (glamourerDataDifferent)
|
||||
{
|
||||
Logger.Debug("Updating " + objectKind);
|
||||
@@ -159,7 +159,7 @@ public class CachedPlayer
|
||||
Logger.Debug("Downloading missing files for player " + PlayerName + ", kind: " + objectKind);
|
||||
if (toDownloadReplacements.Any())
|
||||
{
|
||||
await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken);
|
||||
await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken).ConfigureAwait(false);
|
||||
_apiController.CancelDownload(downloadId);
|
||||
}
|
||||
if (downloadToken.IsCancellationRequested)
|
||||
@@ -168,7 +168,7 @@ public class CachedPlayer
|
||||
return;
|
||||
}
|
||||
|
||||
if ((TryCalculateModdedDictionary(out moddedPaths)).All(c => _apiController.ForbiddenTransfers.Any(f => f.Hash == c.Hash)))
|
||||
if ((TryCalculateModdedDictionary(out moddedPaths)).All(c => _apiController.ForbiddenTransfers.Any(f => string.Equals(f.Hash, c.Hash, StringComparison.Ordinal))))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -195,7 +195,7 @@ public class CachedPlayer
|
||||
private List<FileReplacementDto> TryCalculateModdedDictionary(out Dictionary<string, string> moddedDictionary)
|
||||
{
|
||||
List<FileReplacementDto> missingFiles = new();
|
||||
moddedDictionary = new Dictionary<string, string>();
|
||||
moddedDictionary = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
try
|
||||
{
|
||||
foreach (var item in _cachedData.FileReplacements.SelectMany(k => k.Value.Where(v => string.IsNullOrEmpty(v.FileSwapPath))).ToList())
|
||||
@@ -454,7 +454,7 @@ public class CachedPlayer
|
||||
private void IpcManagerOnPenumbraRedrawEvent(IntPtr address, int idx)
|
||||
{
|
||||
var player = _dalamudUtil.GetCharacterFromObjectTableByIndex(idx);
|
||||
if (player == null || player.Name.ToString() != PlayerName) return;
|
||||
if (player == null || !string.Equals(player.Name.ToString(), PlayerName, StringComparison.OrdinalIgnoreCase)) return;
|
||||
if (!_penumbraRedrawEventTask?.IsCompleted ?? false) return;
|
||||
|
||||
_penumbraRedrawEventTask = Task.Run(() =>
|
||||
|
||||
@@ -158,7 +158,7 @@ public class IpcManager : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
return _heelsGetApiVersion.InvokeFunc() == "1.0.1";
|
||||
return string.Equals(_heelsGetApiVersion.InvokeFunc(), "1.0.1", StringComparison.Ordinal);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -19,8 +19,8 @@ public class OnlinePlayerManager : IDisposable
|
||||
private readonly IpcManager _ipcManager;
|
||||
private readonly PlayerManager _playerManager;
|
||||
private readonly FileCacheManager _fileDbManager;
|
||||
private readonly ConcurrentDictionary<string, CachedPlayer> _onlineCachedPlayers = new();
|
||||
private readonly ConcurrentDictionary<string, CharacterCacheDto> _temporaryStoredCharacterCache = new();
|
||||
private readonly ConcurrentDictionary<string, CachedPlayer> _onlineCachedPlayers = new(StringComparer.Ordinal);
|
||||
private readonly ConcurrentDictionary<string, CharacterCacheDto> _temporaryStoredCharacterCache = new(StringComparer.Ordinal);
|
||||
private readonly ConcurrentDictionary<CachedPlayer, CancellationTokenSource> _playerTokenDisposal = new();
|
||||
|
||||
private List<string> OnlineVisiblePlayerHashes => _onlineCachedPlayers.Select(p => p.Value).Where(p => p.PlayerCharacter != IntPtr.Zero)
|
||||
@@ -226,7 +226,7 @@ public class OnlinePlayerManager : IDisposable
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await _apiController.PushCharacterData(_playerManager.LastCreatedCharacterData,
|
||||
visiblePlayers);
|
||||
visiblePlayers).ConfigureAwait(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class PlayerManager : IDisposable
|
||||
private CancellationTokenSource? _playerChangedCts = new();
|
||||
private CancellationTokenSource _transientUpdateCts = new();
|
||||
|
||||
private List<PlayerRelatedObject> playerRelatedObjects = new List<PlayerRelatedObject>();
|
||||
private List<PlayerRelatedObject> playerRelatedObjects = new();
|
||||
|
||||
public unsafe PlayerManager(ApiController apiController, IpcManager ipcManager,
|
||||
CharacterDataFactory characterDataFactory, DalamudUtil dalamudUtil, TransientResourceManager transientResourceManager,
|
||||
@@ -88,7 +88,7 @@ public class PlayerManager : IDisposable
|
||||
Task.Run(async () =>
|
||||
{
|
||||
Logger.Debug("Delaying transient resource load update");
|
||||
await Task.Delay(750, token);
|
||||
await Task.Delay(750, token).ConfigureAwait(false);
|
||||
if (obj.HasUnprocessedUpdate || token.IsCancellationRequested) return;
|
||||
Logger.Debug("Firing transient resource load update");
|
||||
obj.HasTransientsUpdate = true;
|
||||
@@ -169,7 +169,7 @@ public class PlayerManager : IDisposable
|
||||
while (!PermanentDataCache.IsReady && !token.IsCancellationRequested)
|
||||
{
|
||||
Logger.Verbose("Waiting until cache is ready");
|
||||
await Task.Delay(50, token);
|
||||
await Task.Delay(50, token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested) return null;
|
||||
@@ -215,7 +215,7 @@ public class PlayerManager : IDisposable
|
||||
var token = _playerChangedCts.Token;
|
||||
|
||||
// fix for redraw from anamnesis
|
||||
while ((!_dalamudUtil.IsPlayerPresent || _dalamudUtil.PlayerName == "--") && !token.IsCancellationRequested)
|
||||
while ((!_dalamudUtil.IsPlayerPresent || string.Equals(_dalamudUtil.PlayerName, "--", StringComparison.Ordinal)) && !token.IsCancellationRequested)
|
||||
{
|
||||
Logger.Debug("Waiting Until Player is Present");
|
||||
Thread.Sleep(100);
|
||||
@@ -244,7 +244,7 @@ public class PlayerManager : IDisposable
|
||||
_dalamudUtil.WaitWhileCharacterIsDrawing("self " + item.ObjectKind.ToString(), item.Address, 10000, token);
|
||||
}
|
||||
|
||||
cacheDto = (await CreateFullCharacterCacheDto(token));
|
||||
cacheDto = (await CreateFullCharacterCacheDto(token).ConfigureAwait(false));
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
|
||||
@@ -82,7 +82,7 @@ public class TransientResourceManager : IDisposable
|
||||
|
||||
private void Manager_PenumbraResourceLoadEvent(IntPtr gameObject, string gamePath, string filePath)
|
||||
{
|
||||
if (!FileTypesToHandle.Any(type => gamePath.ToLowerInvariant().EndsWith(type)))
|
||||
if (!FileTypesToHandle.Any(type => gamePath.EndsWith(type, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -93,25 +93,25 @@ public class TransientResourceManager : IDisposable
|
||||
|
||||
if (!TransientResources.ContainsKey(gameObject))
|
||||
{
|
||||
TransientResources[gameObject] = new();
|
||||
TransientResources[gameObject] = new(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (filePath.StartsWith("|"))
|
||||
if (filePath.StartsWith("|", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
filePath = filePath.Split("|")[2];
|
||||
}
|
||||
|
||||
filePath = filePath.ToLowerInvariant().Replace("\\", "/");
|
||||
filePath = filePath.ToLowerInvariant().Replace("\\", "/", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var replacedGamePath = gamePath.ToLowerInvariant().Replace("\\", "/");
|
||||
var replacedGamePath = gamePath.ToLowerInvariant().Replace("\\", "/", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (TransientResources[gameObject].Contains(replacedGamePath) ||
|
||||
SemiTransientResources.Any(r => r.Value.Any(f => f.GamePaths.First().ToLowerInvariant() == replacedGamePath
|
||||
&& f.ResolvedPath.ToLowerInvariant() == filePath)))
|
||||
SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath , StringComparison.OrdinalIgnoreCase)
|
||||
&& string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase))))
|
||||
{
|
||||
Logger.Debug("Not adding " + replacedGamePath + ":" + filePath);
|
||||
Logger.Verbose("SemiTransientAny: " + SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase) && string.Equals(f.ResolvedPath.ToLowerInvariant(), filePath, StringComparison.OrdinalIgnoreCase))).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath));
|
||||
&& f.ResolvedPath.ToLowerInvariant() == filePath)).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath));
|
||||
Logger.Verbose("SemiTransientAny: " + SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase)
|
||||
&& string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase))).ToString() + ", TransientAny: " + TransientResources[gameObject].Contains(replacedGamePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -125,7 +125,7 @@ public class TransientResourceManager : IDisposable
|
||||
{
|
||||
if (TransientResources.ContainsKey(gameObject))
|
||||
{
|
||||
TransientResources[gameObject].RemoveWhere(f => fileReplacement.GamePaths.Any(g => g.ToLowerInvariant() == f.ToLowerInvariant()));
|
||||
TransientResources[gameObject].RemoveWhere(f => fileReplacement.GamePaths.Any(g => string.Equals(g, f, StringComparison.OrdinalIgnoreCase)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,11 +145,11 @@ public class TransientResourceManager : IDisposable
|
||||
Logger.Debug("Persisting " + transientResources.Count + " transient resources");
|
||||
foreach (var gamePath in transientResources)
|
||||
{
|
||||
var existingResource = SemiTransientResources[objectKind].Any(f => f.GamePaths.First().ToLowerInvariant() == gamePath.ToLowerInvariant());
|
||||
var existingResource = SemiTransientResources[objectKind].Any(f => string.Equals(f.GamePaths.First(), gamePath, StringComparison.OrdinalIgnoreCase));
|
||||
if (existingResource)
|
||||
{
|
||||
Logger.Debug("Semi Transient resource replaced: " + gamePath);
|
||||
SemiTransientResources[objectKind].RemoveWhere(f => f.GamePaths.First().ToLowerInvariant() == gamePath.ToLowerInvariant());
|
||||
SemiTransientResources[objectKind].RemoveWhere(f => string.Equals(f.GamePaths.First(), gamePath, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
try
|
||||
@@ -196,7 +196,7 @@ public class TransientResourceManager : IDisposable
|
||||
SemiTransientResources[objectKind] = new HashSet<FileReplacement>();
|
||||
}
|
||||
|
||||
if (!SemiTransientResources[objectKind].Any(f => f.ResolvedPath.ToLowerInvariant() == item.ResolvedPath.ToLowerInvariant()))
|
||||
if (!SemiTransientResources[objectKind].Any(f => string.Equals(f.ResolvedPath, item.ResolvedPath, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
SemiTransientResources[objectKind].Add(item);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.8" />
|
||||
<PackageReference Include="lz4net" Version="1.0.15.93" />
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="1.0.733">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -86,4 +90,8 @@
|
||||
<EmbeddedResource Include="Localization\fr.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -31,10 +31,10 @@ public class CharacterData
|
||||
|
||||
if (!FileReplacements.ContainsKey(objectKind)) FileReplacements.Add(objectKind, new List<FileReplacement>());
|
||||
|
||||
var existingReplacement = FileReplacements[objectKind].SingleOrDefault(f => f.ResolvedPath == fileReplacement.ResolvedPath);
|
||||
var existingReplacement = FileReplacements[objectKind].SingleOrDefault(f => string.Equals(f.ResolvedPath, fileReplacement.ResolvedPath, System.StringComparison.OrdinalIgnoreCase));
|
||||
if (existingReplacement != null)
|
||||
{
|
||||
existingReplacement.GamePaths.AddRange(fileReplacement.GamePaths.Where(e => !existingReplacement.GamePaths.Contains(e)));
|
||||
existingReplacement.GamePaths.AddRange(fileReplacement.GamePaths.Where(e => !existingReplacement.GamePaths.Contains(e, System.StringComparer.OrdinalIgnoreCase)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -44,11 +44,11 @@ public class CharacterData
|
||||
|
||||
public CharacterCacheDto ToCharacterCacheDto()
|
||||
{
|
||||
var fileReplacements = FileReplacements.ToDictionary(k => k.Key, k => k.Value.Where(f => f.HasFileReplacement && !f.IsFileSwap).GroupBy(f => f.Hash).Select(g =>
|
||||
var fileReplacements = FileReplacements.ToDictionary(k => k.Key, k => k.Value.Where(f => f.HasFileReplacement && !f.IsFileSwap).GroupBy(f => f.Hash, System.StringComparer.OrdinalIgnoreCase).Select(g =>
|
||||
{
|
||||
return new FileReplacementDto()
|
||||
{
|
||||
GamePaths = g.SelectMany(f => f.GamePaths).Distinct().ToArray(),
|
||||
GamePaths = g.SelectMany(f => f.GamePaths).Distinct(System.StringComparer.OrdinalIgnoreCase).ToArray(),
|
||||
Hash = g.First().Hash,
|
||||
};
|
||||
}).ToList());
|
||||
|
||||
@@ -21,9 +21,9 @@ public class FileReplacement
|
||||
|
||||
public List<string> GamePaths { get; set; } = new();
|
||||
|
||||
public bool HasFileReplacement => GamePaths.Count >= 1 && GamePaths.Any(p => p != ResolvedPath);
|
||||
public bool HasFileReplacement => GamePaths.Count >= 1 && GamePaths.Any(p => !string.Equals(p, ResolvedPath, System.StringComparison.Ordinal));
|
||||
|
||||
public bool IsFileSwap => !Regex.IsMatch(ResolvedPath, @"^[a-zA-Z]:(/|\\)", RegexOptions.ECMAScript) && GamePaths.First() != ResolvedPath;
|
||||
public bool IsFileSwap => !Regex.IsMatch(ResolvedPath, @"^[a-zA-Z]:(/|\\)", RegexOptions.ECMAScript) && !string.Equals(GamePaths.First(), ResolvedPath, System.StringComparison.Ordinal);
|
||||
|
||||
public string Hash { get; set; } = string.Empty;
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ public class PlayerRelatedObject
|
||||
bool equip = CompareAndUpdateByteData(chara->EquipSlotData, chara->CustomizeData);
|
||||
bool drawObj = (IntPtr)chara->GameObject.DrawObject != DrawObjectAddress;
|
||||
var name = new Utf8String(chara->GameObject.Name).ToString();
|
||||
bool nameChange = (name != _name);
|
||||
bool nameChange = (!string.Equals(name, _name, StringComparison.Ordinal));
|
||||
if (addr || equip || drawObj || nameChange)
|
||||
{
|
||||
_name = name;
|
||||
|
||||
@@ -175,7 +175,7 @@ public sealed class Plugin : IDalamudPlugin
|
||||
{
|
||||
while (!_dalamudUtil.IsPlayerPresent)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
@@ -20,7 +21,7 @@ public class CompactUi : Window, IDisposable
|
||||
{
|
||||
private readonly ApiController _apiController;
|
||||
private readonly Configuration _configuration;
|
||||
public readonly Dictionary<string, bool> ShowUidForEntry = new();
|
||||
public readonly Dictionary<string, bool> ShowUidForEntry = new(StringComparer.Ordinal);
|
||||
private readonly UiShared _uiShared;
|
||||
private readonly WindowSystem _windowSystem;
|
||||
private string _characterOrCommentFilter = string.Empty;
|
||||
@@ -162,7 +163,7 @@ public class CompactUi : Window, IDisposable
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - buttonSize.X);
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
|
||||
{
|
||||
if (_apiController.PairedClients.All(w => w.OtherUID != _pairToAdd))
|
||||
if (_apiController.PairedClients.All(w => !string.Equals(w.OtherUID, _pairToAdd, StringComparison.Ordinal)))
|
||||
{
|
||||
_ = _apiController.SendPairedClientAddition(_pairToAdd);
|
||||
_pairToAdd = string.Empty;
|
||||
@@ -316,7 +317,7 @@ public class CompactUi : Window, IDisposable
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (EditNickEntry != entry.OtherUID)
|
||||
if (!string.Equals(EditNickEntry, entry.OtherUID, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont);
|
||||
@@ -415,7 +416,7 @@ public class CompactUi : Window, IDisposable
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private IEnumerable<ClientPairDto> GetFilteredUsers()
|
||||
{
|
||||
@@ -424,17 +425,23 @@ public class CompactUi : Window, IDisposable
|
||||
if (_characterOrCommentFilter.IsNullOrEmpty()) return true;
|
||||
_configuration.GetCurrentServerUidComments().TryGetValue(p.OtherUID, out var comment);
|
||||
var uid = p.VanityUID.IsNullOrEmpty() ? p.OtherUID : p.VanityUID;
|
||||
return uid.ToLowerInvariant().Contains(_characterOrCommentFilter.ToLowerInvariant()) ||
|
||||
(comment?.ToLowerInvariant().Contains(_characterOrCommentFilter.ToLowerInvariant()) ?? false);
|
||||
return uid.Contains(_characterOrCommentFilter, StringComparison.OrdinalIgnoreCase) ||
|
||||
(comment?.Contains(_characterOrCommentFilter, StringComparison.OrdinalIgnoreCase) ?? false);
|
||||
});
|
||||
}
|
||||
|
||||
private void DrawServerStatus()
|
||||
{
|
||||
var buttonSize = UiShared.GetIconButtonSize(FontAwesomeIcon.Link);
|
||||
var userCount = _apiController.OnlineUsers.ToString();
|
||||
var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture);
|
||||
var userSize = ImGui.CalcTextSize(userCount);
|
||||
var textSize = ImGui.CalcTextSize("Users Online");
|
||||
#if DEBUG
|
||||
string shardConnection = $"Connected shard: {_apiController.ServerInfo.ShardName}";
|
||||
#else
|
||||
string shardConnection = string.Equals(_apiController.ServerInfo.ShardName, "Main", StringComparison.OrdinalIgnoreCase) ? string.Empty : $"Connected shard: {_apiController.ServerInfo.ShardName}";
|
||||
#endif
|
||||
var shardTextSize = ImGui.CalcTextSize(shardConnection);
|
||||
|
||||
if (_apiController.ServerState is ServerState.Connected)
|
||||
{
|
||||
@@ -444,6 +451,11 @@ public class CompactUi : Window, IDisposable
|
||||
ImGui.SameLine();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.Text("Users Online");
|
||||
ImGui.AlignTextToFramePadding();
|
||||
if (!string.IsNullOrEmpty(shardConnection))
|
||||
{
|
||||
ImGui.TextUnformatted(shardConnection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace MareSynchronos.UI
|
||||
private Configuration _configuration;
|
||||
private ApiController _apiController;
|
||||
|
||||
private readonly Dictionary<string, bool> _showGidForEntry = new();
|
||||
private readonly Dictionary<string, bool> _showGidForEntry = new(StringComparer.Ordinal);
|
||||
private string _editGroupEntry = string.Empty;
|
||||
private string _editGroupComment = string.Empty;
|
||||
private string _syncShellPassword = string.Empty;
|
||||
@@ -33,7 +33,7 @@ namespace MareSynchronos.UI
|
||||
private bool _errorGroupJoin;
|
||||
private bool _errorGroupCreate = false;
|
||||
private GroupCreatedDto? _lastCreatedGroup = null;
|
||||
private Dictionary<string, bool> ExpandedGroupState = new Dictionary<string, bool>();
|
||||
private readonly Dictionary<string, bool> ExpandedGroupState = new(StringComparer.Ordinal);
|
||||
|
||||
public GroupPanel(CompactUi mainUi, UiShared uiShared, Configuration configuration, ApiController apiController)
|
||||
{
|
||||
@@ -56,23 +56,35 @@ namespace MareSynchronos.UI
|
||||
ImGui.SetNextItemWidth(UiShared.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X - buttonSize.X);
|
||||
ImGui.InputTextWithHint("##syncshellid", "Syncshell GID/Alias", ref _syncShellToJoin, 20);
|
||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiShared.GetWindowContentRegionWidth() - buttonSize.X);
|
||||
|
||||
bool userCanJoinMoreGroups = _apiController.Groups.Count < _apiController.ServerInfo.MaxGroupsJoinedByUser;
|
||||
bool userCanCreateMoreGroups = _apiController.Groups.Count(u => string.Equals(u.OwnedBy, _apiController.UID, StringComparison.Ordinal)) < _apiController.ServerInfo.MaxGroupsCreatedByUser;
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
|
||||
{
|
||||
if (_apiController.Groups.All(w => w.GID != _syncShellToJoin) && !string.IsNullOrEmpty(_syncShellToJoin))
|
||||
if (_apiController.Groups.All(w => !string.Equals(w.GID, _syncShellToJoin, StringComparison.Ordinal)) && !string.IsNullOrEmpty(_syncShellToJoin))
|
||||
{
|
||||
_errorGroupJoin = false;
|
||||
_showModalEnterPassword = true;
|
||||
ImGui.OpenPopup("Enter Syncshell Password");
|
||||
if (userCanJoinMoreGroups)
|
||||
{
|
||||
_errorGroupJoin = false;
|
||||
_showModalEnterPassword = true;
|
||||
ImGui.OpenPopup("Enter Syncshell Password");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastCreatedGroup = null;
|
||||
_errorGroupCreate = false;
|
||||
_showModalCreateGroup = true;
|
||||
ImGui.OpenPopup("Create Syncshell");
|
||||
if (userCanCreateMoreGroups)
|
||||
{
|
||||
_lastCreatedGroup = null;
|
||||
_errorGroupCreate = false;
|
||||
_showModalCreateGroup = true;
|
||||
ImGui.OpenPopup("Create Syncshell");
|
||||
}
|
||||
}
|
||||
}
|
||||
UiShared.AttachToolTip(_syncShellToJoin.IsNullOrEmpty() ? "Create Syncshell" : "Join Syncshell" + _syncShellToJoin);
|
||||
UiShared.AttachToolTip(_syncShellToJoin.IsNullOrEmpty()
|
||||
? (userCanCreateMoreGroups ? "Create Syncshell" : $"You cannot create more than {_apiController.ServerInfo.MaxGroupsCreatedByUser} Syncshells")
|
||||
: (userCanJoinMoreGroups ? "Join Syncshell" + _syncShellToJoin : $"You cannot join more than {_apiController.ServerInfo.MaxGroupsJoinedByUser} Syncshells"));
|
||||
|
||||
if (ImGui.BeginPopupModal("Enter Syncshell Password", ref _showModalEnterPassword, ImGuiWindowFlags.AlwaysAutoResize))
|
||||
{
|
||||
@@ -82,7 +94,8 @@ namespace MareSynchronos.UI
|
||||
ImGui.InputTextWithHint("##password", _syncShellToJoin + " Password", ref _syncShellPassword, 255, ImGuiInputTextFlags.Password);
|
||||
if (_errorGroupJoin)
|
||||
{
|
||||
UiShared.ColorTextWrapped("An error occured during joining of this Syncshell: you either have joined the maximum amount of Syncshells (6), it does not exist, the password you entered is wrong, you already joined the Syncshell, the Syncshell is full (100 users) or the Syncshell has closed invites.",
|
||||
UiShared.ColorTextWrapped($"An error occured during joining of this Syncshell: you either have joined the maximum amount of Syncshells ({_apiController.ServerInfo.MaxGroupsJoinedByUser}), " +
|
||||
$"it does not exist, the password you entered is wrong, you already joined the Syncshell, the Syncshell is full ({_apiController.ServerInfo.MaxGroupUserCount} users) or the Syncshell has closed invites.",
|
||||
new Vector4(1, 0, 0, 1));
|
||||
}
|
||||
if (ImGui.Button("Join " + _syncShellToJoin))
|
||||
@@ -141,7 +154,6 @@ namespace MareSynchronos.UI
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
|
||||
ImGuiHelpers.ScaledDummy(2);
|
||||
}
|
||||
|
||||
@@ -161,7 +173,7 @@ namespace MareSynchronos.UI
|
||||
private void DrawSyncshell(GroupDto group)
|
||||
{
|
||||
var name = group.Alias ?? group.GID;
|
||||
var pairsInGroup = _apiController.GroupPairedClients.Where(p => p.GroupGID == group.GID).ToList();
|
||||
var pairsInGroup = _apiController.GroupPairedClients.Where(p => string.Equals(p.GroupGID, group.GID, StringComparison.Ordinal)).ToList();
|
||||
if (!ExpandedGroupState.TryGetValue(group.GID, out bool isExpanded))
|
||||
{
|
||||
isExpanded = false;
|
||||
@@ -188,7 +200,7 @@ namespace MareSynchronos.UI
|
||||
var groupName = group.Alias ?? group.GID;
|
||||
var textIsGid = true;
|
||||
|
||||
if (group.OwnedBy == _apiController.UID)
|
||||
if (string.Equals(group.OwnedBy, _apiController.UID, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.Text(FontAwesomeIcon.Crown.ToIconString());
|
||||
@@ -207,7 +219,7 @@ namespace MareSynchronos.UI
|
||||
}
|
||||
}
|
||||
|
||||
if (_editGroupEntry != group.GID)
|
||||
if (!string.Equals(_editGroupEntry, group.GID, StringComparison.Ordinal))
|
||||
{
|
||||
if (textIsGid) ImGui.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TextUnformatted(groupName);
|
||||
@@ -258,12 +270,12 @@ namespace MareSynchronos.UI
|
||||
ImGui.Indent(collapseButton.X);
|
||||
if (ExpandedGroupState[group.GID])
|
||||
{
|
||||
pairsInGroup = pairsInGroup.OrderBy(p => p.UserUID == group.OwnedBy ? 0 : 1).ThenBy(p => p.IsPinned ?? false).ThenBy(p => p.UserAlias ?? p.UserUID).ToList();
|
||||
pairsInGroup = pairsInGroup.OrderBy(p => string.Equals(p.UserUID, group.OwnedBy, StringComparison.Ordinal) ? 0 : 1).ThenBy(p => p.IsPinned ?? false).ThenBy(p => p.UserAlias ?? p.UserUID).ToList();
|
||||
ImGui.Indent(ImGui.GetStyle().ItemSpacing.X / 2);
|
||||
ImGui.Separator();
|
||||
foreach (var pair in pairsInGroup)
|
||||
{
|
||||
UiShared.DrawWithID(group.GID + pair.UserUID, () => DrawSyncshellPairedClient(pair, group.OwnedBy == _apiController.UID, group?.IsPaused ?? false));
|
||||
UiShared.DrawWithID(group.GID + pair.UserUID, () => DrawSyncshellPairedClient(pair, string.Equals(group.OwnedBy, _apiController.UID, StringComparison.Ordinal), group?.IsPaused ?? false));
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
@@ -299,7 +311,7 @@ namespace MareSynchronos.UI
|
||||
_ = _apiController.SendLeaveGroup(entry.GID);
|
||||
}
|
||||
}
|
||||
UiShared.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (entry.OwnedBy != _apiController.UID ? string.Empty : Environment.NewLine
|
||||
UiShared.AttachToolTip("Hold CTRL and click to leave this Syncshell" + (!string.Equals(entry.OwnedBy, _apiController.UID, StringComparison.Ordinal) ? string.Empty : Environment.NewLine
|
||||
+ "WARNING: This action is irreverisble" + Environment.NewLine + "Leaving an owned Syncshell will transfer the ownership to a random person in the Syncshell."));
|
||||
|
||||
if (UiShared.IconTextButton(FontAwesomeIcon.Copy, "Copy ID"))
|
||||
@@ -308,7 +320,7 @@ namespace MareSynchronos.UI
|
||||
}
|
||||
UiShared.AttachToolTip("Copy Syncshell ID to Clipboard");
|
||||
|
||||
if (entry.OwnedBy == _apiController.UID)
|
||||
if (string.Equals(entry.OwnedBy, _apiController.UID, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.Separator();
|
||||
|
||||
@@ -428,7 +440,7 @@ namespace MareSynchronos.UI
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (_mainUi.EditNickEntry != entry.UserUID)
|
||||
if (!string.Equals(_mainUi.EditNickEntry, entry.UserUID, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.SetCursorPosY(textPos);
|
||||
if (textIsUid) ImGui.PushFont(UiBuilder.MonoFont);
|
||||
@@ -476,7 +488,7 @@ namespace MareSynchronos.UI
|
||||
UiShared.AttachToolTip("Hit ENTER to save\nRight click to cancel");
|
||||
}
|
||||
|
||||
bool plusButtonShown = !_apiController.PairedClients.Any(p => p.OtherUID == entry.UserUID);
|
||||
bool plusButtonShown = !_apiController.PairedClients.Any(p => string.Equals(p.OtherUID, entry.UserUID, StringComparison.Ordinal));
|
||||
|
||||
if (plusButtonShown)
|
||||
{
|
||||
|
||||
@@ -37,12 +37,12 @@ internal class IntroUi : Window, IDisposable
|
||||
private Task _timeoutTask;
|
||||
private string _timeoutTime;
|
||||
|
||||
private Dictionary<string, string> _languages = new() { { "English", "en" }, { "Deutsch", "de" }, { "Français", "fr" } };
|
||||
private Dictionary<string, string> _languages = new(StringComparer.Ordinal) { { "English", "en" }, { "Deutsch", "de" }, { "Français", "fr" } };
|
||||
private int _currentLanguage;
|
||||
|
||||
private bool DarkSoulsCaptchaValid => _darkSoulsCaptcha1.Item2 == _enteredDarkSoulsCaptcha1.Trim()
|
||||
&& _darkSoulsCaptcha2.Item2 == _enteredDarkSoulsCaptcha2.Trim()
|
||||
&& _darkSoulsCaptcha3.Item2 == _enteredDarkSoulsCaptcha3.Trim();
|
||||
private bool DarkSoulsCaptchaValid => string.Equals(_darkSoulsCaptcha1.Item2, _enteredDarkSoulsCaptcha1.Trim()
|
||||
, StringComparison.Ordinal) && string.Equals(_darkSoulsCaptcha2.Item2, _enteredDarkSoulsCaptcha2.Trim()
|
||||
, StringComparison.Ordinal) && string.Equals(_darkSoulsCaptcha3.Item2, _enteredDarkSoulsCaptcha3.Trim(), StringComparison.Ordinal);
|
||||
|
||||
|
||||
public void Dispose()
|
||||
@@ -158,7 +158,7 @@ internal class IntroUi : Window, IDisposable
|
||||
{
|
||||
_timeoutTime = $"{i}s " + Strings.ToS.RemainingLabel;
|
||||
Logger.Debug(_timeoutTime);
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -286,11 +286,11 @@ internal class IntroUi : Window, IDisposable
|
||||
|
||||
private Tuple<string, string> GetCaptchaTuple()
|
||||
{
|
||||
Random random = new Random();
|
||||
Random random = new();
|
||||
var paragraphIdx = random.Next(TosParagraphs.Length);
|
||||
var splitParagraph = TosParagraphs[paragraphIdx].Split(".", StringSplitOptions.RemoveEmptyEntries).Select(c => c.Trim()).ToArray();
|
||||
var sentenceIdx = random.Next(splitParagraph.Length);
|
||||
var splitSentence = splitParagraph[sentenceIdx].Split(" ").Select(c => c.Trim()).Select(c => c.Replace(".", "").Replace(",", "").Replace("'", "")).ToArray();
|
||||
var splitSentence = splitParagraph[sentenceIdx].Split(" ").Select(c => c.Trim()).Select(c => c.Replace(".", "", StringComparison.Ordinal).Replace(",", "", StringComparison.Ordinal).Replace("'", "", StringComparison.Ordinal)).ToArray();
|
||||
var wordIdx = random.Next(splitSentence.Length);
|
||||
return new($"{Strings.ToS.ParagraphLabel} {paragraphIdx + 1}, {Strings.ToS.SentenceLabel} {sentenceIdx + 1}, {Strings.ToS.WordLabel} {wordIdx + 1}", splitSentence[wordIdx]);
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ public class SettingsUi : Window, IDisposable
|
||||
});
|
||||
}
|
||||
ImGui.SameLine();
|
||||
if (onlineUser.UID != _apiController.UID && _apiController.IsAdmin)
|
||||
if (!string.Equals(onlineUser.UID, _apiController.UID, StringComparison.Ordinal) && _apiController.IsAdmin)
|
||||
{
|
||||
if (!onlineUser.IsModerator)
|
||||
{
|
||||
|
||||
@@ -294,7 +294,7 @@ public class UiShared : IDisposable
|
||||
bool isSelected = _serverSelectionIndex == i;
|
||||
if (ImGui.Selectable(comboEntries[i], isSelected))
|
||||
{
|
||||
_pluginConfiguration.ApiUri = _apiController.ServerDictionary.Single(k => k.Value == comboEntries[i]).Key;
|
||||
_pluginConfiguration.ApiUri = _apiController.ServerDictionary.Single(k => string.Equals(k.Value, comboEntries[i], StringComparison.Ordinal)).Key;
|
||||
_pluginConfiguration.Save();
|
||||
_ = _apiController.CreateConnections();
|
||||
}
|
||||
@@ -451,7 +451,7 @@ public class UiShared : IDisposable
|
||||
{
|
||||
if (!success) return;
|
||||
|
||||
_isPenumbraDirectory = path.ToLowerInvariant() == _ipcManager.PenumbraModDirectory()?.ToLowerInvariant();
|
||||
_isPenumbraDirectory = string.Equals(path.ToLowerInvariant(), _ipcManager.PenumbraModDirectory()?.ToLowerInvariant(), StringComparison.Ordinal);
|
||||
_isDirectoryWritable = IsDirectoryWritable(path);
|
||||
_cacheDirectoryHasOtherFilesThanCache = Directory.GetFiles(path, "*", SearchOption.AllDirectories).Any(f => new FileInfo(f).Name.Length != 40);
|
||||
_cacheDirectoryIsValidPath = Regex.IsMatch(path, @"^(?:[a-zA-Z]:\\[\w\s\-\\]+?|\/(?:[\w\s\-\/])+?)$", RegexOptions.ECMAScript);
|
||||
|
||||
@@ -11,24 +11,24 @@ public class Crypto
|
||||
public static string GetFileHash(string filePath)
|
||||
{
|
||||
using SHA1CryptoServiceProvider cryptoProvider = new();
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(File.ReadAllBytes(filePath))).Replace("-", "");
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(File.ReadAllBytes(filePath))).Replace("-", "", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static string GetHash(string stringToHash)
|
||||
{
|
||||
using SHA1CryptoServiceProvider cryptoProvider = new();
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", "");
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", "", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static string GetHash256(string stringToHash)
|
||||
{
|
||||
using SHA256CryptoServiceProvider cryptoProvider = new();
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", "");
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToHash))).Replace("-", "", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public static string GetHash256(PlayerCharacter character)
|
||||
{
|
||||
using SHA256CryptoServiceProvider cryptoProvider = new();
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(character.Name + character.HomeWorld.Id.ToString()))).Replace("-", "");
|
||||
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(character.Name + character.HomeWorld.Id.ToString()))).Replace("-", "", StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
26
MareSynchronos/Utils/DalamudLoggingProvider.cs
Normal file
26
MareSynchronos/Utils/DalamudLoggingProvider.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.Utils;
|
||||
|
||||
[ProviderAlias("Dalamud")]
|
||||
public class DalamudLoggingProvider : ILoggerProvider
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Logger> _loggers =
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public DalamudLoggingProvider()
|
||||
{
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return _loggers.GetOrAdd(categoryName, name => new Logger(categoryName));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loggers.Clear();
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public class DalamudUtil : IDisposable
|
||||
{
|
||||
return _objectTable.Where(obj =>
|
||||
obj.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player &&
|
||||
obj.Name.ToString() != PlayerName).Select(p => (PlayerCharacter)p).ToList();
|
||||
!string.Equals(obj.Name.ToString(), PlayerName, StringComparison.Ordinal)).Select(p => (PlayerCharacter)p).ToList();
|
||||
}
|
||||
|
||||
public Dalamud.Game.ClientState.Objects.Types.Character? GetCharacterFromObjectTableByIndex(int index)
|
||||
@@ -201,7 +201,7 @@ public class DalamudUtil : IDisposable
|
||||
foreach (var item in _objectTable)
|
||||
{
|
||||
if (item.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue;
|
||||
if (item.Name.ToString() == characterName) return (PlayerCharacter)item;
|
||||
if (string.Equals(item.Name.ToString(), characterName, StringComparison.Ordinal)) return (PlayerCharacter)item;
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -209,7 +209,7 @@ public class DalamudUtil : IDisposable
|
||||
|
||||
public async Task<T> RunOnFrameworkThread<T>(Func<T> func)
|
||||
{
|
||||
return await _framework.RunOnFrameworkThread(func);
|
||||
return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public unsafe void WaitWhileCharacterIsDrawing(string name, IntPtr characterAddress, int timeOut = 5000, CancellationToken? ct = null)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Utility;
|
||||
@@ -7,27 +6,6 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MareSynchronos.Utils;
|
||||
|
||||
[ProviderAlias("Dalamud")]
|
||||
public class DalamudLoggingProvider : ILoggerProvider
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Logger> _loggers =
|
||||
new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public DalamudLoggingProvider()
|
||||
{
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return _loggers.GetOrAdd(categoryName, name => new Logger(categoryName));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loggers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Logger : ILogger
|
||||
{
|
||||
private readonly string name;
|
||||
@@ -41,7 +19,7 @@ internal class Logger : ILogger
|
||||
public static void Debug(string debug, string stringToHighlight = "")
|
||||
{
|
||||
var caller = new StackTrace().GetFrame(1)?.GetMethod()?.ReflectedType?.Name ?? "Unknown";
|
||||
if (debug.Contains(stringToHighlight) && !stringToHighlight.IsNullOrEmpty())
|
||||
if (debug.Contains(stringToHighlight, StringComparison.Ordinal) && !stringToHighlight.IsNullOrEmpty())
|
||||
{
|
||||
PluginLog.Warning($"[{caller}] {debug}");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public static class VariousExtensions
|
||||
if (attribute?.InformationalVersion != null)
|
||||
{
|
||||
var value = attribute.InformationalVersion;
|
||||
var index = value.IndexOf(BuildVersionMetadataPrefix);
|
||||
var index = value.IndexOf(BuildVersionMetadataPrefix, StringComparison.Ordinal);
|
||||
if (index > 0)
|
||||
{
|
||||
value = value[(index + BuildVersionMetadataPrefix.Length)..];
|
||||
@@ -33,7 +33,7 @@ public partial class ApiController
|
||||
|
||||
public async Task DeleteAllMyFiles()
|
||||
{
|
||||
await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles);
|
||||
await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<string> DownloadFile(int downloadId, string hash, Uri downloadUri, CancellationToken ct)
|
||||
@@ -44,7 +44,7 @@ public partial class ApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
CurrentDownloads[downloadId].Single(f => f.Hash == hash).Transferred = e.BytesReceived;
|
||||
CurrentDownloads[downloadId].Single(f => string.Equals(f.Hash, hash, StringComparison.Ordinal)).Transferred = e.BytesReceived;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -61,11 +61,11 @@ public partial class ApiController
|
||||
|
||||
try
|
||||
{
|
||||
await wc.DownloadFileTaskAsync(downloadUri, fileName);
|
||||
await wc.DownloadFileTaskAsync(downloadUri, fileName).ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
|
||||
CurrentDownloads[downloadId].Single(f => f.Hash == hash).Transferred = CurrentDownloads[downloadId].Single(f => f.Hash == hash).Total;
|
||||
CurrentDownloads[downloadId].Single(f => string.Equals(f.Hash, hash, StringComparison.Ordinal)).Transferred = CurrentDownloads[downloadId].Single(f => string.Equals(f.Hash, hash, StringComparison.Ordinal)).Total;
|
||||
|
||||
wc.DownloadProgressChanged -= progChanged;
|
||||
return fileName;
|
||||
@@ -78,7 +78,7 @@ public partial class ApiController
|
||||
DownloadStarted?.Invoke();
|
||||
try
|
||||
{
|
||||
await DownloadFilesInternal(currentDownloadId, fileReplacementDto, ct);
|
||||
await DownloadFilesInternal(currentDownloadId, fileReplacementDto, ct).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -94,8 +94,8 @@ public partial class ApiController
|
||||
{
|
||||
Logger.Debug("Downloading files (Download ID " + currentDownloadId + ")");
|
||||
|
||||
List<DownloadFileDto> downloadFileInfoFromService = new List<DownloadFileDto>();
|
||||
downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync<List<DownloadFileDto>>(Api.InvokeGetFilesSizes, fileReplacementDto.Select(f => f.Hash).ToList(), ct));
|
||||
List<DownloadFileDto> downloadFileInfoFromService = new();
|
||||
downloadFileInfoFromService.AddRange(await _mareHub!.InvokeAsync<List<DownloadFileDto>>(Api.InvokeGetFilesSizes, fileReplacementDto.Select(f => f.Hash).ToList(), ct).ConfigureAwait(false));
|
||||
|
||||
Logger.Debug("Files with size 0 or less: " + string.Join(", ", downloadFileInfoFromService.Where(f => f.Size <= 0).Select(f => f.Hash)));
|
||||
|
||||
@@ -104,7 +104,7 @@ public partial class ApiController
|
||||
|
||||
foreach (var dto in downloadFileInfoFromService.Where(c => c.IsForbidden))
|
||||
{
|
||||
if (ForbiddenTransfers.All(f => f.Hash != dto.Hash))
|
||||
if (ForbiddenTransfers.All(f => !string.Equals(f.Hash, dto.Hash, StringComparison.Ordinal)))
|
||||
{
|
||||
ForbiddenTransfers.Add(new DownloadFileTransfer(dto));
|
||||
}
|
||||
@@ -118,7 +118,7 @@ public partial class ApiController
|
||||
async (file, token) =>
|
||||
{
|
||||
var hash = file.Hash;
|
||||
var tempFile = await DownloadFile(currentDownloadId, file.Hash, file.DownloadUri, token);
|
||||
var tempFile = await DownloadFile(currentDownloadId, file.Hash, file.DownloadUri, token).ConfigureAwait(false);
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
@@ -128,16 +128,16 @@ public partial class ApiController
|
||||
return;
|
||||
}
|
||||
|
||||
var tempFileData = await File.ReadAllBytesAsync(tempFile, token);
|
||||
var tempFileData = await File.ReadAllBytesAsync(tempFile, token).ConfigureAwait(false);
|
||||
var extractedFile = LZ4Codec.Unwrap(tempFileData);
|
||||
File.Delete(tempFile);
|
||||
var filePath = Path.Combine(_pluginConfiguration.CacheFolder, file.Hash);
|
||||
await File.WriteAllBytesAsync(filePath, extractedFile, token);
|
||||
await File.WriteAllBytesAsync(filePath, extractedFile, token).ConfigureAwait(false);
|
||||
var fi = new FileInfo(filePath);
|
||||
Func<DateTime> RandomDayFunc()
|
||||
{
|
||||
DateTime start = new DateTime(1995, 1, 1);
|
||||
Random gen = new Random();
|
||||
DateTime start = new(1995, 1, 1);
|
||||
Random gen = new();
|
||||
int range = (DateTime.Today - start).Days;
|
||||
return () => start.AddDays(gen.Next(range));
|
||||
}
|
||||
@@ -155,7 +155,7 @@ public partial class ApiController
|
||||
Logger.Warn(ex.Message);
|
||||
Logger.Warn(ex.StackTrace);
|
||||
}
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
Logger.Debug("Download complete, removing " + currentDownloadId);
|
||||
CancelDownload(currentDownloadId);
|
||||
@@ -163,7 +163,7 @@ public partial class ApiController
|
||||
|
||||
public async Task PushCharacterData(CharacterCacheDto character, List<string> visibleCharacterIds)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", StringComparison.Ordinal)) return;
|
||||
Logger.Debug("Sending Character data to service " + ApiUri);
|
||||
|
||||
CancelUpload();
|
||||
@@ -172,7 +172,7 @@ public partial class ApiController
|
||||
Logger.Verbose("New Token Created");
|
||||
|
||||
List<string> unverifiedUploadHashes = new();
|
||||
foreach (var item in character.FileReplacements.SelectMany(c => c.Value.Where(f => string.IsNullOrEmpty(f.FileSwapPath)).Select(v => v.Hash).Distinct()).Distinct().ToList())
|
||||
foreach (var item in character.FileReplacements.SelectMany(c => c.Value.Where(f => string.IsNullOrEmpty(f.FileSwapPath)).Select(v => v.Hash).Distinct(StringComparer.Ordinal)).Distinct(StringComparer.Ordinal).ToList())
|
||||
{
|
||||
if (!_verifiedUploadedHashes.Contains(item))
|
||||
{
|
||||
@@ -183,7 +183,7 @@ public partial class ApiController
|
||||
if (unverifiedUploadHashes.Any())
|
||||
{
|
||||
Logger.Debug("Verifying " + unverifiedUploadHashes.Count + " files");
|
||||
var filesToUpload = await _mareHub!.InvokeAsync<List<UploadFileDto>>(Api.InvokeFileSendFiles, unverifiedUploadHashes, uploadToken);
|
||||
var filesToUpload = await _mareHub!.InvokeAsync<List<UploadFileDto>>(Api.InvokeFileSendFiles, unverifiedUploadHashes, uploadToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var file in filesToUpload.Where(f => !f.IsForbidden))
|
||||
{
|
||||
@@ -203,7 +203,7 @@ public partial class ApiController
|
||||
|
||||
foreach (var file in filesToUpload.Where(c => c.IsForbidden))
|
||||
{
|
||||
if (ForbiddenTransfers.All(f => f.Hash != file.Hash))
|
||||
if (ForbiddenTransfers.All(f => !string.Equals(f.Hash, file.Hash, StringComparison.Ordinal)))
|
||||
{
|
||||
ForbiddenTransfers.Add(new UploadFileTransfer(file)
|
||||
{
|
||||
@@ -217,9 +217,9 @@ public partial class ApiController
|
||||
foreach (var file in CurrentUploads.Where(f => f.CanBeTransferred && !f.IsTransferred).ToList())
|
||||
{
|
||||
Logger.Debug("Compressing and uploading " + file);
|
||||
var data = await GetCompressedFileData(file.Hash, uploadToken);
|
||||
CurrentUploads.Single(e => e.Hash == data.Item1).Total = data.Item2.Length;
|
||||
await UploadFile(data.Item2, file.Hash, uploadToken);
|
||||
var data = await GetCompressedFileData(file.Hash, uploadToken).ConfigureAwait(false);
|
||||
CurrentUploads.Single(e => string.Equals(e.Hash, data.Item1, StringComparison.Ordinal)).Total = data.Item2.Length;
|
||||
await UploadFile(data.Item2, file.Hash, uploadToken).ConfigureAwait(false);
|
||||
if (!uploadToken.IsCancellationRequested) continue;
|
||||
Logger.Warn("Cancel in filesToUpload loop detected");
|
||||
CurrentUploads.Clear();
|
||||
@@ -233,12 +233,12 @@ public partial class ApiController
|
||||
}
|
||||
|
||||
Logger.Debug("Upload tasks complete, waiting for server to confirm");
|
||||
var anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken);
|
||||
var anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken).ConfigureAwait(false);
|
||||
Logger.Debug("Uploads open: " + anyUploadsOpen);
|
||||
while (anyUploadsOpen && !uploadToken.IsCancellationRequested)
|
||||
{
|
||||
anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken);
|
||||
await Task.Delay(TimeSpan.FromSeconds(0.5), uploadToken);
|
||||
anyUploadsOpen = await _mareHub!.InvokeAsync<bool>(Api.InvokeFileIsUploadFinished, uploadToken).ConfigureAwait(false);
|
||||
await Task.Delay(TimeSpan.FromSeconds(0.5), uploadToken).ConfigureAwait(false);
|
||||
Logger.Debug("Waiting for uploads to finish");
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ public partial class ApiController
|
||||
if (!uploadToken.IsCancellationRequested)
|
||||
{
|
||||
Logger.Info("Pushing character data for " + character.GetHashCode() + " to " + string.Join(", ", visibleCharacterIds));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringBuilder sb = new();
|
||||
foreach (var item in character.FileReplacements)
|
||||
{
|
||||
sb.AppendLine($"FileReplacements for {item.Key}: {item.Value.Count}");
|
||||
@@ -267,7 +267,7 @@ public partial class ApiController
|
||||
sb.AppendLine($"GlamourerData for {item.Key}: {!string.IsNullOrEmpty(item.Value)}");
|
||||
}
|
||||
Logger.Debug("Chara data contained: " + Environment.NewLine + sb.ToString());
|
||||
await _mareHub!.InvokeAsync(Api.InvokeUserPushCharacterDataToVisibleClients, character, visibleCharacterIds, uploadToken);
|
||||
await _mareHub!.InvokeAsync(Api.InvokeUserPushCharacterDataToVisibleClients, character, visibleCharacterIds, uploadToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -281,7 +281,7 @@ public partial class ApiController
|
||||
private async Task<(string, byte[])> GetCompressedFileData(string fileHash, CancellationToken uploadToken)
|
||||
{
|
||||
var fileCache = _fileDbManager.GetFileCacheByHash(fileHash)!.ResolvedFilepath;
|
||||
return (fileHash, LZ4Codec.WrapHC(await File.ReadAllBytesAsync(fileCache, uploadToken), 0,
|
||||
return (fileHash, LZ4Codec.WrapHC(await File.ReadAllBytesAsync(fileCache, uploadToken).ConfigureAwait(false), 0,
|
||||
(int)new FileInfo(fileCache).Length));
|
||||
}
|
||||
|
||||
@@ -295,15 +295,15 @@ public partial class ApiController
|
||||
using var ms = new MemoryStream(compressedFile);
|
||||
var buffer = new byte[chunkSize];
|
||||
int bytesRead;
|
||||
while ((bytesRead = await ms.ReadAsync(buffer, 0, chunkSize, token)) > 0 && !token.IsCancellationRequested)
|
||||
while ((bytesRead = await ms.ReadAsync(buffer, 0, chunkSize, token).ConfigureAwait(false)) > 0 && !token.IsCancellationRequested)
|
||||
{
|
||||
CurrentUploads.Single(f => f.Hash == fileHash).Transferred += bytesRead;
|
||||
CurrentUploads.Single(f => string.Equals(f.Hash, fileHash, StringComparison.Ordinal)).Transferred += bytesRead;
|
||||
token.ThrowIfCancellationRequested();
|
||||
yield return bytesRead == chunkSize ? buffer.ToArray() : buffer.Take(bytesRead).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
await _mareHub!.SendAsync(Api.SendFileUploadFileStreamAsync, fileHash, AsyncFileData(uploadToken), uploadToken);
|
||||
await _mareHub!.SendAsync(Api.SendFileUploadFileStreamAsync, fileHash, AsyncFileData(uploadToken), uploadToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void CancelDownload(int downloadId)
|
||||
|
||||
@@ -11,32 +11,32 @@ public partial class ApiController
|
||||
{
|
||||
_pluginConfiguration.ClientSecret.Remove(ApiUri);
|
||||
_pluginConfiguration.Save();
|
||||
await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles);
|
||||
await _mareHub!.SendAsync(Api.SendUserDeleteAccount);
|
||||
await CreateConnections();
|
||||
await _mareHub!.SendAsync(Api.SendFileDeleteAllFiles).ConfigureAwait(false);
|
||||
await _mareHub!.SendAsync(Api.SendUserDeleteAccount).ConfigureAwait(false);
|
||||
await CreateConnections().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetOnlineCharacters()
|
||||
{
|
||||
return await _mareHub!.InvokeAsync<List<string>>(Api.InvokeUserGetOnlineCharacters);
|
||||
return await _mareHub!.InvokeAsync<List<string>>(Api.InvokeUserGetOnlineCharacters).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendPairedClientAddition(string uid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendUserPairedClientAddition, uid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendUserPairedClientAddition, uid).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendPairedClientPauseChange(string uid, bool paused)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendUserPairedClientPauseChange, uid, paused);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendUserPairedClientPauseChange, uid, paused).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendPairedClientRemoval(string uid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendUserPairedClientRemoval, uid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendUserPairedClientRemoval, uid).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,27 +10,27 @@ public partial class ApiController
|
||||
{
|
||||
public async Task AddOrUpdateForbiddenFileEntry(ForbiddenFileDto forbiddenFile)
|
||||
{
|
||||
await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddForbiddenFile, forbiddenFile);
|
||||
await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddForbiddenFile, forbiddenFile).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task DeleteForbiddenFileEntry(ForbiddenFileDto forbiddenFile)
|
||||
{
|
||||
await _mareHub!.SendAsync(Api.SendAdminDeleteForbiddenFile, forbiddenFile);
|
||||
await _mareHub!.SendAsync(Api.SendAdminDeleteForbiddenFile, forbiddenFile).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task AddOrUpdateBannedUserEntry(BannedUserDto bannedUser)
|
||||
{
|
||||
await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddBannedUser, bannedUser);
|
||||
await _mareHub!.SendAsync(Api.SendAdminUpdateOrAddBannedUser, bannedUser).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task DeleteBannedUserEntry(BannedUserDto bannedUser)
|
||||
{
|
||||
await _mareHub!.SendAsync(Api.SendAdminDeleteBannedUser, bannedUser);
|
||||
await _mareHub!.SendAsync(Api.SendAdminDeleteBannedUser, bannedUser).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task RefreshOnlineUsers()
|
||||
{
|
||||
AdminOnlineUsers = await _mareHub!.InvokeAsync<List<OnlineUserDto>>(Api.InvokeAdminGetOnlineUsers);
|
||||
AdminOnlineUsers = await _mareHub!.InvokeAsync<List<OnlineUserDto>>(Api.InvokeAdminGetOnlineUsers).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public List<OnlineUserDto> AdminOnlineUsers { get; set; } = new List<OnlineUserDto>();
|
||||
|
||||
@@ -17,10 +17,10 @@ public partial class ApiController
|
||||
|
||||
private void UpdateLocalClientPairsCallback(ClientPairDto dto)
|
||||
{
|
||||
var entry = PairedClients.SingleOrDefault(e => e.OtherUID == dto.OtherUID);
|
||||
var entry = PairedClients.SingleOrDefault(e => string.Equals(e.OtherUID, dto.OtherUID, System.StringComparison.Ordinal));
|
||||
if (dto.IsRemoved)
|
||||
{
|
||||
PairedClients.RemoveAll(p => p.OtherUID == dto.OtherUID);
|
||||
PairedClients.RemoveAll(p => string.Equals(p.OtherUID, dto.OtherUID, System.StringComparison.Ordinal));
|
||||
return;
|
||||
}
|
||||
if (entry == null)
|
||||
@@ -43,7 +43,7 @@ public partial class ApiController
|
||||
|
||||
private void UpdateOrAddBannedUserCallback(BannedUserDto obj)
|
||||
{
|
||||
var user = AdminBannedUsers.SingleOrDefault(b => b.CharacterHash == obj.CharacterHash);
|
||||
var user = AdminBannedUsers.SingleOrDefault(b => string.Equals(b.CharacterHash, obj.CharacterHash, System.StringComparison.Ordinal));
|
||||
if (user == null)
|
||||
{
|
||||
AdminBannedUsers.Add(obj);
|
||||
@@ -56,12 +56,12 @@ public partial class ApiController
|
||||
|
||||
private void DeleteBannedUserCallback(BannedUserDto obj)
|
||||
{
|
||||
AdminBannedUsers.RemoveAll(a => a.CharacterHash == obj.CharacterHash);
|
||||
AdminBannedUsers.RemoveAll(a => string.Equals(a.CharacterHash, obj.CharacterHash, System.StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private void UpdateOrAddForbiddenFileCallback(ForbiddenFileDto obj)
|
||||
{
|
||||
var user = AdminForbiddenFiles.SingleOrDefault(b => b.Hash == obj.Hash);
|
||||
var user = AdminForbiddenFiles.SingleOrDefault(b => string.Equals(b.Hash, obj.Hash, System.StringComparison.Ordinal));
|
||||
if (user == null)
|
||||
{
|
||||
AdminForbiddenFiles.Add(obj);
|
||||
@@ -74,18 +74,18 @@ public partial class ApiController
|
||||
|
||||
private void DeleteForbiddenFileCallback(ForbiddenFileDto obj)
|
||||
{
|
||||
AdminForbiddenFiles.RemoveAll(f => f.Hash == obj.Hash);
|
||||
AdminForbiddenFiles.RemoveAll(f => string.Equals(f.Hash, obj.Hash, System.StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private void GroupPairChangedCallback(GroupPairDto dto)
|
||||
{
|
||||
if (dto.IsRemoved.GetValueOrDefault(false))
|
||||
{
|
||||
GroupPairedClients.RemoveAll(g => g.GroupGID == dto.GroupGID && g.UserUID == dto.UserUID);
|
||||
GroupPairedClients.RemoveAll(g => string.Equals(g.GroupGID, dto.GroupGID, System.StringComparison.Ordinal) && string.Equals(g.UserUID, dto.UserUID, System.StringComparison.Ordinal));
|
||||
return;
|
||||
}
|
||||
|
||||
var existingUser = GroupPairedClients.FirstOrDefault(f => f.GroupGID == dto.GroupGID && f.UserUID == dto.UserUID);
|
||||
var existingUser = GroupPairedClients.FirstOrDefault(f => string.Equals(f.GroupGID, dto.GroupGID, System.StringComparison.Ordinal) && string.Equals(f.UserUID, dto.UserUID, System.StringComparison.Ordinal));
|
||||
if (existingUser == null)
|
||||
{
|
||||
GroupPairedClients.Add(dto);
|
||||
@@ -101,16 +101,16 @@ public partial class ApiController
|
||||
{
|
||||
if (dto.IsDeleted.GetValueOrDefault(false))
|
||||
{
|
||||
Groups.RemoveAll(g => g.GID == dto.GID);
|
||||
GroupPairedClients.RemoveAll(g => g.GroupGID == dto.GID);
|
||||
Groups.RemoveAll(g => string.Equals(g.GID, dto.GID, System.StringComparison.Ordinal));
|
||||
GroupPairedClients.RemoveAll(g => string.Equals(g.GroupGID, dto.GID, System.StringComparison.Ordinal));
|
||||
return;
|
||||
}
|
||||
|
||||
var existingGroup = Groups.FirstOrDefault(g => g.GID == dto.GID);
|
||||
var existingGroup = Groups.FirstOrDefault(g => string.Equals(g.GID, dto.GID, System.StringComparison.Ordinal));
|
||||
if (existingGroup == null)
|
||||
{
|
||||
Groups.Add(dto);
|
||||
GroupPairedClients.AddRange(await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, dto.GID));
|
||||
GroupPairedClients.AddRange(await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, dto.GID).ConfigureAwait(false));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,79 +9,79 @@ public partial class ApiController
|
||||
{
|
||||
public async Task<GroupCreatedDto> CreateGroup()
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return new GroupCreatedDto();
|
||||
return await _mareHub!.InvokeAsync<GroupCreatedDto>(Api.InvokeGroupCreate);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new GroupCreatedDto();
|
||||
return await _mareHub!.InvokeAsync<GroupCreatedDto>(Api.InvokeGroupCreate).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<bool> ChangeGroupPassword(string gid, string newpassword)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return false;
|
||||
return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupChangePassword, gid, newpassword);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return false;
|
||||
return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupChangePassword, gid, newpassword).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<List<GroupDto>> GetGroups()
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return new List<GroupDto>();
|
||||
return await _mareHub!.InvokeAsync<List<GroupDto>>(Api.InvokeGroupGetGroups);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new List<GroupDto>();
|
||||
return await _mareHub!.InvokeAsync<List<GroupDto>>(Api.InvokeGroupGetGroups).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<List<GroupPairDto>> GetUsersInGroup(string gid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return new List<GroupPairDto>();
|
||||
return await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, gid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return new List<GroupPairDto>();
|
||||
return await _mareHub!.InvokeAsync<List<GroupPairDto>>(Api.InvokeGroupGetUsersInGroup, gid).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<bool> SendGroupJoin(string gid, string password)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return false;
|
||||
return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupJoin, gid, password);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return false;
|
||||
return await _mareHub!.InvokeAsync<bool>(Api.InvokeGroupJoin, gid, password).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendGroupChangeInviteState(string gid, bool opened)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupChangeInviteState, gid, opened);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupChangeInviteState, gid, opened).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendDeleteGroup(string gid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupDelete, gid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupDelete, gid).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendChangeUserPinned(string gid, string uid, bool isPinned)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupChangePinned, gid, uid, isPinned);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupChangePinned, gid, uid, isPinned).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendClearGroup(string gid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupClear, gid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupClear, gid).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendLeaveGroup(string gid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupLeave, gid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupLeave, gid).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendPauseGroup(string gid, bool isPaused)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupPause, gid, isPaused);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupPause, gid, isPaused).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendRemoveUserFromGroup(string gid, string uid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupRemoveUser, gid, uid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupRemoveUser, gid, uid).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task ChangeOwnerOfGroup(string gid, string uid)
|
||||
{
|
||||
if (!IsConnected || SecretKey == "-") return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupChangeOwner, gid, uid);
|
||||
if (!IsConnected || string.Equals(SecretKey, "-", System.StringComparison.Ordinal)) return;
|
||||
await _mareHub!.SendAsync(Api.SendGroupChangeOwner, gid, uid).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,11 @@ public partial class ApiController : IDisposable
|
||||
private HubConnection? _mareHub;
|
||||
|
||||
private CancellationTokenSource? _uploadCancellationTokenSource = new();
|
||||
private CancellationTokenSource? _healthCheckTokenSource = new();
|
||||
|
||||
private ConnectionDto? _connectionDto;
|
||||
public ServerInfoDto ServerInfo => _connectionDto?.ServerInfo ?? new ServerInfoDto();
|
||||
|
||||
public SystemInfoDto SystemInfoDto { get; private set; } = new();
|
||||
public bool IsModerator => (_connectionDto?.IsAdmin ?? false) || (_connectionDto?.IsModerator ?? false);
|
||||
|
||||
@@ -51,7 +54,7 @@ public partial class ApiController : IDisposable
|
||||
_dalamudUtil.LogIn += DalamudUtilOnLogIn;
|
||||
_dalamudUtil.LogOut += DalamudUtilOnLogOut;
|
||||
ServerState = ServerState.Offline;
|
||||
_verifiedUploadedHashes = new();
|
||||
_verifiedUploadedHashes = new(StringComparer.Ordinal);
|
||||
|
||||
if (_dalamudUtil.IsLoggedIn)
|
||||
{
|
||||
@@ -61,7 +64,7 @@ public partial class ApiController : IDisposable
|
||||
|
||||
private void DalamudUtilOnLogOut()
|
||||
{
|
||||
Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token));
|
||||
Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false));
|
||||
ServerState = ServerState.Offline;
|
||||
}
|
||||
|
||||
@@ -108,10 +111,10 @@ public partial class ApiController : IDisposable
|
||||
|
||||
public bool ServerAlive => ServerState is ServerState.Connected or ServerState.RateLimited or ServerState.Unauthorized or ServerState.Disconnected;
|
||||
|
||||
public Dictionary<string, string> ServerDictionary => new Dictionary<string, string>()
|
||||
public Dictionary<string, string> ServerDictionary => new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{ { MainServiceUri, MainServer } }
|
||||
.Concat(_pluginConfiguration.CustomServerList)
|
||||
.ToDictionary(k => k.Key, k => k.Value);
|
||||
.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal);
|
||||
|
||||
public string UID => _connectionDto?.UID ?? string.Empty;
|
||||
public string DisplayName => _connectionDto?.UID ?? string.Empty;
|
||||
@@ -138,11 +141,11 @@ public partial class ApiController : IDisposable
|
||||
Logger.Info("Not recreating Connection, paused");
|
||||
ServerState = ServerState.Disconnected;
|
||||
_connectionDto = null;
|
||||
await StopConnection(_connectionCancellationTokenSource.Token);
|
||||
await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await StopConnection(_connectionCancellationTokenSource.Token);
|
||||
await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false);
|
||||
|
||||
Logger.Info("Recreating Connection");
|
||||
|
||||
@@ -154,11 +157,11 @@ public partial class ApiController : IDisposable
|
||||
{
|
||||
if (string.IsNullOrEmpty(SecretKey))
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(2));
|
||||
await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
await StopConnection(token);
|
||||
await StopConnection(token).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -167,32 +170,32 @@ public partial class ApiController : IDisposable
|
||||
while (!_dalamudUtil.IsPlayerPresent && !token.IsCancellationRequested)
|
||||
{
|
||||
Logger.Debug("Player not loaded in yet, waiting");
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), token);
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested) break;
|
||||
|
||||
_mareHub = BuildHubConnection(Api.Path);
|
||||
|
||||
await _mareHub.StartAsync(token);
|
||||
await _mareHub.StartAsync(token).ConfigureAwait(false);
|
||||
|
||||
_mareHub.On<SystemInfoDto>(Api.OnUpdateSystemInfo, (dto) => SystemInfoDto = dto);
|
||||
|
||||
_connectionDto =
|
||||
await _mareHub.InvokeAsync<ConnectionDto>(Api.InvokeHeartbeat, _dalamudUtil.PlayerNameHashed, token);
|
||||
await _mareHub.InvokeAsync<ConnectionDto>(Api.InvokeHeartbeat, _dalamudUtil.PlayerNameHashed, token).ConfigureAwait(false);
|
||||
|
||||
ServerState = ServerState.Connected;
|
||||
|
||||
if (_connectionDto.ServerVersion != Api.Version)
|
||||
{
|
||||
ServerState = ServerState.VersionMisMatch;
|
||||
await StopConnection(token);
|
||||
await StopConnection(token).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServerState is ServerState.Connected) // user is authorized && server is legit
|
||||
{
|
||||
await InitializeData(token);
|
||||
await InitializeData(token).ConfigureAwait(false);
|
||||
|
||||
_mareHub.Closed += MareHubOnClosed;
|
||||
_mareHub.Reconnecting += MareHubOnReconnecting;
|
||||
@@ -206,7 +209,7 @@ public partial class ApiController : IDisposable
|
||||
Logger.Warn(ex.StackTrace ?? string.Empty);
|
||||
|
||||
ServerState = ServerState.RateLimited;
|
||||
await StopConnection(token);
|
||||
await StopConnection(token).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
@@ -218,14 +221,14 @@ public partial class ApiController : IDisposable
|
||||
if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||
{
|
||||
ServerState = ServerState.Unauthorized;
|
||||
await StopConnection(token);
|
||||
await StopConnection(token).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerState = ServerState.Offline;
|
||||
Logger.Info("Failed to establish connection, retrying");
|
||||
await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token);
|
||||
await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -234,7 +237,7 @@ public partial class ApiController : IDisposable
|
||||
Logger.Warn(ex.Message);
|
||||
Logger.Warn(ex.StackTrace ?? string.Empty);
|
||||
Logger.Info("Failed to establish connection, retrying");
|
||||
await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token);
|
||||
await Task.Delay(TimeSpan.FromSeconds(new Random().Next(5, 20)), token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,6 +248,21 @@ public partial class ApiController : IDisposable
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task ClientHealthCheck(CancellationToken ct)
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(30), ct).ConfigureAwait(false);
|
||||
if (ct.IsCancellationRequested) break;
|
||||
var needsRestart = await _mareHub!.InvokeAsync<bool>(Api.InvokeCheckClientHealth, ct).ConfigureAwait(false);
|
||||
Logger.Debug("Checked Client Health State, healthy: " + !needsRestart);
|
||||
if (needsRestart)
|
||||
{
|
||||
_ = CreateConnections();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitializeData(CancellationToken token)
|
||||
{
|
||||
if (_mareHub == null) return;
|
||||
@@ -263,22 +281,22 @@ public partial class ApiController : IDisposable
|
||||
_mareHub.On<GroupPairDto>(Api.OnGroupUserChange, GroupPairChangedCallback);
|
||||
|
||||
PairedClients =
|
||||
await _mareHub!.InvokeAsync<List<ClientPairDto>>(Api.InvokeUserGetPairedClients, token);
|
||||
Groups = await GetGroups();
|
||||
await _mareHub!.InvokeAsync<List<ClientPairDto>>(Api.InvokeUserGetPairedClients, token).ConfigureAwait(false);
|
||||
Groups = await GetGroups().ConfigureAwait(false);
|
||||
GroupPairedClients.Clear();
|
||||
foreach (var group in Groups)
|
||||
{
|
||||
GroupPairedClients.AddRange(await GetUsersInGroup(group.GID));
|
||||
GroupPairedClients.AddRange(await GetUsersInGroup(group.GID).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
if (IsModerator)
|
||||
{
|
||||
AdminForbiddenFiles =
|
||||
await _mareHub.InvokeAsync<List<ForbiddenFileDto>>(Api.InvokeAdminGetForbiddenFiles,
|
||||
token);
|
||||
token).ConfigureAwait(false);
|
||||
AdminBannedUsers =
|
||||
await _mareHub.InvokeAsync<List<BannedUserDto>>(Api.InvokeAdminGetBannedUsers,
|
||||
token);
|
||||
token).ConfigureAwait(false);
|
||||
_mareHub.On<BannedUserDto>(Api.OnAdminUpdateOrAddBannedUser,
|
||||
UpdateOrAddBannedUserCallback);
|
||||
_mareHub.On<BannedUserDto>(Api.OnAdminDeleteBannedUser, DeleteBannedUserCallback);
|
||||
@@ -288,6 +306,11 @@ public partial class ApiController : IDisposable
|
||||
DeleteForbiddenFileCallback);
|
||||
}
|
||||
|
||||
_healthCheckTokenSource?.Cancel();
|
||||
_healthCheckTokenSource?.Dispose();
|
||||
_healthCheckTokenSource = new CancellationTokenSource();
|
||||
_ = ClientHealthCheck(_healthCheckTokenSource.Token);
|
||||
|
||||
Connected?.Invoke();
|
||||
}
|
||||
|
||||
@@ -298,7 +321,7 @@ public partial class ApiController : IDisposable
|
||||
_dalamudUtil.LogIn -= DalamudUtilOnLogIn;
|
||||
_dalamudUtil.LogOut -= DalamudUtilOnLogOut;
|
||||
|
||||
Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token));
|
||||
Task.Run(async () => await StopConnection(_connectionCancellationTokenSource.Token).ConfigureAwait(false));
|
||||
_connectionCancellationTokenSource?.Cancel();
|
||||
}
|
||||
|
||||
@@ -332,6 +355,7 @@ public partial class ApiController : IDisposable
|
||||
|
||||
private Task MareHubOnReconnecting(Exception? arg)
|
||||
{
|
||||
_healthCheckTokenSource?.Cancel();
|
||||
ServerState = ServerState.Disconnected;
|
||||
Logger.Warn("Connection closed... Reconnecting");
|
||||
Logger.Warn(arg?.Message ?? string.Empty);
|
||||
@@ -350,8 +374,8 @@ public partial class ApiController : IDisposable
|
||||
_mareHub.Closed -= MareHubOnClosed;
|
||||
_mareHub.Reconnecting -= MareHubOnReconnecting;
|
||||
_mareHub.Reconnected -= MareHubOnReconnected;
|
||||
await _mareHub.StopAsync(token);
|
||||
await _mareHub.DisposeAsync();
|
||||
await _mareHub.StopAsync(token).ConfigureAwait(false);
|
||||
await _mareHub.DisposeAsync().ConfigureAwait(false);
|
||||
CurrentUploads.Clear();
|
||||
CurrentDownloads.Clear();
|
||||
_uploadCancellationTokenSource?.Cancel();
|
||||
@@ -363,7 +387,7 @@ public partial class ApiController : IDisposable
|
||||
{
|
||||
while (ServerState != ServerState.Offline)
|
||||
{
|
||||
await Task.Delay(16);
|
||||
await Task.Delay(16).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user