mirror of
https://github.com/4sval/FModel.git
synced 2026-04-17 23:31:00 -05:00
not bullet proof but good enough
This commit is contained in:
parent
a8c60ac3a9
commit
947d5011c2
|
|
@ -1,4 +1,9 @@
|
|||
namespace FModel.Framework;
|
||||
using System.Linq;
|
||||
using FModel.ViewModels.ApiEndpoints;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace FModel.Framework;
|
||||
|
||||
public class FEndpoint : ViewModel
|
||||
{
|
||||
|
|
@ -6,18 +11,7 @@ public class FEndpoint : ViewModel
|
|||
public string Url
|
||||
{
|
||||
get => _url;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _url, value);
|
||||
RaisePropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
private bool _overwrite;
|
||||
public bool Overwrite
|
||||
{
|
||||
get => _overwrite;
|
||||
set => SetProperty(ref _overwrite, value);
|
||||
set => SetProperty(ref _url, value);
|
||||
}
|
||||
|
||||
private string _path;
|
||||
|
|
@ -27,11 +21,72 @@ public class FEndpoint : ViewModel
|
|||
set => SetProperty(ref _path, value);
|
||||
}
|
||||
|
||||
public bool IsEnabled => !string.IsNullOrWhiteSpace(_url); // change this later
|
||||
private bool _overwrite;
|
||||
public bool Overwrite
|
||||
{
|
||||
get => _overwrite;
|
||||
set => SetProperty(ref _overwrite, value);
|
||||
}
|
||||
|
||||
private string _filePath;
|
||||
public string FilePath
|
||||
{
|
||||
get => _filePath;
|
||||
set => SetProperty(ref _filePath, value);
|
||||
}
|
||||
|
||||
private bool _isValid;
|
||||
public bool IsValid
|
||||
{
|
||||
get => _isValid;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _isValid, value);
|
||||
RaisePropertyChanged(nameof(Label));
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string Label => IsValid ?
|
||||
"Your endpoint configuration is valid! Please, avoid any unnecessary modifications!" :
|
||||
"Your endpoint configuration DOES NOT seem to be valid yet! Please, test it out!";
|
||||
|
||||
public FEndpoint() {}
|
||||
public FEndpoint(string url)
|
||||
public FEndpoint(string url, string path)
|
||||
{
|
||||
Url = url;
|
||||
Path = path;
|
||||
IsValid = !string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(path); // be careful with this
|
||||
}
|
||||
|
||||
public void TryValidate(DynamicApiEndpoint endpoint, EEndpointType type, out JToken response)
|
||||
{
|
||||
response = null;
|
||||
if (string.IsNullOrEmpty(Url) || string.IsNullOrEmpty(Path))
|
||||
{
|
||||
IsValid = false;
|
||||
}
|
||||
else switch (type)
|
||||
{
|
||||
case EEndpointType.Aes:
|
||||
{
|
||||
var r = endpoint.GetAesKeys(default, Url, Path);
|
||||
response = JToken.FromObject(r);
|
||||
IsValid = r.IsValid;
|
||||
break;
|
||||
}
|
||||
case EEndpointType.Mapping:
|
||||
{
|
||||
var r = endpoint.GetMappings(default, Url, Path);
|
||||
response = JToken.FromObject(r);
|
||||
IsValid = r.Any(x => x.IsValid);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
IsValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,17 @@ public static class Helper
|
|||
key.StartsWith("mu", StringComparison.OrdinalIgnoreCase) &&
|
||||
key.EndsWith("sus", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public static string FixKey(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return string.Empty;
|
||||
|
||||
if (key.StartsWith("0x"))
|
||||
key = key[2..];
|
||||
|
||||
return "0x" + key.ToUpper().Trim();
|
||||
}
|
||||
|
||||
public static void OpenWindow<T>(string windowName, Action action) where T : Window
|
||||
{
|
||||
if (!IsWindowOpen<T>(windowName))
|
||||
|
|
|
|||
|
|
@ -39,14 +39,14 @@ namespace FModel.Settings
|
|||
if (File.Exists(FilePath)) File.Delete(FilePath);
|
||||
}
|
||||
|
||||
public static bool IsEndpointEnabled(FGame game, EEndpointType type, out FEndpoint endpoint)
|
||||
public static bool IsEndpointValid(FGame game, EEndpointType type, out FEndpoint endpoint)
|
||||
{
|
||||
endpoint = null;
|
||||
if (!Default.CustomEndpoints.TryGetValue(game, out var endpoints))
|
||||
return false;
|
||||
|
||||
endpoint = endpoints[(int) type];
|
||||
return endpoint.IsEnabled;
|
||||
return endpoint.IsValid;
|
||||
}
|
||||
|
||||
private bool _showChangelog = true;
|
||||
|
|
@ -384,8 +384,8 @@ namespace FModel.Settings
|
|||
{
|
||||
FGame.FortniteGame, new []
|
||||
{
|
||||
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/aes"),
|
||||
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/mappings")
|
||||
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/aes", "$.['mainKey','dynamicKeys']"),
|
||||
new FEndpoint("https://fortnitecentral.gmatrixgames.ga/api/v1/mappings", "$.[?(@.meta.compressionMethod=='Oodle')].['url','fileName']")
|
||||
}
|
||||
},
|
||||
{FGame.ShooterGame, new FEndpoint[]{new (), new ()}},
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class AesManagerViewModel : ViewModel
|
|||
DynamicKeys = null
|
||||
};
|
||||
|
||||
_mainKey.Key = FixKey(_keysFromSettings.MainKey);
|
||||
_mainKey.Key = Helper.FixKey(_keysFromSettings.MainKey);
|
||||
AesKeys = new FullyObservableCollection<FileItem>(EnumerateAesKeys());
|
||||
AesKeys.ItemPropertyChanged += AesKeysOnItemPropertyChanged;
|
||||
AesKeysView = new ListCollectionView(AesKeys) { SortDescriptions = { new SortDescription("Name", ListSortDirection.Ascending) } };
|
||||
|
|
@ -63,11 +63,11 @@ public class AesManagerViewModel : ViewModel
|
|||
if (e.PropertyName != "Key" || sender is not FullyObservableCollection<FileItem> collection)
|
||||
return;
|
||||
|
||||
var key = FixKey(collection[e.CollectionIndex].Key);
|
||||
var key = Helper.FixKey(collection[e.CollectionIndex].Key);
|
||||
if (e.CollectionIndex == 0)
|
||||
{
|
||||
if (!HasChange)
|
||||
HasChange = FixKey(_keysFromSettings.MainKey) != key;
|
||||
HasChange = Helper.FixKey(_keysFromSettings.MainKey) != key;
|
||||
|
||||
_keysFromSettings.MainKey = key;
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ public class AesManagerViewModel : ViewModel
|
|||
else if (_keysFromSettings.DynamicKeys.FirstOrDefault(x => x.Guid == collection[e.CollectionIndex].Guid.ToString()) is { } d)
|
||||
{
|
||||
if (!HasChange)
|
||||
HasChange = FixKey(d.Key) != key;
|
||||
HasChange = Helper.FixKey(d.Key) != key;
|
||||
|
||||
d.Key = key;
|
||||
}
|
||||
|
|
@ -117,17 +117,6 @@ public class AesManagerViewModel : ViewModel
|
|||
Log.Information("{@Json}", UserSettings.Default);
|
||||
}
|
||||
|
||||
private string FixKey(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return string.Empty;
|
||||
|
||||
if (key.StartsWith("0x"))
|
||||
key = key[2..];
|
||||
|
||||
return "0x" + key.ToUpper().Trim();
|
||||
}
|
||||
|
||||
private IEnumerable<FileItem> EnumerateAesKeys()
|
||||
{
|
||||
yield return _mainKey;
|
||||
|
|
@ -145,7 +134,7 @@ public class AesManagerViewModel : ViewModel
|
|||
k = dynamicKey.Key;
|
||||
}
|
||||
|
||||
file.Key = FixKey(k);
|
||||
file.Key = Helper.FixKey(k);
|
||||
yield return file;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using System.Threading;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FModel.Framework;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using RestSharp;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -13,35 +15,55 @@ public class DynamicApiEndpoint : AbstractApiProvider
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<AesResponse> GetAesKeysAsync(CancellationToken token, string url)
|
||||
public async Task<AesResponse> GetAesKeysAsync(CancellationToken token, string url, string path)
|
||||
{
|
||||
var request = new FRestRequest(url)
|
||||
{
|
||||
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
|
||||
};
|
||||
var response = await _client.ExecuteAsync<AesResponse>(request, token).ConfigureAwait(false);
|
||||
var response = await _client.ExecuteAsync(request, token).ConfigureAwait(false);
|
||||
var body = JToken.Parse(response.Content!);
|
||||
Log.Information("[{Method}] [{Status}({StatusCode})] '{Resource}'", request.Method, response.StatusDescription, (int) response.StatusCode, response.ResponseUri?.OriginalString);
|
||||
return response.Data;
|
||||
|
||||
var tokens = body.SelectTokens(path);
|
||||
var ret = new AesResponse { MainKey = Helper.FixKey(tokens.ElementAtOrDefault(0).ToString()) };
|
||||
if (tokens.ElementAtOrDefault(1) is JArray dynamicKeys)
|
||||
{
|
||||
foreach (var dynamicKey in dynamicKeys)
|
||||
{
|
||||
if (dynamicKey["guid"] is not { } guid || dynamicKey["key"] is not { } key)
|
||||
continue;
|
||||
|
||||
ret.DynamicKeys.Add(new DynamicKey{Guid = guid.ToString(), Key = Helper.FixKey(key.ToString())});
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public AesResponse GetAesKeys(CancellationToken token, string url)
|
||||
public AesResponse GetAesKeys(CancellationToken token, string url, string path)
|
||||
{
|
||||
return GetAesKeysAsync(token, url).GetAwaiter().GetResult();
|
||||
return GetAesKeysAsync(token, url, path).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public async Task<MappingsResponse[]> GetMappingsAsync(CancellationToken token, string url)
|
||||
public async Task<MappingsResponse[]> GetMappingsAsync(CancellationToken token, string url, string path)
|
||||
{
|
||||
var request = new FRestRequest(url)
|
||||
{
|
||||
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
|
||||
};
|
||||
var response = await _client.ExecuteAsync<MappingsResponse[]>(request, token).ConfigureAwait(false);
|
||||
var response = await _client.ExecuteAsync(request, token).ConfigureAwait(false);
|
||||
var body = JToken.Parse(response.Content!);
|
||||
Log.Information("[{Method}] [{Status}({StatusCode})] '{Resource}'", request.Method, response.StatusDescription, (int) response.StatusCode, response.ResponseUri?.OriginalString);
|
||||
return response.Data;
|
||||
|
||||
var tokens = body.SelectTokens(path);
|
||||
var ret = new MappingsResponse[] {new()};
|
||||
ret[0].Url = tokens.ElementAtOrDefault(0).ToString();
|
||||
ret[0].FileName = tokens.ElementAtOrDefault(1).ToString();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public MappingsResponse[] GetMappings(CancellationToken token, string url)
|
||||
public MappingsResponse[] GetMappings(CancellationToken token, string url, string path)
|
||||
{
|
||||
return GetMappingsAsync(token, url).GetAwaiter().GetResult();
|
||||
return GetMappingsAsync(token, url, path).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public class AesResponse
|
|||
}
|
||||
|
||||
[I] public bool HasDynamicKeys => DynamicKeys is { Count: > 0 };
|
||||
[I] public bool IsValid => !string.IsNullOrEmpty(MainKey);
|
||||
[I] public bool IsValid => MainKey.Length == 66;
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{" + nameof(Key) + "}")]
|
||||
|
|
@ -29,6 +29,5 @@ public class DynamicKey
|
|||
[J("guid")] public string Guid { get; set; }
|
||||
[J("key")] public string Key { get; set; }
|
||||
|
||||
[I] public bool IsValid => !string.IsNullOrEmpty(Guid) &&
|
||||
!string.IsNullOrEmpty(Key);
|
||||
[I] public bool IsValid => Guid.Length == 32 && Key.Length == 66;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ public class MappingsResponse
|
|||
}
|
||||
|
||||
[I] public bool IsValid => !string.IsNullOrEmpty(Url) &&
|
||||
!string.IsNullOrEmpty(FileName) &&
|
||||
Meta != null;
|
||||
!string.IsNullOrEmpty(FileName);
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{" + nameof(CompressionMethod) + "}")]
|
||||
|
|
@ -31,11 +30,4 @@ public class Meta
|
|||
{
|
||||
[I][J] public string Version { get; private set; }
|
||||
[J] public string CompressionMethod { get; set; }
|
||||
|
||||
public Meta()
|
||||
{
|
||||
CompressionMethod = "Oodle";
|
||||
}
|
||||
|
||||
[I] public bool IsValid => CompressionMethod == "Oodle";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,12 +295,12 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
// game directory dependent, we don't have the provider game name yet since we don't have aes keys
|
||||
// except when this comes from the AES Manager
|
||||
if (!UserSettings.IsEndpointEnabled(Game, EEndpointType.Aes, out var endpoint))
|
||||
if (!UserSettings.IsEndpointValid(Game, EEndpointType.Aes, out var endpoint))
|
||||
return;
|
||||
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
var aes = _apiEndpointView.DynamicApi.GetAesKeys(cancellationToken, endpoint.Url);
|
||||
var aes = _apiEndpointView.DynamicApi.GetAesKeys(cancellationToken, endpoint.Url, endpoint.Path);
|
||||
if (aes is not { IsValid: true }) return;
|
||||
|
||||
UserSettings.Default.AesKeys[Game] = aes;
|
||||
|
|
@ -323,26 +323,26 @@ public class CUE4ParseViewModel : ViewModel
|
|||
|
||||
public async Task InitBenMappings()
|
||||
{
|
||||
if (!UserSettings.IsEndpointEnabled(Game, EEndpointType.Mapping, out var endpoint))
|
||||
if (!UserSettings.IsEndpointValid(Game, EEndpointType.Mapping, out var endpoint))
|
||||
return;
|
||||
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
{
|
||||
if (endpoint.Overwrite && File.Exists(endpoint.Path))
|
||||
if (endpoint.Overwrite && File.Exists(endpoint.FilePath))
|
||||
{
|
||||
Provider.MappingsContainer = new FileUsmapTypeMappingsProvider(endpoint.Path);
|
||||
Provider.MappingsContainer = new FileUsmapTypeMappingsProvider(endpoint.FilePath);
|
||||
FLogger.AppendInformation();
|
||||
FLogger.AppendText($"Mappings pulled from '{endpoint.Path.SubstringAfterLast("\\")}'", Constants.WHITE, true);
|
||||
FLogger.AppendText($"Mappings pulled from '{endpoint.FilePath.SubstringAfterLast("\\")}'", Constants.WHITE, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var mappingsFolder = Path.Combine(UserSettings.Default.OutputDirectory, ".data");
|
||||
var mappings = _apiEndpointView.DynamicApi.GetMappings(cancellationToken, endpoint.Url);
|
||||
var mappings = _apiEndpointView.DynamicApi.GetMappings(cancellationToken, endpoint.Url, endpoint.Path);
|
||||
if (mappings is { Length: > 0 })
|
||||
{
|
||||
foreach (var mapping in mappings)
|
||||
{
|
||||
if (!mapping.IsValid || !mapping.Meta.IsValid) continue;
|
||||
if (!mapping.IsValid) continue;
|
||||
|
||||
var mappingPath = Path.Combine(mappingsFolder, mapping.FileName);
|
||||
if (!File.Exists(mappingPath))
|
||||
|
|
|
|||
|
|
@ -324,12 +324,6 @@ public class SettingsViewModel : ViewModel
|
|||
UserSettings.Default.OverridedOptions[_game] = SelectedOptions;
|
||||
}
|
||||
|
||||
if (UserSettings.Default.CustomEndpoints.TryGetValue(_game, out var endpoints))
|
||||
{
|
||||
endpoints[0] = AesEndpoint;
|
||||
endpoints[1] = MappingEndpoint;
|
||||
}
|
||||
|
||||
UserSettings.Default.AssetLanguage = SelectedAssetLanguage;
|
||||
UserSettings.Default.CompressedAudioMode = SelectedCompressedAudio;
|
||||
UserSettings.Default.CosmeticStyle = SelectedCosmeticStyle;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
|
||||
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
|
||||
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
|
||||
WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen" IconVisibility="Collapsed" ResizeMode="NoResize" Closing="OnClosing"
|
||||
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.50'}"
|
||||
Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.30'}">
|
||||
<adonisControls:AdonisWindow.Resources>
|
||||
|
|
@ -23,38 +23,62 @@
|
|||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="5"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" Margin="{adonisUi:Space 1, 0.5}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="5"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="Endpoint" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<TextBox x:Name="EndpointUrl" Grid.Column="2" Margin="0 0 0 5" />
|
||||
<Button Grid.Column="4" Content="Send" HorizontalAlignment="Right" Margin="0 0 0 5"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.AccentButton}}" Click="OnSend"/>
|
||||
<Grid Grid.Row="0" Margin="{adonisUi:Space 1, 0.5}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="Endpoint" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<TextBox Grid.Column="2" Margin="0 0 0 5" Text="{Binding Url, Mode=TwoWay}" TextChanged="OnTextChanged" />
|
||||
<Button Grid.Column="4" Content="Send" HorizontalAlignment="Right" Margin="0 0 0 5"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.AccentButton}}" Click="OnSend"/>
|
||||
</Grid>
|
||||
|
||||
<avalonEdit:TextEditor x:Name="EndpointResponse" Grid.Row="2" Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
|
||||
FontFamily="Consolas" FontSize="8pt" IsReadOnly="True" ShowLineNumbers="True" Foreground="#DAE5F2" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="5"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<avalonEdit:TextEditor x:Name="EndpointResponse" Grid.Column="0" Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
|
||||
<Grid Grid.Row="0" Margin="{adonisUi:Space 1, 0.5}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="Path" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<TextBox Grid.Column="2" Margin="0 0 0 5" Text="{Binding Path, Mode=TwoWay}" TextChanged="OnTextChanged" />
|
||||
<Button Grid.Column="4" Content="Test" HorizontalAlignment="Right" Margin="0 0 0 5"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.AccentButton}}" Click="OnTest"/>
|
||||
</Grid>
|
||||
|
||||
<avalonEdit:TextEditor x:Name="TargetResponse" Grid.Row="2" Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
|
||||
FontFamily="Consolas" FontSize="8pt" IsReadOnly="True" ShowLineNumbers="True" Foreground="#DAE5F2" />
|
||||
<avalonEdit:TextEditor x:Name="TargetResponse" Grid.Column="2" Background="{DynamicResource {x:Static adonisUi:Brushes.Layer3BackgroundBrush}}"
|
||||
FontFamily="Consolas" FontSize="8pt" IsReadOnly="False" ShowLineNumbers="True" Foreground="#DAE5F2" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
|
@ -65,12 +89,17 @@
|
|||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="0" MinWidth="78" Margin="0 0 12 0" IsDefault="True" IsCancel="False"
|
||||
<TextBlock Grid.Column="0" Text="{Binding Label}"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="11" Margin="0 0 10 0" FontWeight="DemiBold"
|
||||
Foreground="{DynamicResource {x:Static adonisUi:Brushes.Layer1InteractionForegroundBrush}}" />
|
||||
|
||||
<Button Grid.Column="1" MinWidth="78" Margin="0 0 12 0" IsDefault="True" IsCancel="False"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="OK" Click="OnClick" />
|
||||
<Button Grid.Column="1" MinWidth="78" Margin="0 0 12 0" IsDefault="False" IsCancel="True"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="Cancel" />
|
||||
<Button Grid.Column="2" MinWidth="78" Margin="0 0 12 0" IsDefault="False" IsCancel="False"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Content="Online Evaluator" Click="OnEvaluator" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using FModel.Extensions;
|
||||
using FModel.Framework;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
using FModel.Services;
|
||||
using ICSharpCode.AvalonEdit.Document;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
@ -12,61 +14,71 @@ namespace FModel.Views.Resources.Controls;
|
|||
|
||||
public partial class EndpointEditor
|
||||
{
|
||||
private readonly AesResponse _defaultAesResponse = new ();
|
||||
private readonly MappingsResponse[] _defaultMappingResponse = {new ()};
|
||||
private JObject _body;
|
||||
|
||||
public FEndpoint Endpoint { get; private set; }
|
||||
private readonly EEndpointType _type;
|
||||
private bool _isTested;
|
||||
|
||||
public EndpointEditor(FEndpoint endpoint, string title, EEndpointType type)
|
||||
{
|
||||
DataContext = endpoint;
|
||||
_type = type;
|
||||
_isTested = endpoint.IsValid;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = title;
|
||||
EndpointUrl.Text = endpoint.Url;
|
||||
TargetResponse.SyntaxHighlighting = EndpointResponse.SyntaxHighlighting = AvalonExtensions.HighlighterSelector("json");
|
||||
TargetResponse.Document = new TextDocument
|
||||
{
|
||||
Text = JsonConvert.SerializeObject(type switch
|
||||
{
|
||||
EEndpointType.Aes => _defaultAesResponse,
|
||||
EEndpointType.Mapping => _defaultMappingResponse,
|
||||
_ => throw new NotImplementedException()
|
||||
}, Formatting.Indented)
|
||||
};
|
||||
TargetResponse.SyntaxHighlighting =
|
||||
EndpointResponse.SyntaxHighlighting = AvalonExtensions.HighlighterSelector("json");
|
||||
}
|
||||
|
||||
private void OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Endpoint = new FEndpoint(EndpointUrl.Text);
|
||||
DialogResult = true;
|
||||
Close();
|
||||
DialogResult = DataContext is FEndpoint { IsValid: true };
|
||||
}
|
||||
|
||||
private async void OnSend(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await new RestClient().ExecuteAsync(new FRestRequest(EndpointUrl.Text)
|
||||
{
|
||||
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
|
||||
}).ConfigureAwait(false);
|
||||
_body = JObject.Parse(response.Content!);
|
||||
if (DataContext is not FEndpoint endpoint) return;
|
||||
|
||||
Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
EndpointResponse.Document = new TextDocument
|
||||
{
|
||||
Text = _body.ToString(Formatting.Indented)
|
||||
};
|
||||
});
|
||||
}
|
||||
catch
|
||||
var response = await new RestClient().ExecuteAsync(new FRestRequest(endpoint.Url)
|
||||
{
|
||||
//
|
||||
}
|
||||
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
|
||||
}).ConfigureAwait(false);
|
||||
var body = JToken.Parse(response.Content!);
|
||||
|
||||
Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
EndpointResponse.Document ??= new TextDocument();
|
||||
EndpointResponse.Document.Text = body.ToString(Formatting.Indented);
|
||||
});
|
||||
}
|
||||
|
||||
private void OnTest(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not FEndpoint endpoint) return;
|
||||
|
||||
endpoint.TryValidate(ApplicationService.ApiEndpointView.DynamicApi, _type, out var response);
|
||||
_isTested = true;
|
||||
|
||||
TargetResponse.Document ??= new TextDocument();
|
||||
TargetResponse.Document.Text = JsonConvert.SerializeObject(response, Formatting.Indented);
|
||||
}
|
||||
|
||||
private void OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (sender is not TextBox { IsLoaded: true } ||
|
||||
DataContext is not FEndpoint endpoint) return;
|
||||
endpoint.IsValid = false;
|
||||
}
|
||||
|
||||
private void OnEvaluator(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo { FileName = "https://jsonpath.herokuapp.com/", UseShellExecute = true });
|
||||
}
|
||||
|
||||
private void OnClosing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (!_isTested) OnTest(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ public class EndpointToTypeConverter : IMultiValueConverter
|
|||
values[1] is not EEndpointType type)
|
||||
return false;
|
||||
|
||||
var isEnabled = UserSettings.IsEndpointEnabled(viewModel.CUE4Parse.Game, type, out _);
|
||||
var isValid = UserSettings.IsEndpointValid(viewModel.CUE4Parse.Game, type, out _);
|
||||
return targetType switch
|
||||
{
|
||||
not null when targetType == typeof(Visibility) => isEnabled ? Visibility.Visible : Visibility.Collapsed,
|
||||
not null when targetType == typeof(Visibility) => isValid ? Visibility.Visible : Visibility.Collapsed,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,11 +201,11 @@
|
|||
|
||||
<TextBlock Grid.Row="13" Grid.Column="0" Text="AES Reload at Launch" VerticalAlignment="Center" Margin="0 0 0 5"
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}"
|
||||
Visibility="{Binding SettingsView.AesEndpoint.IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
Visibility="{Binding SettingsView.AesEndpoint.IsValid, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<ComboBox Grid.Row="13" Grid.Column="2" Grid.ColumnSpan="5" Margin="0 0 0 5"
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}"
|
||||
ItemsSource="{Binding SettingsView.AesReloads}" SelectedItem="{Binding SettingsView.SelectedAesReload, Mode=TwoWay}"
|
||||
Visibility="{Binding SettingsView.AesEndpoint.IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
Visibility="{Binding SettingsView.AesEndpoint.IsValid, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Converter={x:Static converters:EnumToStringConverter.Instance}}" />
|
||||
|
|
@ -219,18 +219,17 @@
|
|||
|
||||
<TextBlock Grid.Row="15" Grid.Column="0" Text="Overwrite Mapping File" VerticalAlignment="Center" Margin="0 0 0 5"
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}"
|
||||
Visibility="{Binding SettingsView.MappingEndpoint.IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
Visibility="{Binding SettingsView.MappingEndpoint.IsValid, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<CheckBox Grid.Row="15" Grid.Column="2" Margin="0 5 0 10"
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}"
|
||||
Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
Visibility="{Binding SettingsView.MappingEndpoint.IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
Visibility="{Binding SettingsView.MappingEndpoint.IsValid, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
IsChecked="{Binding SettingsView.MappingEndpoint.Overwrite, Mode=TwoWay}" />
|
||||
|
||||
<TextBlock Grid.Row="16" Grid.Column="0" Text="Mapping File Path" VerticalAlignment="Center" Margin="0 0 0 5"
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}"
|
||||
Visibility="{Binding SettingsView.MappingEndpoint.Overwrite, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
</TextBlock>
|
||||
<TextBox Grid.Row="16" Grid.Column="2" Grid.ColumnSpan="3" Margin="0 0 0 5" Text="{Binding SettingsView.MappingEndpoint.Path, Mode=TwoWay}"
|
||||
Visibility="{Binding SettingsView.MappingEndpoint.Overwrite, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<TextBox Grid.Row="16" Grid.Column="2" Grid.ColumnSpan="3" Margin="0 0 0 5" Text="{Binding SettingsView.MappingEndpoint.FilePath, Mode=TwoWay}"
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}"
|
||||
Visibility="{Binding SettingsView.MappingEndpoint.Overwrite, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<Button Grid.Row="16" Grid.Column="6" Content="..." HorizontalAlignment="Right" Click="OnBrowseMappings" Margin="0 0 0 5"
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public partial class SettingsView
|
|||
if (!openFileDialog.ShowDialog().GetValueOrDefault())
|
||||
return;
|
||||
|
||||
_applicationView.SettingsView.MappingEndpoint.Path = openFileDialog.FileName;
|
||||
_applicationView.SettingsView.MappingEndpoint.FilePath = openFileDialog.FileName;
|
||||
await _applicationView.CUE4Parse.InitBenMappings();
|
||||
}
|
||||
|
||||
|
|
@ -173,26 +173,14 @@ public partial class SettingsView
|
|||
private void OpenAesEndpoint(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var editor = new EndpointEditor(
|
||||
_applicationView.SettingsView.AesEndpoint,
|
||||
"Endpoint Configuration (AES)",
|
||||
EEndpointType.Aes);
|
||||
var result = editor.ShowDialog();
|
||||
if (!result.HasValue || !result.Value)
|
||||
return;
|
||||
|
||||
_applicationView.SettingsView.AesEndpoint = editor.Endpoint;
|
||||
_applicationView.SettingsView.AesEndpoint, "Endpoint Configuration (AES)", EEndpointType.Aes);
|
||||
editor.ShowDialog();
|
||||
}
|
||||
|
||||
private void OpenMappingEndpoint(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var editor = new EndpointEditor(
|
||||
_applicationView.SettingsView.MappingEndpoint,
|
||||
"Endpoint Configuration (Mapping)",
|
||||
EEndpointType.Mapping);
|
||||
var result = editor.ShowDialog();
|
||||
if (!result.HasValue || !result.Value)
|
||||
return;
|
||||
|
||||
_applicationView.SettingsView.MappingEndpoint = editor.Endpoint;
|
||||
_applicationView.SettingsView.MappingEndpoint, "Endpoint Configuration (Mapping)", EEndpointType.Mapping);
|
||||
editor.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user