Compare commits
No commits in common. "master" and "4.0.0" have entirely different histories.
164
.editorconfig
|
|
@ -1,164 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
# C# files
|
|
||||||
[*.cs]
|
|
||||||
indent_size = 4
|
|
||||||
# New line preferences
|
|
||||||
csharp_new_line_before_open_brace = all
|
|
||||||
csharp_new_line_before_else = true
|
|
||||||
csharp_new_line_before_catch = true
|
|
||||||
csharp_new_line_before_finally = true
|
|
||||||
csharp_new_line_before_members_in_object_initializers = true
|
|
||||||
csharp_new_line_before_members_in_anonymous_types = true
|
|
||||||
csharp_new_line_within_query_expression_clauses = true
|
|
||||||
|
|
||||||
# Code files
|
|
||||||
[*.{cs,csx,vb,vbx}]
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
# Indentation preferences
|
|
||||||
csharp_indent_block_contents = true
|
|
||||||
csharp_indent_braces = false
|
|
||||||
csharp_indent_case_contents = true
|
|
||||||
csharp_indent_switch_labels = true
|
|
||||||
csharp_indent_labels = one_less_than_current
|
|
||||||
|
|
||||||
# avoid this. unless absolutely necessary
|
|
||||||
dotnet_style_qualification_for_field = false:suggestion
|
|
||||||
dotnet_style_qualification_for_property = false:suggestion
|
|
||||||
dotnet_style_qualification_for_method = false:suggestion
|
|
||||||
dotnet_style_qualification_for_event = false:suggestion
|
|
||||||
|
|
||||||
# only use var when it's obvious what the variable type is
|
|
||||||
csharp_style_var_for_built_in_types = false:none
|
|
||||||
csharp_style_var_when_type_is_apparent = false:none
|
|
||||||
csharp_style_var_elsewhere = false:suggestion
|
|
||||||
|
|
||||||
# use language keywords instead of BCL types
|
|
||||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
|
||||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
|
||||||
|
|
||||||
# name all constant fields using PascalCase
|
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
|
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
|
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
|
|
||||||
|
|
||||||
dotnet_naming_symbols.constant_fields.applicable_kinds = field
|
|
||||||
dotnet_naming_symbols.constant_fields.required_modifiers = const
|
|
||||||
|
|
||||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
|
||||||
|
|
||||||
# internal and private fields should be _camelCase
|
|
||||||
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
|
|
||||||
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
|
|
||||||
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
|
|
||||||
|
|
||||||
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
|
|
||||||
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
|
|
||||||
|
|
||||||
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
|
|
||||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
|
||||||
|
|
||||||
# Code style defaults
|
|
||||||
dotnet_sort_system_directives_first = true
|
|
||||||
csharp_preserve_single_line_blocks = true
|
|
||||||
csharp_preserve_single_line_statements = false
|
|
||||||
|
|
||||||
# Expression-level preferences
|
|
||||||
dotnet_style_object_initializer = true:suggestion
|
|
||||||
dotnet_style_collection_initializer = true:suggestion
|
|
||||||
dotnet_style_explicit_tuple_names = true:suggestion
|
|
||||||
dotnet_style_coalesce_expression = true:suggestion
|
|
||||||
dotnet_style_null_propagation = true:suggestion
|
|
||||||
|
|
||||||
# Expression-bodied members
|
|
||||||
csharp_style_expression_bodied_methods = false:none
|
|
||||||
csharp_style_expression_bodied_constructors = false:none
|
|
||||||
csharp_style_expression_bodied_operators = false:none
|
|
||||||
csharp_style_expression_bodied_properties = true:none
|
|
||||||
csharp_style_expression_bodied_indexers = true:none
|
|
||||||
csharp_style_expression_bodied_accessors = true:none
|
|
||||||
|
|
||||||
# Pattern matching
|
|
||||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
|
||||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
|
||||||
csharp_style_inlined_variable_declaration = true:suggestion
|
|
||||||
|
|
||||||
# Null checking preferences
|
|
||||||
csharp_style_throw_expression = true:suggestion
|
|
||||||
csharp_style_conditional_delegate_call = true:suggestion
|
|
||||||
|
|
||||||
# Space preferences
|
|
||||||
csharp_space_after_cast = true
|
|
||||||
csharp_space_after_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_after_comma = true
|
|
||||||
csharp_space_after_dot = false
|
|
||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
|
||||||
csharp_space_after_semicolon_in_for_statement = true
|
|
||||||
csharp_space_around_binary_operators = before_and_after
|
|
||||||
csharp_space_around_declaration_statements = do_not_ignore
|
|
||||||
csharp_space_before_colon_in_inheritance_clause = true
|
|
||||||
csharp_space_before_comma = false
|
|
||||||
csharp_space_before_dot = false
|
|
||||||
csharp_space_before_open_square_brackets = false
|
|
||||||
csharp_space_before_semicolon_in_for_statement = false
|
|
||||||
csharp_space_between_empty_square_brackets = false
|
|
||||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
|
||||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
|
||||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
|
||||||
csharp_space_between_parentheses = false
|
|
||||||
csharp_space_between_square_brackets = false
|
|
||||||
|
|
||||||
[*.{asm,inc}]
|
|
||||||
indent_size = 8
|
|
||||||
|
|
||||||
# Visual Studio Solution Files
|
|
||||||
[*.sln]
|
|
||||||
indent_style = tab
|
|
||||||
|
|
||||||
# Visual Studio XML Project Files
|
|
||||||
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# XML Configuration Files
|
|
||||||
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[CMakeLists.txt]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# Makefiles
|
|
||||||
[Makefile]
|
|
||||||
indent_style = tab
|
|
||||||
|
|
||||||
# Batch Files
|
|
||||||
[*.{cmd,bat}]
|
|
||||||
indent_size = 2
|
|
||||||
end_of_line = crlf
|
|
||||||
|
|
||||||
# Bash Files
|
|
||||||
[*.sh]
|
|
||||||
end_of_line = lf
|
|
||||||
|
|
||||||
# Web Files
|
|
||||||
[*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,pcss,svg,vue}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# Markdown Files
|
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
||||||
# JSON Files
|
|
||||||
[*.{json,json5,webmanifest}]
|
|
||||||
indent_size = 2
|
|
||||||
1
.github/FUNDING.yml
vendored
|
|
@ -1 +0,0 @@
|
||||||
custom: "https://fmodel.app/donate"
|
|
||||||
45
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
|
@ -1,45 +0,0 @@
|
||||||
name: Bug Report
|
|
||||||
description: File a bug report
|
|
||||||
title: "Bug Title"
|
|
||||||
labels: [bug]
|
|
||||||
assignees:
|
|
||||||
- iAmAsval
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thanks for taking the time to fill out this bug report! Keep in mind that screenshots and log files help us a lot so don't forget to provide one or both of those (drag and drop files in a text area).
|
|
||||||
Your bug report will be closed without explanation if you don't follow the following rules:
|
|
||||||
- Bad bug explanation will result in bad support and probably on a negative tone
|
|
||||||
- This template shouldn't be used to ask how to use FModel or a certain feature FModel provides
|
|
||||||
- Bug reports must always use the latest FModel with the latest available version of the game you use
|
|
||||||
- If you can't load files, it's probably because of your AES key, no need to file a report
|
|
||||||
- We absolutely do not support modding
|
|
||||||
- type: input
|
|
||||||
id: game
|
|
||||||
attributes:
|
|
||||||
label: Game
|
|
||||||
placeholder: ex. Fortnite, Valorant, ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: error
|
|
||||||
attributes:
|
|
||||||
label: Error
|
|
||||||
description: Tell us what FModel says about the error, from the console and / or the log file
|
|
||||||
placeholder: ex. [ERR] Could not export 'EditorClientAssetRegistry.bin'
|
|
||||||
render: shell
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: repro
|
|
||||||
attributes:
|
|
||||||
label: Reproduction steps
|
|
||||||
description: How do you trigger this bug? Please walk us through it step by step.
|
|
||||||
placeholder: |
|
|
||||||
1.
|
|
||||||
2.
|
|
||||||
3.
|
|
||||||
...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -1,5 +0,0 @@
|
||||||
blank_issues_enabled: true
|
|
||||||
contact_links:
|
|
||||||
- name: Discord Server
|
|
||||||
url: https://fmodel.app/discord
|
|
||||||
about: Please ask and answer questions here.
|
|
||||||
22
.github/ISSUE_TEMPLATE/feature.yml
vendored
|
|
@ -1,22 +0,0 @@
|
||||||
name: Feature Request
|
|
||||||
description: Submit a new feature request
|
|
||||||
title: "Feature Title"
|
|
||||||
labels: [suggestion]
|
|
||||||
assignees:
|
|
||||||
- iAmAsval
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thanks for taking the time to fill out this feature request! Before going any further, make sure what you're about to submit doesn't already exist.
|
|
||||||
Your feature request will be closed without explanation if you don't follow the following rules:
|
|
||||||
- This template shouldn't be used to ask how to use FModel or a certain feature FModel provides
|
|
||||||
- We absolutely do not support modding
|
|
||||||
- type: textarea
|
|
||||||
id: description
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: Tell us what you want FModel to be able to do
|
|
||||||
placeholder: Please describe with details and how it could be done if possible...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
36
.github/workflows/main.yml
vendored
|
|
@ -1,12 +1,7 @@
|
||||||
name: FModel Builder
|
name: Artifact Generator
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
|
||||||
appVersion:
|
|
||||||
description: 'FModel Version And Release Tag'
|
|
||||||
required: true
|
|
||||||
default: '4.0.X.X'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
@ -17,32 +12,21 @@ jobs:
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
token: ${{ secrets.PAT_TOKEN }}
|
||||||
|
|
||||||
- name: Fetch Submodules Recursively
|
- name: .NET 5 Setup
|
||||||
run: git submodule update --init --recursive
|
uses: actions/setup-dotnet@v1
|
||||||
|
|
||||||
- name: .NET 8 Setup
|
|
||||||
uses: actions/setup-dotnet@v2
|
|
||||||
with:
|
with:
|
||||||
dotnet-version: '8.0.x'
|
dotnet-version: 5.0.x
|
||||||
|
|
||||||
- name: .NET Restore
|
- name: .NET Restore
|
||||||
run: dotnet restore FModel
|
run: dotnet restore FModel
|
||||||
|
|
||||||
- name: .NET Publish
|
- name: .NET Publish
|
||||||
run: dotnet publish FModel -c Release --no-self-contained -r win-x64 -f net8.0-windows -o "./FModel/bin/Publish/" -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:DebugType=None -p:GenerateDocumentationFile=false -p:DebugSymbols=false -p:AssemblyVersion=${{ github.event.inputs.appVersion }} -p:FileVersion=${{ github.event.inputs.appVersion }}
|
run: dotnet publish FModel -c Release -f net5.0-windows -o "./FModel/bin/Publish/" -p:PublishReadyToRun=true -p:PublishSingleFile=true -p:DebugType=None -p:GenerateDocumentationFile=false -p:DebugSymbols=false --no-self-contained -r win-x64
|
||||||
|
|
||||||
- name: ZIP File
|
- name: EXE Upload
|
||||||
uses: papeloto/action-zip@v1
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
files: ./FModel/bin/Publish/FModel.exe
|
name: FModel
|
||||||
dest: FModel.zip # will end up in working directory not the Publish folder
|
path: D:\a\FModel\FModel\FModel\bin\Publish\
|
||||||
|
|
||||||
- name: GIT Release
|
|
||||||
uses: marvinpinto/action-automatic-releases@latest
|
|
||||||
with:
|
|
||||||
title: "FModel v${{ github.event.inputs.appVersion }}"
|
|
||||||
automatic_release_tag: ${{ github.event.inputs.appVersion }}
|
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
prerelease: false
|
|
||||||
files: FModel.zip
|
|
||||||
|
|
|
||||||
65
.github/workflows/qa.yml
vendored
|
|
@ -1,65 +0,0 @@
|
||||||
name: FModel QA Builder
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ dev ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: GIT Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: 'recursive'
|
|
||||||
|
|
||||||
- name: .NET 8 Setup
|
|
||||||
uses: actions/setup-dotnet@v4
|
|
||||||
with:
|
|
||||||
dotnet-version: '8.0.x'
|
|
||||||
|
|
||||||
- name: .NET Restore
|
|
||||||
run: dotnet restore FModel
|
|
||||||
|
|
||||||
- name: .NET Publish
|
|
||||||
run: dotnet publish "./FModel/FModel.csproj" -c Release --no-restore --no-self-contained -r win-x64 -f net8.0-windows -o "./FModel/bin/Publish/" -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:DebugType=None -p:GenerateDocumentationFile=false -p:DebugSymbols=false
|
|
||||||
|
|
||||||
- name: ZIP File
|
|
||||||
uses: thedoctor0/zip-release@0.7.6
|
|
||||||
with:
|
|
||||||
type: zip
|
|
||||||
filename: ${{ github.sha }}.zip # will end up in working directory not the Publish folder
|
|
||||||
path: ./FModel/bin/Publish/FModel.exe
|
|
||||||
|
|
||||||
- name: Edit QA Artifact
|
|
||||||
uses: ncipollo/release-action@v1.14.0
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
name: 'FModel QA Testing'
|
|
||||||
body: 'Dev builds'
|
|
||||||
tag: 'qa'
|
|
||||||
artifacts: ${{ github.sha }}.zip
|
|
||||||
prerelease: true
|
|
||||||
allowUpdates: true
|
|
||||||
|
|
||||||
- name: Get Version
|
|
||||||
id: package_version
|
|
||||||
uses: kzrnm/get-net-sdk-project-versions-action@v2
|
|
||||||
with:
|
|
||||||
proj-path: ./FModel/FModel.csproj
|
|
||||||
|
|
||||||
- name: FModel Auth
|
|
||||||
id: fmodel_auth
|
|
||||||
uses: fjogeleit/http-request-action@v1.15.5
|
|
||||||
with:
|
|
||||||
url: "https://api.fmodel.app/v1/oauth/token"
|
|
||||||
data: '{"username": "${{ secrets.API_USERNAME }}", "password": "${{ secrets.API_PASSWORD }}"}'
|
|
||||||
|
|
||||||
- name: FModel Deploy Build
|
|
||||||
uses: fjogeleit/http-request-action@v1.15.5
|
|
||||||
with:
|
|
||||||
url: "https://api.fmodel.app/v1/infos/${{ secrets.QA_ID }}"
|
|
||||||
method: "PATCH"
|
|
||||||
bearerToken: ${{ fromJson(steps.fmodel_auth.outputs.response).accessToken }}
|
|
||||||
data: '{"version": "${{ steps.package_version.outputs.version }}-dev+${{ github.sha }}", "downloadUrl": "https://github.com/4sval/FModel/releases/download/qa/${{ github.sha }}.zip"}'
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 455b72e5e38bfe9476b5823bc642fc8ef488347f
|
Subproject commit 09a98cdafd273db1cdee58ded37ed4f5b3a2ff22
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using AdonisUI.Controls;
|
using AdonisUI.Controls;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using FModel.Framework;
|
using FModel.Framework;
|
||||||
|
|
@ -16,25 +16,15 @@ using MessageBox = AdonisUI.Controls.MessageBox;
|
||||||
using MessageBoxImage = AdonisUI.Controls.MessageBoxImage;
|
using MessageBoxImage = AdonisUI.Controls.MessageBoxImage;
|
||||||
using MessageBoxResult = AdonisUI.Controls.MessageBoxResult;
|
using MessageBoxResult = AdonisUI.Controls.MessageBoxResult;
|
||||||
|
|
||||||
namespace FModel;
|
namespace FModel
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for App.xaml
|
/// Interaction logic for App.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class App
|
public partial class App
|
||||||
{
|
{
|
||||||
[DllImport("kernel32.dll")]
|
|
||||||
private static extern bool AttachConsole(int dwProcessId);
|
|
||||||
|
|
||||||
[DllImport("winbrand.dll", CharSet = CharSet.Unicode)]
|
|
||||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
|
||||||
static extern string BrandingFormatString(string format);
|
|
||||||
|
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
|
||||||
AttachConsole(-1);
|
|
||||||
#endif
|
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -47,69 +37,28 @@ public partial class App
|
||||||
UserSettings.Default = new UserSettings();
|
UserSettings.Default = new UserSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
var createMe = false;
|
|
||||||
if (!Directory.Exists(UserSettings.Default.OutputDirectory))
|
if (!Directory.Exists(UserSettings.Default.OutputDirectory))
|
||||||
{
|
{
|
||||||
var currentDir = Directory.GetCurrentDirectory();
|
UserSettings.Default.OutputDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Output");
|
||||||
var dirInfo = new DirectoryInfo(currentDir);
|
|
||||||
if (dirInfo.Attributes.HasFlag(FileAttributes.Archive))
|
|
||||||
throw new Exception("FModel cannot be run from an archive file. Please extract it and try again.");
|
|
||||||
if (dirInfo.Attributes.HasFlag(FileAttributes.ReadOnly))
|
|
||||||
throw new Exception("FModel cannot be run from a read-only directory. Please move it to a writable location.");
|
|
||||||
|
|
||||||
UserSettings.Default.OutputDirectory = Path.Combine(currentDir, "Output");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(UserSettings.Default.RawDataDirectory))
|
|
||||||
{
|
|
||||||
createMe = true;
|
|
||||||
UserSettings.Default.RawDataDirectory = Path.Combine(UserSettings.Default.OutputDirectory, "Exports");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(UserSettings.Default.PropertiesDirectory))
|
|
||||||
{
|
|
||||||
createMe = true;
|
|
||||||
UserSettings.Default.PropertiesDirectory = Path.Combine(UserSettings.Default.OutputDirectory, "Exports");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(UserSettings.Default.TextureDirectory))
|
|
||||||
{
|
|
||||||
createMe = true;
|
|
||||||
UserSettings.Default.TextureDirectory = Path.Combine(UserSettings.Default.OutputDirectory, "Exports");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(UserSettings.Default.AudioDirectory))
|
|
||||||
{
|
|
||||||
createMe = true;
|
|
||||||
UserSettings.Default.AudioDirectory = Path.Combine(UserSettings.Default.OutputDirectory, "Exports");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Directory.Exists(UserSettings.Default.ModelDirectory))
|
|
||||||
{
|
|
||||||
createMe = true;
|
|
||||||
UserSettings.Default.ModelDirectory = Path.Combine(UserSettings.Default.OutputDirectory, "Exports");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FModel"));
|
Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FModel"));
|
||||||
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Backups"));
|
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Backups"));
|
||||||
if (createMe) Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Exports"));
|
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Exports"));
|
||||||
|
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Saves"));
|
||||||
|
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Textures"));
|
||||||
|
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Sounds"));
|
||||||
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Logs"));
|
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, "Logs"));
|
||||||
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data"));
|
Directory.CreateDirectory(Path.Combine(UserSettings.Default.OutputDirectory, ".data"));
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
Log.Logger = new LoggerConfiguration().WriteTo.Console(theme: AnsiConsoleTheme.Literate).WriteTo.File(
|
Log.Logger = new LoggerConfiguration().WriteTo.Console(theme: AnsiConsoleTheme.Literate).WriteTo.File(
|
||||||
Path.Combine(UserSettings.Default.OutputDirectory, "Logs", $"FModel-Debug-Log-{DateTime.Now:yyyy-MM-dd}.txt"),
|
path: Path.Combine(UserSettings.Default.OutputDirectory, "Logs", $"FModel-Log-{DateTime.Now:yyyy-MM-dd}.txt"),
|
||||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [FModel] [{Level:u3}] {Message:lj}{NewLine}{Exception}").CreateLogger();
|
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [FModel] [{Level:u3}] {Message:lj}{NewLine}{Exception}").CreateLogger();
|
||||||
#else
|
|
||||||
Log.Logger = new LoggerConfiguration().WriteTo.Console(theme: AnsiConsoleTheme.Literate).WriteTo.File(
|
|
||||||
Path.Combine(UserSettings.Default.OutputDirectory, "Logs", $"FModel-Log-{DateTime.Now:yyyy-MM-dd}.txt"),
|
|
||||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [FModel] [{Level:u3}] {Message:lj}{NewLine}{Exception}").CreateLogger();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Log.Information("Version {Version} ({CommitId})", Constants.APP_VERSION, Constants.APP_COMMIT_ID);
|
Log.Information("Version {Version}", Constants.APP_VERSION);
|
||||||
Log.Information("{OS}", GetOperatingSystemProductName());
|
Log.Information("{OS}", GetOperatingSystemProductName());
|
||||||
Log.Information("{RuntimeVer}", RuntimeInformation.FrameworkDescription);
|
Log.Information("{RuntimeVer}", RuntimeInformation.FrameworkDescription);
|
||||||
Log.Information("Culture {SysLang}", CultureInfo.CurrentCulture);
|
Log.Information("Culture {SysLang}", Thread.CurrentThread.CurrentUICulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AppExit(object sender, ExitEventArgs e)
|
private void AppExit(object sender, ExitEventArgs e)
|
||||||
|
|
@ -131,7 +80,6 @@ public partial class App
|
||||||
Icon = MessageBoxImage.Error,
|
Icon = MessageBoxImage.Error,
|
||||||
Buttons = new[]
|
Buttons = new[]
|
||||||
{
|
{
|
||||||
MessageBoxButtons.Custom("Reset Settings", EErrorKind.ResetSettings),
|
|
||||||
MessageBoxButtons.Custom("Restart", EErrorKind.Restart),
|
MessageBoxButtons.Custom("Restart", EErrorKind.Restart),
|
||||||
MessageBoxButtons.Custom("OK", EErrorKind.Ignore)
|
MessageBoxButtons.Custom("OK", EErrorKind.Ignore)
|
||||||
},
|
},
|
||||||
|
|
@ -141,9 +89,6 @@ public partial class App
|
||||||
MessageBox.Show(messageBox);
|
MessageBox.Show(messageBox);
|
||||||
if (messageBox.Result == MessageBoxResult.Custom && (EErrorKind) messageBox.ButtonPressed.Id != EErrorKind.Ignore)
|
if (messageBox.Result == MessageBoxResult.Custom && (EErrorKind) messageBox.ButtonPressed.Id != EErrorKind.Ignore)
|
||||||
{
|
{
|
||||||
if ((EErrorKind) messageBox.ButtonPressed.Id == EErrorKind.ResetSettings)
|
|
||||||
UserSettings.Delete();
|
|
||||||
|
|
||||||
ApplicationService.ApplicationView.Restart();
|
ApplicationService.ApplicationView.Restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +100,7 @@ public partial class App
|
||||||
var productName = string.Empty;
|
var productName = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
productName = BrandingFormatString("%WINDOWS_LONG%");
|
productName = GetRegistryValue(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName", RegistryHive.LocalMachine);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
@ -168,7 +113,7 @@ public partial class App
|
||||||
return $"{productName} ({(Environment.Is64BitOperatingSystem ? "64" : "32")}-bit)";
|
return $"{productName} ({(Environment.Is64BitOperatingSystem ? "64" : "32")}-bit)";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetRegistryValue(string path, string name = null, RegistryHive root = RegistryHive.CurrentUser)
|
private string GetRegistryValue(string path, string name = null, RegistryHive root = RegistryHive.CurrentUser)
|
||||||
{
|
{
|
||||||
using var rk = RegistryKey.OpenBaseKey(root, RegistryView.Default).OpenSubKey(path);
|
using var rk = RegistryKey.OpenBaseKey(root, RegistryView.Default).OpenSubKey(path);
|
||||||
if (rk != null)
|
if (rk != null)
|
||||||
|
|
@ -176,3 +121,4 @@ public partial class App
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,57 +1,63 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||||
using FModel.Extensions;
|
|
||||||
|
|
||||||
namespace FModel;
|
|
||||||
|
|
||||||
|
namespace FModel
|
||||||
|
{
|
||||||
public static class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
public static readonly string APP_PATH = Path.GetFullPath(Environment.GetCommandLineArgs()[0]);
|
public static readonly string APP_VERSION = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
|
||||||
public static readonly string APP_VERSION = FileVersionInfo.GetVersionInfo(APP_PATH).FileVersion;
|
|
||||||
public static readonly string APP_COMMIT_ID = FileVersionInfo.GetVersionInfo(APP_PATH).ProductVersion.SubstringAfter('+');
|
|
||||||
public static readonly string APP_SHORT_COMMIT_ID = APP_COMMIT_ID[..7];
|
|
||||||
|
|
||||||
public const string ZERO_64_CHAR = "0000000000000000000000000000000000000000000000000000000000000000";
|
public const string ZERO_64_CHAR = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||||
public static readonly FGuid ZERO_GUID = new(0U);
|
public static readonly FGuid ZERO_GUID = new(0U);
|
||||||
|
|
||||||
public const float SCALE_DOWN_RATIO = 0.01F;
|
|
||||||
public const int SAMPLES_COUNT = 4;
|
|
||||||
|
|
||||||
public const string WHITE = "#DAE5F2";
|
public const string WHITE = "#DAE5F2";
|
||||||
public const string GRAY = "#BBBBBB";
|
|
||||||
public const string RED = "#E06C75";
|
public const string RED = "#E06C75";
|
||||||
public const string GREEN = "#98C379";
|
public const string GREEN = "#98C379";
|
||||||
public const string YELLOW = "#E5C07B";
|
public const string YELLOW = "#E5C07B";
|
||||||
public const string BLUE = "#528BCC";
|
public const string BLUE = "#528BCC";
|
||||||
|
|
||||||
public const string ISSUE_LINK = "https://github.com/4sval/FModel/discussions/categories/q-a";
|
public const string DONATE_LINK = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=EP9SSWG8MW4UC&source=url";
|
||||||
public const string GH_REPO = "https://api.github.com/repos/4sval/FModel";
|
public const string CHANGELOG_LINK = "https://github.com/iAmAsval/FModel/releases/latest";
|
||||||
public const string GH_COMMITS_HISTORY = GH_REPO + "/commits";
|
public const string ISSUE_LINK = "https://github.com/iAmAsval/FModel/issues/new";
|
||||||
public const string GH_RELEASES = GH_REPO + "/releases";
|
public const string DISCORD_LINK = "https://discord.gg/fdkNYYQ";
|
||||||
public const string DONATE_LINK = "https://fmodel.app/donate";
|
|
||||||
public const string DISCORD_LINK = "https://fmodel.app/discord";
|
|
||||||
|
|
||||||
public const string _FN_LIVE_TRIGGER = "fortnite-live.manifest";
|
public const string _FN_LIVE_TRIGGER = "fortnite-live.manifest";
|
||||||
public const string _VAL_LIVE_TRIGGER = "valorant-live.manifest";
|
public const string _VAL_LIVE_TRIGGER = "valorant-live.manifest";
|
||||||
|
|
||||||
public const string _NO_PRESET_TRIGGER = "Hand Made";
|
public static string GetRandomColor()
|
||||||
|
|
||||||
public static int PALETTE_LENGTH => COLOR_PALETTE.Length;
|
|
||||||
public static readonly Vector3[] COLOR_PALETTE =
|
|
||||||
{
|
{
|
||||||
new (0.231f, 0.231f, 0.231f), // Dark gray
|
return _randomColors[_random.Next(0, 255)];
|
||||||
new (0.376f, 0.490f, 0.545f), // Teal
|
}
|
||||||
new (0.957f, 0.263f, 0.212f), // Red
|
|
||||||
new (0.196f, 0.804f, 0.196f), // Green
|
private static readonly Random _random = new(Environment.TickCount);
|
||||||
new (0.957f, 0.647f, 0.212f), // Orange
|
private static readonly string[] _randomColors =
|
||||||
new (0.612f, 0.153f, 0.690f), // Purple
|
{
|
||||||
new (0.129f, 0.588f, 0.953f), // Blue
|
"F44336", "FFEBEE", "FFCDD2", "EF9A9A", "E57373", "EF5350", "E53935", "D32F2F", "C62828", "B71C1C",
|
||||||
new (1.000f, 0.920f, 0.424f), // Yellow
|
"FF8A80", "FF5252", "FF1744", "D50000", "FCE4EC", "F8BBD0", "F48FB1", "F06292", "EC407A", "E91E63",
|
||||||
new (0.824f, 0.412f, 0.118f), // Brown
|
"D81B60", "C2185B", "AD1457", "880E4F", "FF80AB", "FF4081", "F50057", "C51162", "F3E5F5", "E1BEE7",
|
||||||
new (0.612f, 0.800f, 0.922f) // Light blue
|
"CE93D8", "BA68C8", "AB47BC", "9C27B0", "8E24AA", "7B1FA2", "6A1B9A", "4A148C", "EA80FC", "E040FB",
|
||||||
|
"D500F9", "AA00FF", "EDE7F6", "D1C4E9", "B39DDB", "9575CD", "7E57C2", "673AB7", "5E35B1", "512DA8",
|
||||||
|
"4527A0", "311B92", "B388FF", "7C4DFF", "651FFF", "6200EA", "E8EAF6", "C5CAE9", "9FA8DA", "7986CB",
|
||||||
|
"5C6BC0", "3F51B5", "3949AB", "303F9F", "283593", "1A237E", "8C9EFF", "536DFE", "3D5AFE", "304FFE",
|
||||||
|
"E3F2FD", "BBDEFB", "90CAF9", "64B5F6", "42A5F5", "2196F3", "1E88E5", "1976D2", "1565C0", "0D47A1",
|
||||||
|
"82B1FF", "448AFF", "2979FF", "2962FF", "E1F5FE", "B3E5FC", "81D4FA", "4FC3F7", "29B6F6", "03A9F4",
|
||||||
|
"039BE5", "0288D1", "0277BD", "01579B", "80D8FF", "40C4FF", "00B0FF", "0091EA", "E0F7FA", "B2EBF2",
|
||||||
|
"80DEEA", "4DD0E1", "26C6DA", "00BCD4", "00ACC1", "0097A7", "00838F", "006064", "84FFFF", "18FFFF",
|
||||||
|
"00E5FF", "00B8D4", "E0F2F1", "B2DFDB", "80CBC4", "4DB6AC", "26A69A", "009688", "00897B", "00796B",
|
||||||
|
"00695C", "004D40", "A7FFEB", "64FFDA", "1DE9B6", "00BFA5", "E8F5E9", "C8E6C9", "A5D6A7", "81C784",
|
||||||
|
"66BB6A", "4CAF50", "43A047", "388E3C", "2E7D32", "1B5E20", "B9F6CA", "69F0AE", "00E676", "00C853",
|
||||||
|
"F1F8E9", "DCEDC8", "C5E1A5", "AED581", "9CCC65", "8BC34A", "7CB342", "689F38", "558B2F", "33691E",
|
||||||
|
"CCFF90", "B2FF59", "76FF03", "64DD17", "F9FBE7", "F0F4C3", "E6EE9C", "DCE775", "D4E157", "CDDC39",
|
||||||
|
"C0CA33", "AFB42B", "9E9D24", "827717", "F4FF81", "EEFF41", "C6FF00", "AEEA00", "FFFDE7", "FFF9C4",
|
||||||
|
"FFF59D", "FFF176", "FFEE58", "FFEB3B", "FDD835", "FBC02D", "F9A825", "F57F17", "FFFF8D", "FFFF00",
|
||||||
|
"FFEA00", "FFD600", "FFF8E1", "FFECB3", "FFE082", "FFD54F", "FFCA28", "FFC107", "FFB300", "FFA000",
|
||||||
|
"FF8F00", "FF6F00", "FFE57F", "FFD740", "FFC400", "FFAB00", "FFF3E0", "FFE0B2", "FFCC80", "FFB74D",
|
||||||
|
"FFA726", "FF9800", "FB8C00", "F57C00", "EF6C00", "E65100", "FFD180", "FFAB40", "FF9100", "FF6D00",
|
||||||
|
"FBE9E7", "FFCCBC", "FFAB91", "FF8A65", "FF7043", "FF5722", "F4511E", "E64A19", "D84315", "BF360C",
|
||||||
|
"FF9E80", "FF6E40", "FF3D00", "DD2C00", "EFEBE9", "D7CCC8", "BCAAA4", "A1887F", "8D6E63", "795548",
|
||||||
|
"6D4C41", "5D4037", "4E342E", "3E2723", "FAFAFA", "F5F5F5", "EEEEEE", "E0E0E0", "BDBDBD", "9E9E9E",
|
||||||
|
"757575", "616161", "424242", "212121", "ECEFF1", "CFD8DC", "B0BEC5", "90A4AE", "78909C", "607D8B",
|
||||||
|
"546E7A", "455A64", "37474F", "263238", "000000",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using FModel.Creator.Bases.FN;
|
using FModel.Creator.Bases.FN;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.BB;
|
namespace FModel.Creator.Bases.BB
|
||||||
|
{
|
||||||
public class BaseBreakersIcon : BaseIcon
|
public class BaseBreakersIcon : BaseIcon
|
||||||
{
|
{
|
||||||
public BaseBreakersIcon(UObject uObject, EIconStyle style) : base(uObject, style)
|
public BaseBreakersIcon(UObject uObject, EIconStyle style) : base(uObject, style)
|
||||||
|
|
@ -17,18 +17,18 @@ public class BaseBreakersIcon : BaseIcon
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
{
|
{
|
||||||
if (Object.TryGetValue(out FSoftObjectPath iconTextureAssetData, "IconTextureAssetData", "UnlockPortraitGuideImage"))
|
if (Object.TryGetValue(out FSoftObjectPath iconTextureAssetData, "IconTextureAssetData"))
|
||||||
Preview = Utils.GetBitmap(iconTextureAssetData);
|
Preview = Utils.GetBitmap(iconTextureAssetData);
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "RegionDisplayName", "ZoneName"))
|
if (Object.TryGetValue(out FText displayName, "DisplayName"))
|
||||||
DisplayName = displayName.Text;
|
DisplayName = displayName.Text;
|
||||||
if (Object.TryGetValue(out FText description, "Description", "RegionShortName", "ZoneDescription"))
|
if (Object.TryGetValue(out FText description, "Description"))
|
||||||
Description = description.Text;
|
Description = description.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawBackground(c);
|
DrawBackground(c);
|
||||||
|
|
@ -37,6 +37,7 @@ public class BaseBreakersIcon : BaseIcon
|
||||||
DrawDisplayName(c);
|
DrawDisplayName(c);
|
||||||
DrawDescription(c);
|
DrawDescription(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
using CUE4Parse.UE4.Assets.Objects;
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
|
|
@ -8,8 +8,8 @@ using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseBundle : UCreator
|
public class BaseBundle : UCreator
|
||||||
{
|
{
|
||||||
private IList<BaseQuest> _quests;
|
private IList<BaseQuest> _quests;
|
||||||
|
|
@ -26,7 +26,7 @@ public class BaseBundle : UCreator
|
||||||
{
|
{
|
||||||
_quests = new List<BaseQuest>();
|
_quests = new List<BaseQuest>();
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName"))
|
if (Object.TryGetValue(out FText displayName, "DisplayName"))
|
||||||
DisplayName = displayName.Text.ToUpperInvariant();
|
DisplayName = displayName.Text.ToUpperInvariant();
|
||||||
|
|
||||||
if (Object.TryGetValue(out FStructFallback[] quests, "QuestInfos")) // prout :)
|
if (Object.TryGetValue(out FStructFallback[] quests, "QuestInfos")) // prout :)
|
||||||
|
|
@ -79,16 +79,16 @@ public class BaseBundle : UCreator
|
||||||
Height += 256 * _quests.Count;
|
Height += 256 * _quests.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawHeader(c);
|
DrawHeader(c);
|
||||||
DrawDisplayName(c);
|
DrawDisplayName(c);
|
||||||
DrawQuests(c);
|
DrawQuests(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly SKPaint _headerPaint = new()
|
private readonly SKPaint _headerPaint = new()
|
||||||
|
|
@ -124,7 +124,8 @@ public class BaseBundle : UCreator
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(_headerPaint.Typeface);
|
var shaper = new CustomSKShaper(_headerPaint.Typeface);
|
||||||
c.DrawShapedText(shaper, DisplayName, Width / 2f, _headerHeight / 2f + _headerPaint.TextSize / 2 - 10, _headerPaint);
|
var shapedText = shaper.Shape(DisplayName, _headerPaint);
|
||||||
|
c.DrawShapedText(shaper, DisplayName, (Width - shapedText.Points[^1].X) / 2, _headerHeight / 2 + _headerPaint.TextSize / 2 - 10, _headerPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawQuests(SKCanvas c)
|
private void DrawQuests(SKCanvas c)
|
||||||
|
|
@ -137,3 +138,4 @@ public class BaseBundle : UCreator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
using System.Linq;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.GameTypes.FN.Enums;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
|
||||||
using CUE4Parse.UE4.Objects.GameplayTags;
|
using CUE4Parse.UE4.Objects.GameplayTags;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using CUE4Parse.UE4.Versions;
|
using CUE4Parse.UE4.Versions;
|
||||||
|
using CUE4Parse_Fortnite.Enums;
|
||||||
using FModel.Extensions;
|
using FModel.Extensions;
|
||||||
using FModel.Framework;
|
using FModel.Framework;
|
||||||
using FModel.Services;
|
using FModel.Services;
|
||||||
|
|
@ -13,8 +11,8 @@ using FModel.ViewModels.ApiEndpoints.Models;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseCommunity : BaseIcon
|
public class BaseCommunity : BaseIcon
|
||||||
{
|
{
|
||||||
private readonly CommunityDesign _design;
|
private readonly CommunityDesign _design;
|
||||||
|
|
@ -32,29 +30,12 @@ public class BaseCommunity : BaseIcon
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
{
|
{
|
||||||
ParseForReward(UserSettings.Default.CosmeticDisplayAsset);
|
ParseForReward(UserSettings.Default.CosmeticDisplayAsset == EEnabledDisabled.Enabled);
|
||||||
|
|
||||||
if (Object.TryGetValue(out FPackageIndex series, "Series"))
|
if (Object.TryGetValue(out FPackageIndex series, "Series") && Utils.TryGetPackageIndexExport(series, out UObject export))
|
||||||
{
|
_rarityName = export.Name;
|
||||||
_rarityName = series.Name;
|
|
||||||
}
|
|
||||||
else if (Object.TryGetValue(out FInstancedStruct[] dataList, "DataList") &&
|
|
||||||
dataList.FirstOrDefault(d => d.NonConstStruct?.TryGetValue(out FPackageIndex _, "Series") == true) is { } dl)
|
|
||||||
{
|
|
||||||
_rarityName = dl.NonConstStruct?.Get<FPackageIndex>("Series").Name;
|
|
||||||
}
|
|
||||||
else if (Object.TryGetValue(out FStructFallback componentContainer, "ComponentContainer") &&
|
|
||||||
componentContainer.TryGetValue(out FPackageIndex[] components, "Components") &&
|
|
||||||
components.FirstOrDefault(c => c.Name.Contains("Series")) is { } seriesDef &&
|
|
||||||
seriesDef.TryLoad(out var seriesDefObj) && seriesDefObj is not null &&
|
|
||||||
seriesDefObj.TryGetValue(out series, "Series"))
|
|
||||||
{
|
|
||||||
_rarityName = series.Name;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
_rarityName = GetRarityName(Object.GetOrDefault<FName>("Rarity"));
|
||||||
_rarityName = Object.GetOrDefault("Rarity", EFortRarity.Uncommon).GetDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags"))
|
if (Object.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags"))
|
||||||
CheckGameplayTags(gameplayTags);
|
CheckGameplayTags(gameplayTags);
|
||||||
|
|
@ -65,9 +46,9 @@ public class BaseCommunity : BaseIcon
|
||||||
Description = Description.ToUpper();
|
Description = Description.ToUpper();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
if (_design == null)
|
if (_design == null)
|
||||||
|
|
@ -88,7 +69,7 @@ public class BaseCommunity : BaseIcon
|
||||||
DrawUserFacingFlags(c, _design.GameplayTags.DrawCustomOnly);
|
DrawUserFacingFlags(c, _design.GameplayTags.DrawCustomOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckGameplayTags(FGameplayTagContainer gameplayTags)
|
private void CheckGameplayTags(FGameplayTagContainer gameplayTags)
|
||||||
|
|
@ -107,8 +88,8 @@ public class BaseCommunity : BaseIcon
|
||||||
if (_design.DrawSeason && gameplayTags.TryGetGameplayTag("Cosmetics.Filter.Season.", out var season))
|
if (_design.DrawSeason && gameplayTags.TryGetGameplayTag("Cosmetics.Filter.Season.", out var season))
|
||||||
_season = GetCosmeticSeason(season.Text, _design.DrawSeasonShort);
|
_season = GetCosmeticSeason(season.Text, _design.DrawSeasonShort);
|
||||||
|
|
||||||
var triggers = _design.GameplayTags.DrawCustomOnly ? new[] { "Cosmetics.UserFacingFlags." } : new[] { "Cosmetics.UserFacingFlags.", "Homebase.Class.", "NPC.CharacterType.Survivor.Defender." };
|
GetUserFacingFlags(gameplayTags.GetAllGameplayTags(
|
||||||
GetUserFacingFlags(gameplayTags.GetAllGameplayTags(triggers));
|
"Cosmetics.UserFacingFlags.", "Homebase.Class.", "NPC.CharacterType.Survivor.Defender."));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCosmeticSet(string setName, bool bShort)
|
private string GetCosmeticSet(string setName, bool bShort)
|
||||||
|
|
@ -120,8 +101,49 @@ public class BaseCommunity : BaseIcon
|
||||||
{
|
{
|
||||||
if (!bShort) return base.GetCosmeticSeason(seasonNumber);
|
if (!bShort) return base.GetCosmeticSeason(seasonNumber);
|
||||||
var s = seasonNumber["Cosmetics.Filter.Season.".Length..];
|
var s = seasonNumber["Cosmetics.Filter.Season.".Length..];
|
||||||
(int chapterIdx, int seasonIdx) = GetInternalSID(int.Parse(s));
|
var number = int.Parse(s);
|
||||||
return $"C{chapterIdx} S{seasonIdx}";
|
if (number == 10)
|
||||||
|
s = "X";
|
||||||
|
|
||||||
|
return number > 10 ? $"C{number / 10 + 1} S{s[^1..]}" : $"C1 S{s}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRarityName(FName r)
|
||||||
|
{
|
||||||
|
var rarity = EFortRarity.Uncommon;
|
||||||
|
switch (r.Text)
|
||||||
|
{
|
||||||
|
case "EFortRarity::Common":
|
||||||
|
case "EFortRarity::Handmade":
|
||||||
|
rarity = EFortRarity.Common;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Rare":
|
||||||
|
case "EFortRarity::Sturdy":
|
||||||
|
rarity = EFortRarity.Rare;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Epic":
|
||||||
|
case "EFortRarity::Quality":
|
||||||
|
rarity = EFortRarity.Epic;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Legendary":
|
||||||
|
case "EFortRarity::Fine":
|
||||||
|
rarity = EFortRarity.Legendary;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Mythic":
|
||||||
|
case "EFortRarity::Elegant":
|
||||||
|
rarity = EFortRarity.Mythic;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Transcendent":
|
||||||
|
case "EFortRarity::Masterwork":
|
||||||
|
rarity = EFortRarity.Transcendent;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Unattainable":
|
||||||
|
case "EFortRarity::Badass":
|
||||||
|
rarity = EFortRarity.Unattainable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rarity.GetDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
private new void DrawBackground(SKCanvas c)
|
private new void DrawBackground(SKCanvas c)
|
||||||
|
|
@ -174,9 +196,10 @@ public class BaseCommunity : BaseIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
||||||
|
var shapedText = shaper.Shape(DisplayName, DisplayNamePaint);
|
||||||
var x = font.Alignment switch
|
var x = font.Alignment switch
|
||||||
{
|
{
|
||||||
SKTextAlign.Center => Width / 2f,
|
SKTextAlign.Center => (Width - shapedText.Points[^1].X) / 2f,
|
||||||
_ => font.X
|
_ => font.X
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -210,9 +233,10 @@ public class BaseCommunity : BaseIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(DescriptionPaint.Typeface);
|
var shaper = new CustomSKShaper(DescriptionPaint.Typeface);
|
||||||
|
var shapedText = shaper.Shape(Description, DescriptionPaint);
|
||||||
var x = font.Alignment switch
|
var x = font.Alignment switch
|
||||||
{
|
{
|
||||||
SKTextAlign.Center => Width / 2f,
|
SKTextAlign.Center => (Width - shapedText.Points[^1].X) / 2f,
|
||||||
_ => font.X
|
_ => font.X
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -253,9 +277,11 @@ public class BaseCommunity : BaseIcon
|
||||||
DisplayNamePaint.Typeface = Utils.Typefaces.OnTheFly(path);
|
DisplayNamePaint.Typeface = Utils.Typefaces.OnTheFly(path);
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
||||||
|
var shapedText = shaper.Shape(text, DisplayNamePaint);
|
||||||
var x = font.Alignment switch
|
var x = font.Alignment switch
|
||||||
{
|
{
|
||||||
SKTextAlign.Center => Width / 2f,
|
SKTextAlign.Center => (Width - shapedText.Points[^1].X) / 2f,
|
||||||
|
SKTextAlign.Right => font.X - DisplayNamePaint.MeasureText(text),
|
||||||
_ => font.X
|
_ => font.X
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -264,7 +290,7 @@ public class BaseCommunity : BaseIcon
|
||||||
|
|
||||||
private void DrawUserFacingFlags(SKCanvas c, bool customOnly)
|
private void DrawUserFacingFlags(SKCanvas c, bool customOnly)
|
||||||
{
|
{
|
||||||
if (UserFacingFlags == null || UserFacingFlags.Count < 1) return;
|
if (UserFacingFlags == null || UserFacingFlags.Length < 1) return;
|
||||||
if (customOnly)
|
if (customOnly)
|
||||||
{
|
{
|
||||||
c.DrawBitmap(_design.GameplayTags.Custom, 0, 0, ImagePaint);
|
c.DrawBitmap(_design.GameplayTags.Custom, 0, 0, ImagePaint);
|
||||||
|
|
@ -276,3 +302,4 @@ public class BaseCommunity : BaseIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using CUE4Parse.GameTypes.FN.Enums;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Engine;
|
using CUE4Parse.UE4.Assets.Exports.Engine;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||||
|
|
@ -13,80 +12,59 @@ using CUE4Parse.UE4.Objects.Core.Math;
|
||||||
using CUE4Parse.UE4.Objects.GameplayTags;
|
using CUE4Parse.UE4.Objects.GameplayTags;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using CUE4Parse_Conversion.Textures;
|
using CUE4Parse_Conversion.Textures;
|
||||||
|
using CUE4Parse_Fortnite.Enums;
|
||||||
using FModel.Settings;
|
using FModel.Settings;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseIcon : UCreator
|
public class BaseIcon : UCreator
|
||||||
{
|
{
|
||||||
public SKBitmap SeriesBackground { get; protected set; }
|
public SKBitmap SeriesBackground { get; protected set; }
|
||||||
protected string ShortDescription { get; set; }
|
protected string ShortDescription { get; set; }
|
||||||
protected string CosmeticSource { get; set; }
|
protected string CosmeticSource { get; set; }
|
||||||
protected Dictionary<string, SKBitmap> UserFacingFlags { get; set; }
|
protected SKBitmap[] UserFacingFlags { get; set; }
|
||||||
|
|
||||||
public BaseIcon(UObject uObject, EIconStyle style) : base(uObject, style) { }
|
public BaseIcon(UObject uObject, EIconStyle style) : base(uObject, style)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public void ParseForReward(bool isUsingDisplayAsset)
|
public void ParseForReward(bool isUsingDisplayAsset)
|
||||||
{
|
{
|
||||||
// rarity
|
// rarity
|
||||||
if (Object.TryGetValue(out FPackageIndex series, "Series")) GetSeries(series);
|
if (Object.TryGetValue(out FPackageIndex series, "Series")) GetSeries(series);
|
||||||
else if (Object.TryGetValue(out FStructFallback componentContainer, "ComponentContainer")) GetSeries(componentContainer);
|
else GetRarity(Object.GetOrDefault<FName>("Rarity")); // default is uncommon
|
||||||
else GetRarity(Object.GetOrDefault("Rarity", EFortRarity.Uncommon)); // default is uncommon
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FInstancedStruct[] dataList, "DataList"))
|
|
||||||
{
|
|
||||||
GetSeries(dataList);
|
|
||||||
Preview = Utils.GetBitmap(dataList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// preview
|
// preview
|
||||||
if (Preview is null)
|
|
||||||
{
|
|
||||||
if (isUsingDisplayAsset && Utils.TryGetDisplayAsset(Object, out var preview))
|
if (isUsingDisplayAsset && Utils.TryGetDisplayAsset(Object, out var preview))
|
||||||
Preview = preview;
|
Preview = preview;
|
||||||
else if (Object.TryGetValue(out FPackageIndex itemDefinition, "HeroDefinition", "WeaponDefinition"))
|
else if (Object.TryGetValue(out FPackageIndex itemDefinition, "HeroDefinition", "WeaponDefinition"))
|
||||||
Preview = Utils.GetBitmap(itemDefinition);
|
Preview = Utils.GetBitmap(itemDefinition);
|
||||||
else if (Object.TryGetValue(out FSoftObjectPath largePreview, "LargePreviewImage", "EntryListIcon", "SmallPreviewImage", "BundleImage", "ItemDisplayAsset", "LargeIcon", "ToastIcon", "SmallIcon"))
|
else if (Object.TryGetValue(out FSoftObjectPath largePreview, "LargePreviewImage", "SidePanelIcon", "EntryListIcon", "SmallPreviewImage", "ItemDisplayAsset", "LargeIcon", "ToastIcon", "SmallIcon"))
|
||||||
Preview = Utils.GetBitmap(largePreview);
|
Preview = Utils.GetBitmap(largePreview);
|
||||||
else if (Object.TryGetValue(out string s, "LargePreviewImage") && !string.IsNullOrEmpty(s))
|
else if (Object.TryGetValue(out string s, "LargePreviewImage") && !string.IsNullOrEmpty(s))
|
||||||
Preview = Utils.GetBitmap(s);
|
Preview = Utils.GetBitmap(s);
|
||||||
else if (Object.TryGetValue(out FPackageIndex otherPreview, "SmallPreviewImage", "ToastIcon", "access_item"))
|
else if (Object.TryGetValue(out FPackageIndex otherPreview, "SmallPreviewImage", "ToastIcon", "access_item"))
|
||||||
Preview = Utils.GetBitmap(otherPreview);
|
Preview = Utils.GetBitmap(otherPreview);
|
||||||
else if (Object.TryGetValue(out UMaterialInstanceConstant materialInstancePreview, "EventCalloutImage"))
|
|
||||||
Preview = Utils.GetBitmap(materialInstancePreview);
|
|
||||||
else if (Object.TryGetValue(out FStructFallback brush, "IconBrush") && brush.TryGetValue(out UTexture2D res, "ResourceObject"))
|
|
||||||
Preview = Utils.GetBitmap(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// text
|
// text
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName", "BundleName", "DefaultHeaderText", "UIDisplayName", "EntryName", "EventCalloutTitle"))
|
if (Object.TryGetValue(out FText displayName, "DisplayName", "DefaultHeaderText", "UIDisplayName", "EntryName"))
|
||||||
DisplayName = displayName.Text;
|
DisplayName = displayName.Text;
|
||||||
if (Object.TryGetValue(out FText description, "Description", "ItemDescription", "BundleDescription", "GeneralDescription", "DefaultBodyText", "UIDescription", "UIDisplayDescription", "EntryDescription", "EventCalloutDescription"))
|
if (Object.TryGetValue(out FText description, "Description", "GeneralDescription", "DefaultBodyText", "UIDescription", "UIDisplayDescription", "EntryDescription"))
|
||||||
Description = description.Text;
|
Description = description.Text;
|
||||||
else if (Object.TryGetValue(out FText[] descriptions, "Description"))
|
else if (Object.TryGetValue(out FText[] descriptions, "Description"))
|
||||||
Description = string.Join('\n', descriptions.Select(x => x.Text));
|
Description = string.Join('\n', descriptions.Select(x => x.Text));
|
||||||
if (Object.TryGetValue(out FText shortDescription, "ShortDescription", "UIDisplaySubName"))
|
if (Object.TryGetValue(out FText shortDescription, "ShortDescription", "UIDisplaySubName"))
|
||||||
ShortDescription = shortDescription.Text;
|
ShortDescription = shortDescription.Text;
|
||||||
else if (Object.ExportType.Equals("AthenaItemWrapDefinition", StringComparison.OrdinalIgnoreCase))
|
else if (Object.ExportType.Equals("AthenaItemWrapDefinition", StringComparison.OrdinalIgnoreCase))
|
||||||
ShortDescription = Utils.GetLocalizedResource("Fort.Cosmetics", "ItemWrapShortDescription", "Wrap");
|
ShortDescription = "Wrap";
|
||||||
|
|
||||||
// Only works on non-cataba designs
|
|
||||||
if (Object.TryGetValue(out FStructFallback eventArrowColor, "EventArrowColor") &&
|
|
||||||
eventArrowColor.TryGetValue(out FLinearColor specifiedArrowColor, "SpecifiedColor") &&
|
|
||||||
Object.TryGetValue(out FStructFallback eventArrowShadowColor, "EventArrowShadowColor") &&
|
|
||||||
eventArrowShadowColor.TryGetValue(out FLinearColor specifiedShadowColor, "SpecifiedColor"))
|
|
||||||
{
|
|
||||||
Background = new[] { SKColor.Parse(specifiedArrowColor.Hex), SKColor.Parse(specifiedShadowColor.Hex) };
|
|
||||||
Border = new[] { SKColor.Parse(specifiedShadowColor.Hex), SKColor.Parse(specifiedArrowColor.Hex) };
|
|
||||||
}
|
|
||||||
|
|
||||||
Description = Utils.RemoveHtmlTags(Description);
|
Description = Utils.RemoveHtmlTags(Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
{
|
{
|
||||||
ParseForReward(UserSettings.Default.CosmeticDisplayAsset);
|
ParseForReward(UserSettings.Default.CosmeticDisplayAsset == EEnabledDisabled.Enabled);
|
||||||
|
|
||||||
if (Object.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags"))
|
if (Object.TryGetValue(out FGameplayTagContainer gameplayTags, "GameplayTags"))
|
||||||
CheckGameplayTags(gameplayTags);
|
CheckGameplayTags(gameplayTags);
|
||||||
|
|
@ -120,14 +98,14 @@ public class BaseIcon : UCreator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
Draw(c);
|
Draw(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetSeries(FPackageIndex s)
|
private void GetSeries(FPackageIndex s)
|
||||||
|
|
@ -137,27 +115,11 @@ public class BaseIcon : UCreator
|
||||||
GetSeries(export);
|
GetSeries(export);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetSeries(FInstancedStruct[] s)
|
|
||||||
{
|
|
||||||
if (s.FirstOrDefault(d => d.NonConstStruct?.TryGetValue(out FPackageIndex _, "Series") == true) is { } dl)
|
|
||||||
GetSeries(dl.NonConstStruct?.Get<FPackageIndex>("Series"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetSeries(FStructFallback s)
|
|
||||||
{
|
|
||||||
if (!s.TryGetValue(out FPackageIndex[] components, "Components")) return;
|
|
||||||
if (components.FirstOrDefault(c => c.Name.Contains("Series")) is not { } seriesDef ||
|
|
||||||
!seriesDef.TryLoad(out var seriesDefObj) || seriesDefObj is null ||
|
|
||||||
!seriesDefObj.TryGetValue(out UObject series, "Series")) return;
|
|
||||||
|
|
||||||
GetSeries(series);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void GetSeries(UObject uObject)
|
protected void GetSeries(UObject uObject)
|
||||||
{
|
{
|
||||||
if (uObject is UTexture2D texture2D)
|
if (uObject is UTexture2D texture2D)
|
||||||
{
|
{
|
||||||
SeriesBackground = texture2D.Decode();
|
SeriesBackground = SKBitmap.Decode(texture2D.Decode()?.Encode());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,11 +151,44 @@ public class BaseIcon : UCreator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetRarity(EFortRarity r)
|
private void GetRarity(FName r)
|
||||||
{
|
{
|
||||||
if (!Utils.TryLoadObject("FortniteGame/Content/Balance/RarityData.RarityData", out UObject export)) return;
|
if (!Utils.TryLoadObject("FortniteGame/Content/Balance/RarityData.RarityData", out UObject export)) return;
|
||||||
|
|
||||||
if (export.GetByIndex<FStructFallback>((int) r) is { } data &&
|
var rarity = EFortRarity.Uncommon;
|
||||||
|
switch (r.Text)
|
||||||
|
{
|
||||||
|
case "EFortRarity::Common":
|
||||||
|
case "EFortRarity::Handmade":
|
||||||
|
rarity = EFortRarity.Common;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Rare":
|
||||||
|
case "EFortRarity::Sturdy":
|
||||||
|
rarity = EFortRarity.Rare;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Epic":
|
||||||
|
case "EFortRarity::Quality":
|
||||||
|
rarity = EFortRarity.Epic;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Legendary":
|
||||||
|
case "EFortRarity::Fine":
|
||||||
|
rarity = EFortRarity.Legendary;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Mythic":
|
||||||
|
case "EFortRarity::Elegant":
|
||||||
|
rarity = EFortRarity.Mythic;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Transcendent":
|
||||||
|
case "EFortRarity::Masterwork":
|
||||||
|
rarity = EFortRarity.Transcendent;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Unattainable":
|
||||||
|
case "EFortRarity::Badass":
|
||||||
|
rarity = EFortRarity.Unattainable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (export.GetByIndex<FStructFallback>((int) rarity) is { } data &&
|
||||||
data.TryGetValue(out FLinearColor color1, "Color1") &&
|
data.TryGetValue(out FLinearColor color1, "Color1") &&
|
||||||
data.TryGetValue(out FLinearColor color2, "Color2") &&
|
data.TryGetValue(out FLinearColor color2, "Color2") &&
|
||||||
data.TryGetValue(out FLinearColor color3, "Color3"))
|
data.TryGetValue(out FLinearColor color3, "Color3"))
|
||||||
|
|
@ -219,46 +214,20 @@ public class BaseIcon : UCreator
|
||||||
return string.Format(format, name);
|
return string.Format(format, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected (int, int) GetInternalSID(int number)
|
|
||||||
{
|
|
||||||
static int GetSeasonsInChapter(int chapter) => chapter switch
|
|
||||||
{
|
|
||||||
1 => 10,
|
|
||||||
2 => 8,
|
|
||||||
3 => 4,
|
|
||||||
4 => 5,
|
|
||||||
_ => 10
|
|
||||||
};
|
|
||||||
|
|
||||||
var chapterIdx = 0;
|
|
||||||
var seasonIdx = 0;
|
|
||||||
while (number > 0)
|
|
||||||
{
|
|
||||||
var seasonsInChapter = GetSeasonsInChapter(++chapterIdx);
|
|
||||||
if (number > seasonsInChapter)
|
|
||||||
number -= seasonsInChapter;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
seasonIdx = number;
|
|
||||||
number = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (chapterIdx, seasonIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string GetCosmeticSeason(string seasonNumber)
|
protected string GetCosmeticSeason(string seasonNumber)
|
||||||
{
|
{
|
||||||
var s = seasonNumber["Cosmetics.Filter.Season.".Length..];
|
var s = seasonNumber["Cosmetics.Filter.Season.".Length..];
|
||||||
var initial = int.Parse(s);
|
var number = int.Parse(s);
|
||||||
(int chapterIdx, int seasonIdx) = GetInternalSID(initial);
|
if (number == 10)
|
||||||
|
s = "X";
|
||||||
|
|
||||||
var season = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "SeasonTextFormat", "Season {0}");
|
var season = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "SeasonTextFormat", "Season {0}");
|
||||||
var introduced = Utils.GetLocalizedResource("Fort.Cosmetics", "CosmeticItemDescription_Season", "\nIntroduced in <SeasonText>{0}</>.");
|
var introduced = Utils.GetLocalizedResource("Fort.Cosmetics", "CosmeticItemDescription_Season", "\nIntroduced in <SeasonText>{0}</>.");
|
||||||
if (initial <= 10) return Utils.RemoveHtmlTags(string.Format(introduced, string.Format(season, s)));
|
if (number <= 10) return Utils.RemoveHtmlTags(string.Format(introduced, string.Format(season, s)));
|
||||||
|
|
||||||
var chapter = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "ChapterTextFormat", "Chapter {0}");
|
var chapter = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "ChapterTextFormat", "Chapter {0}");
|
||||||
var chapterFormat = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "ChapterSeasonTextFormat", "{0}, {1}");
|
var chapterFormat = Utils.GetLocalizedResource("AthenaSeasonItemDefinitionInternal", "ChapterSeasonTextFormat", "{0}, {1}");
|
||||||
var d = string.Format(chapterFormat, string.Format(chapter, chapterIdx), string.Format(season, seasonIdx));
|
var d = string.Format(chapterFormat, string.Format(chapter, number / 10 + 1), string.Format(season, s[^1..]));
|
||||||
return Utils.RemoveHtmlTags(string.Format(introduced, d));
|
return Utils.RemoveHtmlTags(string.Format(introduced, d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,24 +255,24 @@ public class BaseIcon : UCreator
|
||||||
if (!itemCategories.TryGetValue(out FStructFallback[] tertiaryCategories, "TertiaryCategories"))
|
if (!itemCategories.TryGetValue(out FStructFallback[] tertiaryCategories, "TertiaryCategories"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UserFacingFlags = new Dictionary<string, SKBitmap>(userFacingFlags.Count);
|
UserFacingFlags = new SKBitmap[userFacingFlags.Count];
|
||||||
foreach (var flag in userFacingFlags)
|
for (var i = 0; i < UserFacingFlags.Length; i++)
|
||||||
{
|
{
|
||||||
if (flag.Equals("Cosmetics.UserFacingFlags.HasUpgradeQuests", StringComparison.OrdinalIgnoreCase))
|
if (userFacingFlags[i].Equals("Cosmetics.UserFacingFlags.HasUpgradeQuests", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (Object.ExportType.Equals("AthenaPetCarrierItemDefinition", StringComparison.OrdinalIgnoreCase))
|
if (Object.ExportType.Equals("AthenaPetCarrierItemDefinition", StringComparison.OrdinalIgnoreCase))
|
||||||
UserFacingFlags[flag] = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T-Icon-Pets-64.png"))?.Stream);
|
UserFacingFlags[i] = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T-Icon-Pets-64.png"))?.Stream);
|
||||||
else UserFacingFlags[flag] = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T-Icon-Quests-64.png"))?.Stream);
|
else UserFacingFlags[i] = SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/T-Icon-Quests-64.png"))?.Stream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var category in tertiaryCategories)
|
foreach (var category in tertiaryCategories)
|
||||||
{
|
{
|
||||||
if (category.TryGetValue(out FGameplayTagContainer tagContainer, "TagContainer") && tagContainer.TryGetGameplayTag(flag, out _) &&
|
if (category.TryGetValue(out FGameplayTagContainer tagContainer, "TagContainer") && tagContainer.TryGetGameplayTag(userFacingFlags[i], out _) &&
|
||||||
category.TryGetValue(out FStructFallback categoryBrush, "CategoryBrush") && categoryBrush.TryGetValue(out FStructFallback brushXxs, "Brush_XXS") &&
|
category.TryGetValue(out FStructFallback categoryBrush, "CategoryBrush") && categoryBrush.TryGetValue(out FStructFallback brushXxs, "Brush_XXS") &&
|
||||||
brushXxs.TryGetValue(out FPackageIndex resourceObject, "ResourceObject") && Utils.TryGetPackageIndexExport(resourceObject, out UTexture2D texture))
|
brushXxs.TryGetValue(out FPackageIndex resourceObject, "ResourceObject") && Utils.TryGetPackageIndexExport(resourceObject, out UTexture2D texture))
|
||||||
{
|
{
|
||||||
UserFacingFlags[flag] = Utils.GetBitmap(texture);
|
UserFacingFlags[i] = Utils.GetBitmap(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -316,10 +285,13 @@ public class BaseIcon : UCreator
|
||||||
|
|
||||||
const int size = 25;
|
const int size = 25;
|
||||||
var x = Margin * (int) 2.5;
|
var x = Margin * (int) 2.5;
|
||||||
foreach (var flag in UserFacingFlags.Values.Where(flag => flag != null))
|
foreach (var flag in UserFacingFlags)
|
||||||
{
|
{
|
||||||
|
if (flag == null) continue;
|
||||||
|
|
||||||
c.DrawBitmap(flag.Resize(size), new SKPoint(x, Margin * (int) 2.5), ImagePaint);
|
c.DrawBitmap(flag.Resize(size), new SKPoint(x, Margin * (int) 2.5), ImagePaint);
|
||||||
x += size;
|
x += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using CUE4Parse.GameTypes.FN.Enums;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Engine;
|
using CUE4Parse.UE4.Assets.Exports.Engine;
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
using CUE4Parse.UE4.Assets.Objects;
|
||||||
|
|
@ -8,13 +7,14 @@ using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
using CUE4Parse.UE4.Objects.Engine.Curves;
|
using CUE4Parse.UE4.Objects.Engine.Curves;
|
||||||
using CUE4Parse.UE4.Objects.GameplayTags;
|
using CUE4Parse.UE4.Objects.GameplayTags;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
|
using CUE4Parse_Fortnite.Enums;
|
||||||
using FModel.Extensions;
|
using FModel.Extensions;
|
||||||
using FModel.Framework;
|
using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseIconStats : BaseIcon
|
public class BaseIconStats : BaseIcon
|
||||||
{
|
{
|
||||||
private readonly IList<IconStat> _statistics;
|
private readonly IList<IconStat> _statistics;
|
||||||
|
|
@ -52,7 +52,7 @@ public class BaseIconStats : BaseIcon
|
||||||
foreach (var poi in challengeMapPoiData)
|
foreach (var poi in challengeMapPoiData)
|
||||||
{
|
{
|
||||||
if (!poi.TryGetValue(out FStructFallback locationTag, "LocationTag") || !locationTag.TryGetValue(out FName tagName, "TagName") ||
|
if (!poi.TryGetValue(out FStructFallback locationTag, "LocationTag") || !locationTag.TryGetValue(out FName tagName, "TagName") ||
|
||||||
tagName != location.TagName || !poi.TryGetValue(out FText text, "Text")) continue;
|
!tagName.Text.Equals(location.Text, StringComparison.OrdinalIgnoreCase) || !poi.TryGetValue(out FText text, "Text")) continue;
|
||||||
|
|
||||||
locationName = text.Text;
|
locationName = text.Text;
|
||||||
break;
|
break;
|
||||||
|
|
@ -64,13 +64,13 @@ public class BaseIconStats : BaseIcon
|
||||||
|
|
||||||
if (Object.TryGetValue(out FStructFallback maxStackSize, "MaxStackSize"))
|
if (Object.TryGetValue(out FStructFallback maxStackSize, "MaxStackSize"))
|
||||||
{
|
{
|
||||||
if (maxStackSize.TryGetValue(out float v, "Value") && v > 0)
|
if (maxStackSize.TryGetValue(out float v, "Value") && v > -1)
|
||||||
{
|
{
|
||||||
_statistics.Add(new IconStat("Max Stack", v, 15));
|
_statistics.Add(new IconStat("Max Stack", v));
|
||||||
}
|
}
|
||||||
else if (TryGetCurveTableStat(maxStackSize, out var s))
|
else if (TryGetCurveTableStat(maxStackSize, out var s))
|
||||||
{
|
{
|
||||||
_statistics.Add(new IconStat("Max Stack", s, 15));
|
_statistics.Add(new IconStat("Max Stack", s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,22 +84,9 @@ public class BaseIconStats : BaseIcon
|
||||||
weaponStatHandle.TryGetValue(out UDataTable dataTable, "DataTable") &&
|
weaponStatHandle.TryGetValue(out UDataTable dataTable, "DataTable") &&
|
||||||
dataTable.TryGetDataTableRow(weaponRowName.Text, StringComparison.OrdinalIgnoreCase, out var weaponRowValue))
|
dataTable.TryGetDataTableRow(weaponRowName.Text, StringComparison.OrdinalIgnoreCase, out var weaponRowValue))
|
||||||
{
|
{
|
||||||
if (weaponRowValue.TryGetValue(out int bpc, "BulletsPerCartridge"))
|
|
||||||
{
|
|
||||||
var multiplier = bpc != 0f ? bpc : 1;
|
|
||||||
if (weaponRowValue.TryGetValue(out float dmgPb, "DmgPB") && dmgPb != 0f)
|
if (weaponRowValue.TryGetValue(out float dmgPb, "DmgPB") && dmgPb != 0f)
|
||||||
{
|
{
|
||||||
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "35D04D1B45737BEA25B69686D9E085B9", "Damage"), dmgPb * multiplier, 200));
|
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "BF7E3CF34A9ACFF52E95EAAD4F09F133", "Damage to Player"), dmgPb, 200));
|
||||||
}
|
|
||||||
|
|
||||||
if (weaponRowValue.TryGetValue(out float mdpc, "MaxDamagePerCartridge") && mdpc >= 0f)
|
|
||||||
{
|
|
||||||
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "0DEF2455463B008C4499FEA03D149EDF", "Headshot Damage"), mdpc, 200));
|
|
||||||
}
|
|
||||||
else if (weaponRowValue.TryGetValue(out float dmgCritical, "DamageZone_Critical"))
|
|
||||||
{
|
|
||||||
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "0DEF2455463B008C4499FEA03D149EDF", "Headshot Damage"), dmgPb * dmgCritical * multiplier, 200));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weaponRowValue.TryGetValue(out int clipSize, "ClipSize") && clipSize != 0)
|
if (weaponRowValue.TryGetValue(out int clipSize, "ClipSize") && clipSize != 0)
|
||||||
|
|
@ -127,7 +114,7 @@ public class BaseIconStats : BaseIcon
|
||||||
weaponRowValue.TryGetValue(out UDataTable durabilityTable, "Durability") &&
|
weaponRowValue.TryGetValue(out UDataTable durabilityTable, "Durability") &&
|
||||||
weaponRowValue.TryGetValue(out FName durabilityRowName, "DurabilityRowName") &&
|
weaponRowValue.TryGetValue(out FName durabilityRowName, "DurabilityRowName") &&
|
||||||
durabilityTable.TryGetDataTableRow(durabilityRowName.Text, StringComparison.OrdinalIgnoreCase, out var durability) &&
|
durabilityTable.TryGetDataTableRow(durabilityRowName.Text, StringComparison.OrdinalIgnoreCase, out var durability) &&
|
||||||
durability.TryGetValue(out int duraByRarity, Object.GetOrDefault("Rarity", EFortRarity.Uncommon).GetDescription()))
|
durability.TryGetValue(out int duraByRarity, GetRarityName(Object.GetOrDefault<FName>("Rarity"))))
|
||||||
{
|
{
|
||||||
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "6FA2882140CB69DE32FD73A392F0585B", "Durability"), duraByRarity, 20));
|
_statistics.Add(new IconStat(Utils.GetLocalizedResource("", "6FA2882140CB69DE32FD73A392F0585B", "Durability"), duraByRarity, 20));
|
||||||
}
|
}
|
||||||
|
|
@ -138,16 +125,16 @@ public class BaseIconStats : BaseIcon
|
||||||
Height += 50 * _statistics.Count;
|
Height += 50 * _statistics.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawHeader(c);
|
DrawHeader(c);
|
||||||
DrawDisplayName(c);
|
DrawDisplayName(c);
|
||||||
DrawStatistics(c);
|
DrawStatistics(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGetCurveTableStat(FStructFallback property, out float statValue)
|
private bool TryGetCurveTableStat(FStructFallback property, out float statValue)
|
||||||
|
|
@ -155,10 +142,10 @@ public class BaseIconStats : BaseIcon
|
||||||
if (property.TryGetValue(out FStructFallback curve, "Curve") &&
|
if (property.TryGetValue(out FStructFallback curve, "Curve") &&
|
||||||
curve.TryGetValue(out FName rowName, "RowName") &&
|
curve.TryGetValue(out FName rowName, "RowName") &&
|
||||||
curve.TryGetValue(out UCurveTable curveTable, "CurveTable") &&
|
curve.TryGetValue(out UCurveTable curveTable, "CurveTable") &&
|
||||||
curveTable.TryFindCurve(rowName, out var rowValue) &&
|
curveTable.TryGetCurveTableRow(rowName.Text, StringComparison.OrdinalIgnoreCase, out var rowValue) &&
|
||||||
rowValue is FSimpleCurve s && s.Keys.Length > 0)
|
rowValue.TryGetValue(out FSimpleCurveKey[] keys, "Keys") && keys.Length > 0)
|
||||||
{
|
{
|
||||||
statValue = s.Keys[0].Value;
|
statValue = keys[0].KeyValue;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,6 +153,44 @@ public class BaseIconStats : BaseIcon
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetRarityName(FName r)
|
||||||
|
{
|
||||||
|
var rarity = EFortRarity.Uncommon;
|
||||||
|
switch (r.Text)
|
||||||
|
{
|
||||||
|
case "EFortRarity::Common":
|
||||||
|
case "EFortRarity::Handmade":
|
||||||
|
rarity = EFortRarity.Common;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Rare":
|
||||||
|
case "EFortRarity::Sturdy":
|
||||||
|
rarity = EFortRarity.Rare;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Epic":
|
||||||
|
case "EFortRarity::Quality":
|
||||||
|
rarity = EFortRarity.Epic;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Legendary":
|
||||||
|
case "EFortRarity::Fine":
|
||||||
|
rarity = EFortRarity.Legendary;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Mythic":
|
||||||
|
case "EFortRarity::Elegant":
|
||||||
|
rarity = EFortRarity.Mythic;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Transcendent":
|
||||||
|
case "EFortRarity::Masterwork":
|
||||||
|
rarity = EFortRarity.Transcendent;
|
||||||
|
break;
|
||||||
|
case "EFortRarity::Unattainable":
|
||||||
|
case "EFortRarity::Badass":
|
||||||
|
rarity = EFortRarity.Unattainable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rarity.GetDescription();
|
||||||
|
}
|
||||||
|
|
||||||
private readonly SKPaint _informationPaint = new()
|
private readonly SKPaint _informationPaint = new()
|
||||||
{
|
{
|
||||||
IsAntialias = true, FilterQuality = SKFilterQuality.High,
|
IsAntialias = true, FilterQuality = SKFilterQuality.High,
|
||||||
|
|
@ -221,7 +246,8 @@ public class BaseIconStats : BaseIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(_informationPaint.Typeface);
|
var shaper = new CustomSKShaper(_informationPaint.Typeface);
|
||||||
c.DrawShapedText(shaper, DisplayName, _headerHeight + _headerHeight / 3 + 10, _headerHeight / 2f + _informationPaint.TextSize / 3, _informationPaint);
|
shaper.Shape(DisplayName, _informationPaint);
|
||||||
|
c.DrawShapedText(shaper, DisplayName, _headerHeight + _headerHeight / 3 + 10, _headerHeight / 2 + _informationPaint.TextSize / 3, _informationPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawStatistics(SKCanvas c)
|
private void DrawStatistics(SKCanvas c)
|
||||||
|
|
@ -267,12 +293,13 @@ public class IconStat
|
||||||
|
|
||||||
public void Draw(SKCanvas c, SKColor sliderColor, int width, int height, ref float y)
|
public void Draw(SKCanvas c, SKColor sliderColor, int width, int height, ref float y)
|
||||||
{
|
{
|
||||||
while (_statPaint.MeasureText(_statName) > height * 2 - 40)
|
while (_statPaint.MeasureText(_statName) > height * 2)
|
||||||
{
|
{
|
||||||
_statPaint.TextSize -= 1;
|
_statPaint.TextSize -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(_statPaint.Typeface);
|
var shaper = new CustomSKShaper(_statPaint.Typeface);
|
||||||
|
shaper.Shape(_statName, _statPaint);
|
||||||
c.DrawShapedText(shaper, _statName, 50, y + 10, _statPaint);
|
c.DrawShapedText(shaper, _statName, 50, y + 10, _statPaint);
|
||||||
|
|
||||||
_statPaint.TextAlign = SKTextAlign.Right;
|
_statPaint.TextAlign = SKTextAlign.Right;
|
||||||
|
|
@ -285,9 +312,8 @@ public class IconStat
|
||||||
c.DrawText(_value.ToString(), new SKPoint(width - 50, y + 10), _statPaint);
|
c.DrawText(_value.ToString(), new SKPoint(width - 50, y + 10), _statPaint);
|
||||||
|
|
||||||
if (_maxValue < 1 || !float.TryParse(_value.ToString(), out var floatValue)) return;
|
if (_maxValue < 1 || !float.TryParse(_value.ToString(), out var floatValue)) return;
|
||||||
if (floatValue < 0)
|
|
||||||
floatValue = 0;
|
|
||||||
var sliderWidth = (sliderRight - height * 2) * (floatValue / _maxValue);
|
var sliderWidth = (sliderRight - height * 2) * (floatValue / _maxValue);
|
||||||
c.DrawRect(new SKRect(height * 2, y, Math.Min(height * 2 + sliderWidth, sliderRight), y + 5), _statPaint);
|
c.DrawRect(new SKRect(height * 2, y, Math.Min(height * 2 + sliderWidth, sliderRight), y + 5), _statPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,8 +5,8 @@ using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseItemAccessToken : UCreator
|
public class BaseItemAccessToken : UCreator
|
||||||
{
|
{
|
||||||
private readonly SKBitmap _locked, _unlocked;
|
private readonly SKBitmap _locked, _unlocked;
|
||||||
|
|
@ -29,18 +29,18 @@ public class BaseItemAccessToken : UCreator
|
||||||
_icon.ParseForReward(false);
|
_icon.ParseForReward(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName") && displayName.Text != "TBD")
|
if (Object.TryGetValue(out FText displayName, "DisplayName") && displayName.Text != "TBD")
|
||||||
DisplayName = displayName.Text;
|
DisplayName = displayName.Text;
|
||||||
else
|
else
|
||||||
DisplayName = _icon?.DisplayName;
|
DisplayName = _icon?.DisplayName;
|
||||||
|
|
||||||
Description = Object.TryGetValue(out FText description, "Description", "ItemDescription") ? description.Text : _icon?.Description;
|
Description = Object.TryGetValue(out FText description, "Description") ? description.Text : _icon?.Description;
|
||||||
if (Object.TryGetValue(out FText unlockDescription, "UnlockDescription")) _unlockedDescription = unlockDescription.Text;
|
if (Object.TryGetValue(out FText unlockDescription, "UnlockDescription")) _unlockedDescription = unlockDescription.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
switch (Style)
|
switch (Style)
|
||||||
|
|
@ -61,7 +61,7 @@ public class BaseItemAccessToken : UCreator
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawInformation(SKCanvas c)
|
private void DrawInformation(SKCanvas c)
|
||||||
|
|
@ -76,7 +76,7 @@ public class BaseItemAccessToken : UCreator
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
||||||
var shapedText = shaper.Shape(DisplayName, DisplayNamePaint);
|
var shapedText = shaper.Shape(DisplayName, DisplayNamePaint);
|
||||||
c.DrawShapedText(shaper, DisplayName, left - shapedText.Width / 2, _icon.Margin * 8 + size, DisplayNamePaint);
|
c.DrawShapedText(shaper, DisplayName, left - shapedText.Points[^1].X / 2, _icon.Margin * 8 + size, DisplayNamePaint);
|
||||||
|
|
||||||
float topBase = _icon.Margin + size * 2;
|
float topBase = _icon.Margin + size * 2;
|
||||||
if (!string.IsNullOrEmpty(_unlockedDescription))
|
if (!string.IsNullOrEmpty(_unlockedDescription))
|
||||||
|
|
@ -97,3 +97,4 @@ public class BaseItemAccessToken : UCreator
|
||||||
c.DrawBitmap(_icon.Preview ?? _icon.DefaultPreview, new SKRect(left - h / 2, topBase, left + h / 2, Width - _icon.Margin), ImagePaint);
|
c.DrawBitmap(_icon.Preview ?? _icon.DefaultPreview, new SKRect(left - h / 2, topBase, left + h / 2, Width - _icon.Margin), ImagePaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
|
||||||
|
|
||||||
public class BaseJuno : BaseIcon
|
|
||||||
{
|
|
||||||
private BaseIcon _character;
|
|
||||||
|
|
||||||
public BaseJuno(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath baseCid, "BaseAthenaCharacterItemDefinition") &&
|
|
||||||
Utils.TryLoadObject(baseCid.AssetPathName.Text, out UObject cid))
|
|
||||||
{
|
|
||||||
_character = new BaseIcon(cid, Style);
|
|
||||||
_character.ParseForInfo();
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath assembledMeshSchema, "AssembledMeshSchema", "LowDetailsAssembledMeshSchema") &&
|
|
||||||
Utils.TryLoadObject(assembledMeshSchema.AssetPathName.Text, out UObject meshSchema) &&
|
|
||||||
meshSchema.TryGetValue(out FInstancedStruct[] additionalData, "AdditionalData"))
|
|
||||||
{
|
|
||||||
foreach (var data in additionalData)
|
|
||||||
{
|
|
||||||
if (data.NonConstStruct?.TryGetValue(out FSoftObjectPath largePreview, "LargePreviewImage", "SmallPreviewImage") ?? false)
|
|
||||||
{
|
|
||||||
_character.Preview = Utils.GetBitmap(largePreview);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath baseEid, "BaseAthenaDanceItemDefinition") &&
|
|
||||||
Utils.TryLoadObject(baseEid.AssetPathName.Text, out UObject eid))
|
|
||||||
{
|
|
||||||
_character = new BaseIcon(eid, Style);
|
|
||||||
_character.ParseForInfo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SKBitmap[] Draw() => _character.Draw();
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseMaterialInstance : BaseIcon
|
public class BaseMaterialInstance : BaseIcon
|
||||||
{
|
{
|
||||||
public BaseMaterialInstance(UObject uObject, EIconStyle style) : base(uObject, style)
|
public BaseMaterialInstance(UObject uObject, EIconStyle style) : base(uObject, style)
|
||||||
|
|
@ -17,12 +17,11 @@ public class BaseMaterialInstance : BaseIcon
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
{
|
{
|
||||||
if (Object is not UMaterialInstanceConstant material) return;
|
if (!(Object is UMaterialInstanceConstant material)) return;
|
||||||
|
|
||||||
texture_finding:
|
|
||||||
foreach (var textureParameter in material.TextureParameterValues) // get texture from base material
|
foreach (var textureParameter in material.TextureParameterValues) // get texture from base material
|
||||||
{
|
{
|
||||||
if (!textureParameter.ParameterValue.TryLoad<UTexture2D>(out var texture) || Preview != null) continue;
|
if (!(textureParameter.ParameterValue is UTexture2D texture) || Preview != null) continue;
|
||||||
switch (textureParameter.ParameterInfo.Name.Text)
|
switch (textureParameter.ParameterInfo.Name.Text)
|
||||||
{
|
{
|
||||||
case "SeriesTexture":
|
case "SeriesTexture":
|
||||||
|
|
@ -31,7 +30,6 @@ public class BaseMaterialInstance : BaseIcon
|
||||||
case "TextureA":
|
case "TextureA":
|
||||||
case "TextureB":
|
case "TextureB":
|
||||||
case "OfferImage":
|
case "OfferImage":
|
||||||
case "CarTexture":
|
|
||||||
Preview = Utils.GetBitmap(texture);
|
Preview = Utils.GetBitmap(texture);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -47,14 +45,6 @@ public class BaseMaterialInstance : BaseIcon
|
||||||
if (material == null) return;
|
if (material == null) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Preview == null)
|
|
||||||
{
|
|
||||||
if (material.TryGetValue(out FPackageIndex parent, "Parent"))
|
|
||||||
Utils.TryGetPackageIndexExport(parent, out material);
|
|
||||||
|
|
||||||
goto texture_finding;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var vectorParameter in material.VectorParameterValues)
|
foreach (var vectorParameter in material.VectorParameterValues)
|
||||||
{
|
{
|
||||||
if (vectorParameter.ParameterValue == null) continue;
|
if (vectorParameter.ParameterValue == null) continue;
|
||||||
|
|
@ -71,9 +61,9 @@ public class BaseMaterialInstance : BaseIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
switch (Style)
|
switch (Style)
|
||||||
|
|
@ -87,6 +77,7 @@ public class BaseMaterialInstance : BaseIcon
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
using CUE4Parse.UE4.Assets.Objects;
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
using CUE4Parse.UE4.Objects.Core.Math;
|
using CUE4Parse.UE4.Objects.Core.Math;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseMtxOffer : UCreator
|
public class BaseMtxOffer : UCreator
|
||||||
{
|
{
|
||||||
public BaseMtxOffer(UObject uObject, EIconStyle style) : base(uObject, style)
|
public BaseMtxOffer(UObject uObject, EIconStyle style) : base(uObject, style)
|
||||||
|
|
@ -17,9 +17,10 @@ public class BaseMtxOffer : UCreator
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
{
|
{
|
||||||
if (Object.TryGetValue(out FSoftObjectPath image, "SoftDetailsImage", "SoftTileImage"))
|
if (Object.TryGetValue(out FStructFallback typeImage, "DetailsImage", "TileImage") &&
|
||||||
|
typeImage.TryGetValue(out FPackageIndex resource, "ResourceObject"))
|
||||||
{
|
{
|
||||||
Preview = Utils.GetBitmap(image);
|
Preview = Utils.GetBitmap(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.TryGetValue(out FStructFallback gradient, "Gradient") &&
|
if (Object.TryGetValue(out FStructFallback gradient, "Gradient") &&
|
||||||
|
|
@ -55,9 +56,9 @@ public class BaseMtxOffer : UCreator
|
||||||
Description = Utils.RemoveHtmlTags(Description);
|
Description = Utils.RemoveHtmlTags(Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
switch (Style)
|
switch (Style)
|
||||||
|
|
@ -78,6 +79,7 @@ public class BaseMtxOffer : UCreator
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
|
||||||
|
|
||||||
public class BaseOfferDisplayData : UCreator
|
|
||||||
{
|
|
||||||
private readonly List<BaseMaterialInstance> _offerImages;
|
|
||||||
|
|
||||||
public BaseOfferDisplayData(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
_offerImages = new List<BaseMaterialInstance>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
if (!Object.TryGetValue(out FStructFallback[] contextualPresentations, "ContextualPresentations"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (var i = 0; i < contextualPresentations.Length; i++)
|
|
||||||
{
|
|
||||||
if (!contextualPresentations[i].TryGetValue(out FSoftObjectPath material, "Material") ||
|
|
||||||
!material.TryLoad(out UMaterialInterface presentation)) continue;
|
|
||||||
|
|
||||||
var offerImage = new BaseMaterialInstance(presentation, Style);
|
|
||||||
offerImage.ParseForInfo();
|
|
||||||
_offerImages.Add(offerImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
|
||||||
{
|
|
||||||
var ret = new SKBitmap[_offerImages.Count];
|
|
||||||
for (var i = 0; i < ret.Length; i++)
|
|
||||||
{
|
|
||||||
ret[i] = _offerImages[i]?.Draw()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
|
|
@ -6,8 +6,8 @@ using FModel.Services;
|
||||||
using FModel.ViewModels;
|
using FModel.ViewModels;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BasePlaylist : UCreator
|
public class BasePlaylist : UCreator
|
||||||
{
|
{
|
||||||
private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView;
|
private ApiEndpointViewModel _apiEndpointView => ApplicationService.ApiEndpointView;
|
||||||
|
|
@ -34,18 +34,16 @@ public class BasePlaylist : UCreator
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var playlist = _apiEndpointView.FortniteApi.GetPlaylist(playlistName.Text);
|
var playlist = _apiEndpointView.FortniteApi.GetPlaylist(playlistName.Text);
|
||||||
if (!playlist.IsSuccess || playlist.Data.Images is not { HasShowcase: true } ||
|
if (!playlist.IsSuccess || !playlist.Data.Images.HasShowcase ||
|
||||||
!_apiEndpointView.FortniteApi.TryGetBytes(playlist.Data.Images.Showcase, out var image))
|
!_apiEndpointView.FortniteApi.TryGetBytes(playlist.Data.Images.Showcase, out var image))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Preview = Utils.GetBitmap(image).ResizeWithRatio(1024, 512);
|
Preview = Utils.GetBitmap(image).Resize(1024, 512); // Force size to 1024x512 to prevent huge previews.
|
||||||
Width = Preview.Width;
|
|
||||||
Height = Preview.Height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
switch (Style)
|
switch (Style)
|
||||||
|
|
@ -66,7 +64,7 @@ public class BasePlaylist : UCreator
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMissionIcon(SKCanvas c)
|
private void DrawMissionIcon(SKCanvas c)
|
||||||
|
|
@ -75,3 +73,4 @@ public class BasePlaylist : UCreator
|
||||||
c.DrawBitmap(_missionIcon, new SKPoint(5, 5), ImagePaint);
|
c.DrawBitmap(_missionIcon, new SKPoint(5, 5), ImagePaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Engine;
|
using CUE4Parse.UE4.Assets.Exports.Engine;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
using CUE4Parse.UE4.Assets.Objects;
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
|
|
@ -12,8 +10,8 @@ using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseQuest : BaseIcon
|
public class BaseQuest : BaseIcon
|
||||||
{
|
{
|
||||||
private int _count;
|
private int _count;
|
||||||
|
|
@ -69,26 +67,14 @@ public class BaseQuest : BaseIcon
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(ShortDescription))
|
|
||||||
Description = ShortDescription;
|
Description = ShortDescription;
|
||||||
if (string.IsNullOrEmpty(DisplayName) && !string.IsNullOrEmpty(Description))
|
if (Object.TryGetValue(out FText completionText, "CompletionText"))
|
||||||
DisplayName = Description;
|
Description += "\n" + completionText.Text;
|
||||||
if (DisplayName == Description)
|
if (Object.TryGetValue(out FSoftObjectPath tandemCharacterData, "TandemCharacterData") &&
|
||||||
Description = string.Empty;
|
|
||||||
|
|
||||||
if ((Object.TryGetValue(out FSoftObjectPath icon, "QuestGiverWidgetIcon", "NotificationIconOverride") &&
|
|
||||||
Utils.TryLoadObject(icon.AssetPathName.Text, out UObject iconObject)) ||
|
|
||||||
(Object.TryGetValue(out FSoftObjectPath tandemCharacterData, "TandemCharacterData") &&
|
|
||||||
Utils.TryLoadObject(tandemCharacterData.AssetPathName.Text, out UObject uObject) &&
|
Utils.TryLoadObject(tandemCharacterData.AssetPathName.Text, out UObject uObject) &&
|
||||||
uObject.TryGetValue(out FSoftObjectPath tandemIcon, "EntryListIcon", "ToastIcon") &&
|
uObject.TryGetValue(out FSoftObjectPath tandemIcon, "SidePanelIcon", "EntryListIcon", "ToastIcon"))
|
||||||
Utils.TryLoadObject(tandemIcon.AssetPathName.Text, out iconObject)))
|
|
||||||
{
|
{
|
||||||
Preview = iconObject switch
|
Preview = Utils.GetBitmap(tandemIcon);
|
||||||
{
|
|
||||||
UTexture2D text => Utils.GetBitmap(text),
|
|
||||||
UMaterialInstanceConstant mat => Utils.GetBitmap(mat),
|
|
||||||
_ => Preview
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,21 +114,14 @@ public class BaseQuest : BaseIcon
|
||||||
}
|
}
|
||||||
else if (!_unauthorizedReward.Contains(name.Text))
|
else if (!_unauthorizedReward.Contains(name.Text))
|
||||||
{
|
{
|
||||||
_reward = new Reward(quantity, $"{name}:{primaryAssetName}");
|
_reward = new Reward(quantity, primaryAssetName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_reward == null)
|
if (_reward == null && Object.TryGetValue(out UDataTable rewardsTable, "RewardsTable"))
|
||||||
{
|
{
|
||||||
FName rowName = null;
|
if (rewardsTable.TryGetDataTableRow("Default", StringComparison.InvariantCulture, out var row))
|
||||||
if (Object.TryGetValue(out UDataTable rewardsTable, "RewardsTable"))
|
|
||||||
rowName = new FName("Default");
|
|
||||||
else if (Object.TryGetValue(out FStructFallback[] rewardTableRows, "IndividualRewardTableRows") &&
|
|
||||||
rewardTableRows.Length > 0 && rewardTableRows[0].TryGetValue(out rowName, "RowName") &&
|
|
||||||
rewardTableRows[0].TryGetValue(out rewardsTable, "DataTable")) {}
|
|
||||||
|
|
||||||
if (rewardsTable != null && rowName != null && rewardsTable.TryGetDataTableRow(rowName.Text, StringComparison.InvariantCulture, out var row))
|
|
||||||
{
|
{
|
||||||
if (row.TryGetValue(out FName templateId, "TemplateId") &&
|
if (row.TryGetValue(out FName templateId, "TemplateId") &&
|
||||||
row.TryGetValue(out int quantity, "Quantity"))
|
row.TryGetValue(out int quantity, "Quantity"))
|
||||||
|
|
@ -174,14 +153,14 @@ public class BaseQuest : BaseIcon
|
||||||
DrawTexts(c, y);
|
DrawTexts(c, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawQuest(c, 0);
|
DrawQuest(c, 0);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ReformatString(string s, string completionCount, bool isAll)
|
private string ReformatString(string s, string completionCount, bool isAll)
|
||||||
|
|
@ -246,6 +225,7 @@ public class BaseQuest : BaseIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(_informationPaint.Typeface);
|
var shaper = new CustomSKShaper(_informationPaint.Typeface);
|
||||||
|
shaper.Shape(DisplayName, _informationPaint);
|
||||||
c.DrawShapedText(shaper, DisplayName, Height, y + 50, _informationPaint);
|
c.DrawShapedText(shaper, DisplayName, Height, y + 50, _informationPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,3 +256,4 @@ public class BaseQuest : BaseIcon
|
||||||
_reward.DrawQuest(c, new SKRect(Height, outY + 25, Width - 20, y + Height - 25));
|
_reward.DrawQuest(c, new SKRect(Height, outY + 25, Width - 20, y + Height - 25));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
using CUE4Parse.UE4.Assets.Objects;
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
|
|
@ -8,19 +8,12 @@ using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
|
||||||
public class Page
|
|
||||||
{
|
{
|
||||||
public int LevelsNeededForUnlock;
|
|
||||||
public int RewardsNeededForUnlock;
|
|
||||||
public Reward[] RewardEntryList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BaseSeason : UCreator
|
public class BaseSeason : UCreator
|
||||||
{
|
{
|
||||||
private Reward _firstWinReward;
|
private Reward _firstWinReward;
|
||||||
private Page[] _bookXpSchedule;
|
private Dictionary<int, List<Reward>> _bookXpSchedule;
|
||||||
private const int _headerHeight = 150;
|
private const int _headerHeight = 150;
|
||||||
// keep the list because rewards are ordered by least to most important
|
// keep the list because rewards are ordered by least to most important
|
||||||
// we only care about the most but we also have filters so we can't just take the last reward
|
// we only care about the most but we also have filters so we can't just take the last reward
|
||||||
|
|
@ -34,9 +27,9 @@ public class BaseSeason : UCreator
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
{
|
{
|
||||||
_bookXpSchedule = Array.Empty<Page>();
|
_bookXpSchedule = new Dictionary<int, List<Reward>>();
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "ItemName"))
|
if (Object.TryGetValue(out FText displayName, "DisplayName"))
|
||||||
DisplayName = displayName.Text.ToUpperInvariant();
|
DisplayName = displayName.Text.ToUpperInvariant();
|
||||||
|
|
||||||
if (Object.TryGetValue(out FStructFallback seasonFirstWinRewards, "SeasonFirstWinRewards") &&
|
if (Object.TryGetValue(out FStructFallback seasonFirstWinRewards, "SeasonFirstWinRewards") &&
|
||||||
|
|
@ -52,60 +45,68 @@ public class BaseSeason : UCreator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.TryGetValue(out FPackageIndex[] additionalSeasonData, "AdditionalSeasonData"))
|
var freeLevels = Array.Empty<FStructFallback>();
|
||||||
|
var paidLevels = Array.Empty<FStructFallback>();
|
||||||
|
if (Object.TryGetValue(out FPackageIndex[] additionalSeasonData, "AdditionalSeasonData") &&
|
||||||
|
additionalSeasonData.Length > 0 && Utils.TryGetPackageIndexExport(additionalSeasonData[0], out UObject data) &&
|
||||||
|
data.TryGetValue(out FStructFallback battlePassXpScheduleFree, "BattlePassXpScheduleFree") &&
|
||||||
|
battlePassXpScheduleFree.TryGetValue(out freeLevels, "Levels") &&
|
||||||
|
data.TryGetValue(out FStructFallback battlePassXpSchedulePaid, "BattlePassXpSchedulePaid") &&
|
||||||
|
battlePassXpSchedulePaid.TryGetValue(out paidLevels, "Levels"))
|
||||||
{
|
{
|
||||||
foreach (var data in additionalSeasonData)
|
// we got them boys
|
||||||
|
}
|
||||||
|
else if (Object.TryGetValue(out FStructFallback bookXpScheduleFree, "BookXpScheduleFree") &&
|
||||||
|
bookXpScheduleFree.TryGetValue(out freeLevels, "Levels") &&
|
||||||
|
Object.TryGetValue(out FStructFallback bookXpSchedulePaid, "BookXpSchedulePaid") &&
|
||||||
|
bookXpSchedulePaid.TryGetValue(out paidLevels, "Levels"))
|
||||||
{
|
{
|
||||||
if (!Utils.TryGetPackageIndexExport(data, out UObject packageIndex) ||
|
// we got them boys
|
||||||
!packageIndex.TryGetValue(out FStructFallback[] pageList, "PageList")) continue;
|
}
|
||||||
|
|
||||||
var i = 0;
|
for (var i = 0; i < freeLevels.Length; i++)
|
||||||
_bookXpSchedule = new Page[pageList.Length];
|
|
||||||
foreach (var page in pageList)
|
|
||||||
{
|
{
|
||||||
if (!page.TryGetValue(out int levelsNeededForUnlock, "LevelsNeededForUnlock") ||
|
_bookXpSchedule[i] = new List<Reward>();
|
||||||
!page.TryGetValue(out int rewardsNeededForUnlock, "RewardsNeededForUnlock") ||
|
if (!freeLevels[i].TryGetValue(out rewards, "Rewards")) continue;
|
||||||
!page.TryGetValue(out FPackageIndex[] rewardEntryList, "RewardEntryList"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var p = new Page
|
foreach (var reward in rewards)
|
||||||
{
|
{
|
||||||
LevelsNeededForUnlock = levelsNeededForUnlock,
|
if (!reward.TryGetValue(out FSoftObjectPath itemDefinition, "ItemDefinition") ||
|
||||||
RewardsNeededForUnlock = rewardsNeededForUnlock,
|
itemDefinition.AssetPathName.Text.Contains("/Items/Tokens/") ||
|
||||||
RewardEntryList = new Reward[rewardEntryList.Length]
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var j = 0; j < p.RewardEntryList.Length; j++)
|
|
||||||
{
|
|
||||||
if (!Utils.TryGetPackageIndexExport(rewardEntryList[j], out packageIndex) ||
|
|
||||||
!packageIndex.TryGetValue(out FStructFallback battlePassOffer, "BattlePassOffer") ||
|
|
||||||
!battlePassOffer.TryGetValue(out FStructFallback rewardItem, "RewardItem") ||
|
|
||||||
!rewardItem.TryGetValue(out FSoftObjectPath itemDefinition, "ItemDefinition") ||
|
|
||||||
!Utils.TryLoadObject(itemDefinition.AssetPathName.Text, out UObject uObject)) continue;
|
!Utils.TryLoadObject(itemDefinition.AssetPathName.Text, out UObject uObject)) continue;
|
||||||
|
|
||||||
p.RewardEntryList[j] = new Reward(uObject);
|
_bookXpSchedule[i].Add(new Reward(uObject));
|
||||||
}
|
|
||||||
|
|
||||||
_bookXpSchedule[i++] = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Height += 100 * _bookXpSchedule.Sum(x => x.RewardEntryList.Length) / _bookXpSchedule.Length;
|
for (var i = 0; i < paidLevels.Length; i++)
|
||||||
|
{
|
||||||
|
if (!paidLevels[i].TryGetValue(out rewards, "Rewards")) continue;
|
||||||
|
|
||||||
|
foreach (var reward in rewards)
|
||||||
|
{
|
||||||
|
if (!reward.TryGetValue(out FSoftObjectPath itemDefinition, "ItemDefinition") ||
|
||||||
|
!Utils.TryLoadObject(itemDefinition.AssetPathName.Text, out UObject uObject)) continue;
|
||||||
|
|
||||||
|
_bookXpSchedule[i].Add(new Reward(uObject));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
Height += 100 * _bookXpSchedule.Count / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawHeader(c);
|
DrawHeader(c);
|
||||||
_firstWinReward?.DrawSeasonWin(c, _headerHeight);
|
_firstWinReward?.DrawSeasonWin(c, _headerHeight);
|
||||||
DrawBookSchedule(c);
|
DrawBookSchedule(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private const int _DEFAULT_AREA_SIZE = 80;
|
private const int _DEFAULT_AREA_SIZE = 80;
|
||||||
|
|
@ -115,6 +116,12 @@ public class BaseSeason : UCreator
|
||||||
Typeface = Utils.Typefaces.Bundle, TextSize = 50,
|
Typeface = Utils.Typefaces.Bundle, TextSize = 50,
|
||||||
TextAlign = SKTextAlign.Center, Color = SKColor.Parse("#262630")
|
TextAlign = SKTextAlign.Center, Color = SKColor.Parse("#262630")
|
||||||
};
|
};
|
||||||
|
private readonly SKPaint _bookPaint = new()
|
||||||
|
{
|
||||||
|
IsAntialias = true, FilterQuality = SKFilterQuality.High,
|
||||||
|
Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.BundleNumber,
|
||||||
|
Color = SKColors.White, TextAlign = SKTextAlign.Center, TextSize = 15
|
||||||
|
};
|
||||||
|
|
||||||
public void DrawHeader(SKCanvas c)
|
public void DrawHeader(SKCanvas c)
|
||||||
{
|
{
|
||||||
|
|
@ -136,23 +143,32 @@ public class BaseSeason : UCreator
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(_headerPaint.Typeface);
|
var shaper = new CustomSKShaper(_headerPaint.Typeface);
|
||||||
c.DrawShapedText(shaper, DisplayName, Width / 2f, _headerHeight / 2f + _headerPaint.TextSize / 2 - 10, _headerPaint);
|
var shapedText = shaper.Shape(DisplayName, _headerPaint);
|
||||||
|
c.DrawShapedText(shaper, DisplayName, (Width - shapedText.Points[^1].X) / 2, _headerHeight / 2 + _headerPaint.TextSize / 2 - 10, _headerPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawBookSchedule(SKCanvas c)
|
private void DrawBookSchedule(SKCanvas c)
|
||||||
{
|
{
|
||||||
var x = 20;
|
var x = 20;
|
||||||
var y = _headerHeight + 50;
|
var y = _headerHeight + 50;
|
||||||
foreach (var page in _bookXpSchedule)
|
foreach (var (index, reward) in _bookXpSchedule)
|
||||||
{
|
{
|
||||||
foreach (var reward in page.RewardEntryList)
|
if (index == 0 || reward.Count == 0 || !reward[0].HasReward())
|
||||||
{
|
continue;
|
||||||
reward.DrawSeason(c, x, y, _DEFAULT_AREA_SIZE);
|
|
||||||
x += _DEFAULT_AREA_SIZE + 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
c.DrawText(index.ToString(), new SKPoint(x + _DEFAULT_AREA_SIZE / 2, y - 5), _bookPaint);
|
||||||
|
reward[0].DrawSeason(c, x, y, _DEFAULT_AREA_SIZE);
|
||||||
|
|
||||||
|
if (index != 1 && index % 10 == 0)
|
||||||
|
{
|
||||||
y += _DEFAULT_AREA_SIZE + 20;
|
y += _DEFAULT_AREA_SIZE + 20;
|
||||||
x = 20;
|
x = 20;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x += _DEFAULT_AREA_SIZE + 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseSeries : BaseIcon
|
public class BaseSeries : BaseIcon
|
||||||
{
|
{
|
||||||
public BaseSeries(UObject uObject, EIconStyle style) : base(uObject, style)
|
public BaseSeries(UObject uObject, EIconStyle style) : base(uObject, style)
|
||||||
|
|
@ -14,13 +14,14 @@ public class BaseSeries : BaseIcon
|
||||||
GetSeries(Object);
|
GetSeries(Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawBackground(c);
|
DrawBackground(c);
|
||||||
|
|
||||||
return new []{ret};
|
return SKImage.FromBitmap(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,228 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using CUE4Parse.UE4.Versions;
|
|
||||||
using FModel.Framework;
|
|
||||||
using FModel.Settings;
|
|
||||||
using SkiaSharp;
|
|
||||||
using SkiaSharp.HarfBuzz;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
|
||||||
|
|
||||||
public class BaseTandem : BaseIcon
|
|
||||||
{
|
|
||||||
private string _generalDescription, _additionalDescription;
|
|
||||||
|
|
||||||
public BaseTandem(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
DefaultPreview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/BattleRoyale/FeaturedItems/Outfit/T-AthenaSoldiers-CID-883-Athena-Commando-M-ChOneJonesy.T-AthenaSoldiers-CID-883-Athena-Commando-M-ChOneJonesy");
|
|
||||||
Margin = 0;
|
|
||||||
Width = 690;
|
|
||||||
Height = 1080;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
base.ParseForInfo();
|
|
||||||
|
|
||||||
string sidePanel = string.Empty, entryList = string.Empty;
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath sidePanelIcon, "SidePanelIcon"))
|
|
||||||
sidePanel = sidePanelIcon.AssetPathName.Text;
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath entryListIcon, "EntryListIcon"))
|
|
||||||
entryList = entryListIcon.AssetPathName.Text;
|
|
||||||
|
|
||||||
// Overrides for generic "default" images Epic uses for Quest-only or unfinished NPCs
|
|
||||||
if (sidePanel.Contains("Clown") && entryList.Contains("Clown"))
|
|
||||||
Preview = null;
|
|
||||||
else if (sidePanel.Contains("Bane") && !Object.Name.Contains("Sorana"))
|
|
||||||
Preview = Utils.GetBitmap(entryList);
|
|
||||||
else if (!string.IsNullOrWhiteSpace(sidePanel) && !sidePanel.Contains("Clown"))
|
|
||||||
Preview = Utils.GetBitmap(sidePanel);
|
|
||||||
else if ((string.IsNullOrWhiteSpace(sidePanel) || sidePanel.Contains("Clown")) && !string.IsNullOrWhiteSpace(entryList))
|
|
||||||
Preview = Utils.GetBitmap(entryList);
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText genDesc, "GeneralDescription"))
|
|
||||||
_generalDescription = genDesc.Text;
|
|
||||||
if (Object.TryGetValue(out FText addDesc, "AdditionalDescription"))
|
|
||||||
_additionalDescription = addDesc.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
|
||||||
{
|
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
|
||||||
using var c = new SKCanvas(ret);
|
|
||||||
|
|
||||||
DrawBackground(c);
|
|
||||||
DrawPreview(c);
|
|
||||||
DrawHaze(c);
|
|
||||||
|
|
||||||
// Korean is slightly smaller than other languages, so the font size is increased slightly
|
|
||||||
DrawName(c);
|
|
||||||
DrawGeneralDescription(c);
|
|
||||||
DrawAdditionalDescription(c);
|
|
||||||
|
|
||||||
return new[] { ret };
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly SKPaint _panelPaint = new() { IsAntialias = true, FilterQuality = SKFilterQuality.High, Color = SKColor.Parse("#0045C7") };
|
|
||||||
|
|
||||||
private new void DrawBackground(SKCanvas c)
|
|
||||||
{
|
|
||||||
c.DrawBitmap(SKBitmap.Decode(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/npcleftside.png"))?.Stream).Resize(Width, Height), 0, 0, new SKPaint { IsAntialias = false, FilterQuality = SKFilterQuality.None, ImageFilter = SKImageFilter.CreateBlur(0, 25) });
|
|
||||||
|
|
||||||
using var rect1 = new SKPath { FillType = SKPathFillType.EvenOdd };
|
|
||||||
_panelPaint.Color = SKColor.Parse("#002A8C");
|
|
||||||
rect1.MoveTo(29, 0);
|
|
||||||
rect1.LineTo(62, Height);
|
|
||||||
rect1.LineTo(Width, Height);
|
|
||||||
rect1.LineTo(Width, 0);
|
|
||||||
rect1.LineTo(29, 0);
|
|
||||||
rect1.Close();
|
|
||||||
c.DrawPath(rect1, _panelPaint);
|
|
||||||
|
|
||||||
_panelPaint.Shader = SKShader.CreateLinearGradient(new SKPoint(29, 0), new SKPoint(Width, Height),
|
|
||||||
new[] { SKColor.Parse("#002A8C") }, SKShaderTileMode.Clamp);
|
|
||||||
c.DrawPath(rect1, _panelPaint);
|
|
||||||
|
|
||||||
_panelPaint.Shader = SKShader.CreateRadialGradient(new SKPoint(348, 196), 300, new[] { SKColor.Parse("#0049CE"), SKColor.Parse("#002A8C") }, SKShaderTileMode.Clamp);
|
|
||||||
c.DrawPath(rect1, _panelPaint);
|
|
||||||
|
|
||||||
using var rect2 = new SKPath { FillType = SKPathFillType.EvenOdd };
|
|
||||||
|
|
||||||
rect2.MoveTo(10, 0);
|
|
||||||
rect2.LineTo(30, 0);
|
|
||||||
rect2.LineTo(63, Height);
|
|
||||||
rect2.LineTo(56, Height);
|
|
||||||
rect2.LineTo(10, 0);
|
|
||||||
rect2.Close();
|
|
||||||
c.DrawPath(rect2, _panelPaint);
|
|
||||||
|
|
||||||
_panelPaint.Shader = SKShader.CreateLinearGradient(new SKPoint(10, 0), new SKPoint(62, Height),
|
|
||||||
new[] { SKColor.Parse("#0045C7") }, SKShaderTileMode.Clamp);
|
|
||||||
c.DrawPath(rect2, _panelPaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawPreview(SKCanvas c)
|
|
||||||
{
|
|
||||||
var previewToUse = Preview ?? DefaultPreview;
|
|
||||||
|
|
||||||
if (Preview == null)
|
|
||||||
{
|
|
||||||
previewToUse = DefaultPreview;
|
|
||||||
ImagePaint.BlendMode = SKBlendMode.DstOut;
|
|
||||||
ImagePaint.Color = SKColor.Parse("#00175F");
|
|
||||||
}
|
|
||||||
|
|
||||||
var x = -125;
|
|
||||||
|
|
||||||
switch (previewToUse.Width)
|
|
||||||
{
|
|
||||||
case 512 when previewToUse.Height == 1024:
|
|
||||||
previewToUse = previewToUse.ResizeWithRatio(500, 1000);
|
|
||||||
x = 100;
|
|
||||||
break;
|
|
||||||
case 512 when previewToUse.Height == 512:
|
|
||||||
case 128 when previewToUse.Height == 128:
|
|
||||||
previewToUse = previewToUse.Resize(512);
|
|
||||||
x = 125;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
previewToUse = previewToUse.Resize(1000, 1000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
c.DrawBitmap(previewToUse, x, 30, ImagePaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawHaze(SKCanvas c)
|
|
||||||
{
|
|
||||||
using var rect1 = new SKPath { FillType = SKPathFillType.EvenOdd };
|
|
||||||
rect1.MoveTo(29, 0);
|
|
||||||
rect1.LineTo(62, Height);
|
|
||||||
rect1.LineTo(Width, Height);
|
|
||||||
rect1.LineTo(Width, 0);
|
|
||||||
rect1.LineTo(29, 0);
|
|
||||||
rect1.Close();
|
|
||||||
|
|
||||||
_panelPaint.Shader = SKShader.CreateLinearGradient(new SKPoint(343, 0), new SKPoint(343, Height),
|
|
||||||
new[] { SKColors.Transparent, SKColor.Parse("#001E70FF"), SKColor.Parse("#001E70").WithAlpha(200), SKColor.Parse("#001E70").WithAlpha(245), SKColor.Parse("#001E70") }, new[] { 0, (float) .1, (float) .65, (float) .85, 1 }, SKShaderTileMode.Clamp);
|
|
||||||
c.DrawPath(rect1, _panelPaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawName(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(DisplayName)) return;
|
|
||||||
|
|
||||||
DisplayNamePaint.TextSize = UserSettings.Default.AssetLanguage switch
|
|
||||||
{
|
|
||||||
ELanguage.Korean => 56,
|
|
||||||
_ => 42
|
|
||||||
};
|
|
||||||
|
|
||||||
DisplayNamePaint.TextScaleX = (float) 1.1;
|
|
||||||
DisplayNamePaint.Color = SKColors.White;
|
|
||||||
DisplayNamePaint.TextSkewX = (float) -.25;
|
|
||||||
DisplayNamePaint.TextAlign = SKTextAlign.Left;
|
|
||||||
|
|
||||||
var typeface = Utils.Typefaces.TandemDisplayName;
|
|
||||||
if (typeface == Utils.Typefaces.Default)
|
|
||||||
{
|
|
||||||
DisplayNamePaint.TextSize = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayNamePaint.Typeface = typeface;
|
|
||||||
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
|
||||||
c.DrawShapedText(shaper, DisplayName.ToUpper(), 97, 900, DisplayNamePaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawGeneralDescription(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(_generalDescription)) return;
|
|
||||||
|
|
||||||
DescriptionPaint.TextSize = UserSettings.Default.AssetLanguage switch
|
|
||||||
{
|
|
||||||
ELanguage.Korean => 20,
|
|
||||||
_ => 17
|
|
||||||
};
|
|
||||||
|
|
||||||
DescriptionPaint.Color = SKColor.Parse("#00FFFB");
|
|
||||||
DescriptionPaint.TextAlign = SKTextAlign.Left;
|
|
||||||
|
|
||||||
var typeface = Utils.Typefaces.TandemGenDescription;
|
|
||||||
if (typeface == Utils.Typefaces.Default)
|
|
||||||
{
|
|
||||||
DescriptionPaint.TextSize = 21;
|
|
||||||
}
|
|
||||||
|
|
||||||
DescriptionPaint.Typeface = typeface;
|
|
||||||
var shaper = new CustomSKShaper(DescriptionPaint.Typeface);
|
|
||||||
c.DrawShapedText(shaper, _generalDescription.ToUpper(), 97, 930, DescriptionPaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawAdditionalDescription(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(_additionalDescription)) return;
|
|
||||||
|
|
||||||
DescriptionPaint.TextSize = UserSettings.Default.AssetLanguage switch
|
|
||||||
{
|
|
||||||
ELanguage.Korean => 22,
|
|
||||||
_ => 18
|
|
||||||
};
|
|
||||||
|
|
||||||
DescriptionPaint.Color = SKColor.Parse("#89D8FF");
|
|
||||||
DescriptionPaint.TextAlign = SKTextAlign.Left;
|
|
||||||
|
|
||||||
var typeface = Utils.Typefaces.TandemAddDescription;
|
|
||||||
if (typeface == Utils.Typefaces.Default)
|
|
||||||
{
|
|
||||||
DescriptionPaint.TextSize = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
DescriptionPaint.Typeface = typeface;
|
|
||||||
Utils.DrawMultilineText(c, _additionalDescription, Width, 0, SKTextAlign.Left,
|
|
||||||
new SKRect(97, 960, Width - 10, Height), DescriptionPaint, out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -9,8 +9,8 @@ using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class BaseUserControl : UCreator
|
public class BaseUserControl : UCreator
|
||||||
{
|
{
|
||||||
private List<Options> _optionValues = new();
|
private List<Options> _optionValues = new();
|
||||||
|
|
@ -37,9 +37,9 @@ public class BaseUserControl : UCreator
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
{
|
{
|
||||||
if (Object.TryGetValue(out FText optionDisplayName, "OptionDisplayName", "OptionText"))
|
if (Object.TryGetValue(out FText optionDisplayName, "OptionDisplayName"))
|
||||||
DisplayName = optionDisplayName.Text.ToUpperInvariant();
|
DisplayName = optionDisplayName.Text.ToUpperInvariant();
|
||||||
if (Object.TryGetValue(out FText optionDescription, "OptionDescription", "OptionToolTip"))
|
if (Object.TryGetValue(out FText optionDescription, "OptionDescription"))
|
||||||
{
|
{
|
||||||
Description = optionDescription.Text;
|
Description = optionDescription.Text;
|
||||||
|
|
||||||
|
|
@ -48,12 +48,12 @@ public class BaseUserControl : UCreator
|
||||||
Height += (int) _descriptionPaint.TextSize;
|
Height += (int) _descriptionPaint.TextSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.TryGetValue(out FStructFallback[] optionValues, "OptionValues", "Options"))
|
if (Object.TryGetValue(out FStructFallback[] optionValues, "OptionValues"))
|
||||||
{
|
{
|
||||||
_optionValues = new List<Options>();
|
_optionValues = new List<Options>();
|
||||||
foreach (var option in optionValues)
|
foreach (var option in optionValues)
|
||||||
{
|
{
|
||||||
if (option.TryGetValue(out FText displayName, "DisplayName", "DisplayText"))
|
if (option.TryGetValue(out FText displayName, "DisplayName"))
|
||||||
{
|
{
|
||||||
var opt = new Options {Option = displayName.Text.ToUpperInvariant()};
|
var opt = new Options {Option = displayName.Text.ToUpperInvariant()};
|
||||||
if (option.TryGetValue(out FLinearColor color, "Value"))
|
if (option.TryGetValue(out FLinearColor color, "Value"))
|
||||||
|
|
@ -111,15 +111,15 @@ public class BaseUserControl : UCreator
|
||||||
Height += 35 * _optionValues.Count;
|
Height += 35 * _optionValues.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawBackground(c);
|
DrawBackground(c);
|
||||||
DrawInformation(c);
|
DrawInformation(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private new void DrawBackground(SKCanvas c)
|
private new void DrawBackground(SKCanvas c)
|
||||||
|
|
@ -146,6 +146,7 @@ public class BaseUserControl : UCreator
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(_displayNamePaint.Typeface);
|
var shaper = new CustomSKShaper(_displayNamePaint.Typeface);
|
||||||
|
shaper.Shape(DisplayName, _displayNamePaint);
|
||||||
c.DrawShapedText(shaper, DisplayName, Margin, Margin + _displayNamePaint.TextSize, _displayNamePaint);
|
c.DrawShapedText(shaper, DisplayName, Margin, Margin + _displayNamePaint.TextSize, _displayNamePaint);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
c.DrawRect(new SKRect(Margin, Margin, Width - Margin, Margin + _displayNamePaint.TextSize), new SKPaint {Color = SKColors.Blue, IsStroke = true});
|
c.DrawRect(new SKRect(Margin, Margin, Width - Margin, Margin + _displayNamePaint.TextSize), new SKPaint {Color = SKColors.Blue, IsStroke = true});
|
||||||
|
|
@ -189,3 +190,4 @@ public class Options
|
||||||
top += _HEIGHT + _SPACE;
|
top += _HEIGHT + _SPACE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,8 +5,8 @@ using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.FN;
|
namespace FModel.Creator.Bases.FN
|
||||||
|
{
|
||||||
public class Reward
|
public class Reward
|
||||||
{
|
{
|
||||||
private string _rewardQuantity;
|
private string _rewardQuantity;
|
||||||
|
|
@ -64,7 +64,7 @@ public class Reward
|
||||||
_rewardPaint.TextSize = 50;
|
_rewardPaint.TextSize = 50;
|
||||||
if (HasReward())
|
if (HasReward())
|
||||||
{
|
{
|
||||||
c.DrawBitmap((_theReward.Preview ?? _theReward.DefaultPreview).Resize((int) rect.Height), new SKPoint(rect.Left, rect.Top), _rewardPaint);
|
c.DrawBitmap(_theReward.Preview.Resize((int) rect.Height), new SKPoint(rect.Left, rect.Top), _rewardPaint);
|
||||||
|
|
||||||
_rewardPaint.Color = _theReward.Border[0];
|
_rewardPaint.Color = _theReward.Border[0];
|
||||||
_rewardPaint.Typeface = _rewardQuantity.StartsWith("x") ? Utils.Typefaces.BundleNumber : Utils.Typefaces.Bundle;
|
_rewardPaint.Typeface = _rewardQuantity.StartsWith("x") ? Utils.Typefaces.BundleNumber : Utils.Typefaces.Bundle;
|
||||||
|
|
@ -75,6 +75,7 @@ public class Reward
|
||||||
}
|
}
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(_rewardPaint.Typeface);
|
var shaper = new CustomSKShaper(_rewardPaint.Typeface);
|
||||||
|
shaper.Shape(_rewardQuantity, _rewardPaint);
|
||||||
c.DrawShapedText(shaper, _rewardQuantity, rect.Left + rect.Height + 25, rect.MidY + 20, _rewardPaint);
|
c.DrawShapedText(shaper, _rewardQuantity, rect.Left + rect.Height + 25, rect.MidY + 20, _rewardPaint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -88,7 +89,7 @@ public class Reward
|
||||||
public void DrawSeasonWin(SKCanvas c, int size)
|
public void DrawSeasonWin(SKCanvas c, int size)
|
||||||
{
|
{
|
||||||
if (!HasReward()) return;
|
if (!HasReward()) return;
|
||||||
c.DrawBitmap((_theReward.Preview ?? _theReward.DefaultPreview).Resize(size), new SKPoint(0, 0), _rewardPaint);
|
c.DrawBitmap(_theReward.Preview.Resize(size), new SKPoint(0, 0), _rewardPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawSeason(SKCanvas c, int x, int y, int areaSize)
|
public void DrawSeason(SKCanvas c, int x, int y, int areaSize)
|
||||||
|
|
@ -115,33 +116,33 @@ public class Reward
|
||||||
{
|
{
|
||||||
switch (trigger.ToLower())
|
switch (trigger.ToLower())
|
||||||
{
|
{
|
||||||
// case "athenabattlestar":
|
case "athenabattlestar":
|
||||||
// _theReward = new BaseIcon(null, EIconStyle.Default);
|
_theReward = new BaseIcon(null, EIconStyle.Default);
|
||||||
// _theReward.Border[0] = SKColor.Parse("FFDB67");
|
_theReward.Border[0] = SKColor.Parse("FFDB67");
|
||||||
// _theReward.Background[0] = SKColor.Parse("8F4A20");
|
_theReward.Background[0] = SKColor.Parse("8F4A20");
|
||||||
// _theReward.Preview = Utils.GetBitmap("FortniteGame/Content/Athena/UI/Frontend/Art/T_UI_BP_BattleStar_L.T_UI_BP_BattleStar_L");
|
_theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-FNBR-BattlePoints.T-FNBR-BattlePoints");
|
||||||
// break;
|
break;
|
||||||
// case "athenaseasonalxp":
|
case "athenaseasonalxp":
|
||||||
// _theReward = new BaseIcon(null, EIconStyle.Default);
|
_theReward = new BaseIcon(null, EIconStyle.Default);
|
||||||
// _theReward.Border[0] = SKColor.Parse("E6FDB1");
|
_theReward.Border[0] = SKColor.Parse("E6FDB1");
|
||||||
// _theReward.Background[0] = SKColor.Parse("51830F");
|
_theReward.Background[0] = SKColor.Parse("51830F");
|
||||||
// _theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-FNBR-XPUncommon-L.T-FNBR-XPUncommon-L");
|
_theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-FNBR-XPMedium.T-FNBR-XPMedium");
|
||||||
// break;
|
break;
|
||||||
// case "mtxgiveaway":
|
case "mtxgiveaway":
|
||||||
// _theReward = new BaseIcon(null, EIconStyle.Default);
|
_theReward = new BaseIcon(null, EIconStyle.Default);
|
||||||
// _theReward.Border[0] = SKColor.Parse("DCE6FF");
|
_theReward.Border[0] = SKColor.Parse("DCE6FF");
|
||||||
// _theReward.Background[0] = SKColor.Parse("64A0AF");
|
_theReward.Background[0] = SKColor.Parse("64A0AF");
|
||||||
// _theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-Items-MTX.T-Items-MTX");
|
_theReward.Preview = Utils.GetBitmap("FortniteGame/Content/UI/Foundation/Textures/Icons/Items/T-Items-MTX.T-Items-MTX");
|
||||||
// break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
var path = Utils.GetFullPath($"FortniteGame/(?:Content/Athena|Content/Items|Plugins/GameFeatures)/.*?/{trigger}.uasset"); // path has no objectname and its needed so we push the trigger again as the objectname
|
var path = Utils.GetFullPath($"FortniteGame/Content/Athena/.*?/{trigger}.*"); // path has no objectname and its needed so we push the trigger again as the objectname
|
||||||
if (!string.IsNullOrWhiteSpace(path) && Utils.TryLoadObject(path.Replace("uasset", trigger), out UObject d))
|
if (!string.IsNullOrWhiteSpace(path) && Utils.TryLoadObject(path.Replace("uasset", trigger), out UObject d))
|
||||||
{
|
{
|
||||||
_theReward = new BaseIcon(d, EIconStyle.Default);
|
_theReward = new BaseIcon(d, EIconStyle.Default);
|
||||||
_theReward.ParseForReward(false);
|
_theReward.ParseForReward(false);
|
||||||
_theReward.Border[0] = SKColors.White;
|
_theReward.Border[0] = SKColors.White;
|
||||||
_rewardQuantity = $"{_theReward.DisplayName} ({_rewardQuantity})";
|
_rewardQuantity = _theReward.DisplayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -149,3 +150,4 @@ public class Reward
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,287 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Engine;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
|
||||||
using CUE4Parse.UE4.Objects.Core.Math;
|
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using FModel.Extensions;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.MV;
|
|
||||||
|
|
||||||
public class BaseFighter : UCreator
|
|
||||||
{
|
|
||||||
private float _xOffset = 1f;
|
|
||||||
private float _yOffset = 1f;
|
|
||||||
private float _zoom = 1f;
|
|
||||||
|
|
||||||
private readonly SKBitmap _pattern;
|
|
||||||
private readonly SKBitmap _perk;
|
|
||||||
private readonly SKBitmap _emote;
|
|
||||||
private readonly SKBitmap _skin;
|
|
||||||
|
|
||||||
private (SKBitmap, List<string>) _fighterType;
|
|
||||||
private readonly List<SKBitmap> _recommendedPerks;
|
|
||||||
private readonly List<SKBitmap> _availableTaunts;
|
|
||||||
private readonly List<SKBitmap> _skins;
|
|
||||||
|
|
||||||
public BaseFighter(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
Width = 1024;
|
|
||||||
DisplayNamePaint.TextSize = 100;
|
|
||||||
DisplayNamePaint.TextAlign = SKTextAlign.Left;
|
|
||||||
DisplayNamePaint.Typeface = Utils.Typefaces.TandemDisplayName;
|
|
||||||
DescriptionPaint.TextSize = 25;
|
|
||||||
DescriptionPaint.Typeface = Utils.Typefaces.TandemGenDescription;
|
|
||||||
DefaultPreview = Utils.GetBitmap("/Game/Panda_Main/UI/PreMatch/Images/DiamondPortraits/0010_Random.0010_Random");
|
|
||||||
|
|
||||||
_pattern = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/UI_Textures/halftone_jagged.halftone_jagged");
|
|
||||||
_perk = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_perks.ui_icons_perks");
|
|
||||||
_emote = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_emote.ui_icons_emote");
|
|
||||||
_skin = Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_skins.ui_icons_skins");
|
|
||||||
_fighterType.Item2 = new List<string>();
|
|
||||||
_recommendedPerks = new List<SKBitmap>();
|
|
||||||
_availableTaunts = new List<SKBitmap>();
|
|
||||||
_skins = new List<SKBitmap>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
if (Object.TryGetValue(out FLinearColor backgroundColor, "BackgroundColor"))
|
|
||||||
Background = new[] { SKColor.Parse(backgroundColor.Hex) };
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath portraitMaterial, "CollectionsPortraitMaterial") &&
|
|
||||||
portraitMaterial.TryLoad(out UMaterialInstanceConstant portrait))
|
|
||||||
{
|
|
||||||
_xOffset = Math.Abs(portrait.ScalarParameterValues.FirstOrDefault(x => x.ParameterInfo.Name.Text == "XOffset")?.ParameterValue ?? 1f);
|
|
||||||
_yOffset = Math.Abs(portrait.ScalarParameterValues.FirstOrDefault(x => x.ParameterInfo.Name.Text == "YOffset")?.ParameterValue / 10 ?? 1f);
|
|
||||||
_zoom = Math.Clamp(portrait.ScalarParameterValues.FirstOrDefault(x => x.ParameterInfo.Name.Text == "Zoom")?.ParameterValue ?? 1f, 0, 1);
|
|
||||||
Preview = Utils.GetBitmap(portrait);
|
|
||||||
}
|
|
||||||
else if (Object.TryGetValue(out FSoftObjectPath portraitTexture, "NewCharacterSelectPortraitTexture", "HUDPortraitTexture"))
|
|
||||||
Preview = Utils.GetBitmap(portraitTexture);
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName"))
|
|
||||||
DisplayName = displayName.Text;
|
|
||||||
|
|
||||||
GetFighterClassInfo(Object.GetOrDefault("Class", EFighterClass.Support));
|
|
||||||
_fighterType.Item2.Add(Utils.GetLocalizedResource(Object.GetOrDefault("Type", EFighterType.Horizontal)));
|
|
||||||
if (Object.TryGetValue(out FText property, "Property"))
|
|
||||||
_fighterType.Item2.Add(property.Text);
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out UScriptSet recommendedPerks, "RecommendedPerkDatas")) // PORCO DIO WB USE ARRAYS!!!!!!
|
|
||||||
{
|
|
||||||
foreach (var recommendedPerk in recommendedPerks.Properties)
|
|
||||||
{
|
|
||||||
if (recommendedPerk.GenericValue is not FPackageIndex packageIndex ||
|
|
||||||
!Utils.TryGetPackageIndexExport(packageIndex, out UObject export) ||
|
|
||||||
!export.TryGetValue(out FSoftObjectPath rewardThumbnail, "RewardThumbnail"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_recommendedPerks.Add(Utils.GetBitmap(rewardThumbnail));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath[] availableTaunts, "AvailableTauntData"))
|
|
||||||
{
|
|
||||||
foreach (var taunt in availableTaunts)
|
|
||||||
{
|
|
||||||
if (!Utils.TryLoadObject(taunt.AssetPathName.Text, out UObject export) ||
|
|
||||||
!export.TryGetValue(out FSoftObjectPath rewardThumbnail, "RewardThumbnail"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_availableTaunts.Add(Utils.GetBitmap(rewardThumbnail));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath[] skins, "Skins"))
|
|
||||||
{
|
|
||||||
foreach (var skin in skins)
|
|
||||||
{
|
|
||||||
if (!Utils.TryLoadObject(skin.AssetPathName.Text, out UObject export) ||
|
|
||||||
!export.TryGetValue(out FSoftObjectPath rewardThumbnail, "RewardThumbnail"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_skins.Add(Utils.GetBitmap(rewardThumbnail));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
|
||||||
{
|
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
||||||
using var c = new SKCanvas(ret);
|
|
||||||
|
|
||||||
DrawBackground(c);
|
|
||||||
DrawPreview(c);
|
|
||||||
DrawDisplayName(c);
|
|
||||||
DrawFighterInfo(c);
|
|
||||||
DrawRecommendedPerks(c);
|
|
||||||
DrawAvailableTaunts(c);
|
|
||||||
DrawSkins(c);
|
|
||||||
|
|
||||||
return new[] { ret };
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GetFighterClassInfo(EFighterClass clas)
|
|
||||||
{
|
|
||||||
if (!Utils.TryLoadObject("/Game/Panda_Main/UI/In-Game/Data/UICharacterClassInfo_Datatable.UICharacterClassInfo_Datatable", out UDataTable dataTable))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var row = dataTable.RowMap.ElementAt((int) clas).Value;
|
|
||||||
if (!row.TryGetValue(out FText displayName, "DisplayName_5_9DB5DDFF490E1F4AD72329866F96B81D") ||
|
|
||||||
!row.TryGetValue(out FPackageIndex icon, "Icon_8_711534AD4F240D4B001AA6A471EA1895"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_fighterType.Item1 = Utils.GetBitmap(icon);
|
|
||||||
_fighterType.Item2.Add(displayName.Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawBackground(SKCanvas c)
|
|
||||||
{
|
|
||||||
c.DrawRect(new SKRect(0, 0, Width, Height),
|
|
||||||
new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true, FilterQuality = SKFilterQuality.High, Color = Background[0]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(DisplayName))
|
|
||||||
{
|
|
||||||
c.DrawText(DisplayName, -50, 125, new()
|
|
||||||
{
|
|
||||||
IsAntialias = true, FilterQuality = SKFilterQuality.High,
|
|
||||||
Typeface = Utils.Typefaces.DisplayName, TextSize = 200,
|
|
||||||
TextScaleX = .95f, TextSkewX = -0.25f, Color = SKColors.Black.WithAlpha(25)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
c.DrawBitmap(_pattern, new SKRect(0, Height / 2, Width, Height), new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true, FilterQuality = SKFilterQuality.High, BlendMode = SKBlendMode.SoftLight
|
|
||||||
});
|
|
||||||
|
|
||||||
var path = new SKPath { FillType = SKPathFillType.EvenOdd };
|
|
||||||
path.MoveTo(0, Height);
|
|
||||||
path.LineTo(0, Height - 20);
|
|
||||||
path.LineTo(Width, Height - 60);
|
|
||||||
path.LineTo(Width, Height);
|
|
||||||
path.Close();
|
|
||||||
c.DrawPath(path, new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true,
|
|
||||||
FilterQuality = SKFilterQuality.High,
|
|
||||||
Color = SKColor.Parse("#141629")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawPreview(SKCanvas c)
|
|
||||||
{
|
|
||||||
var img = (Preview ?? DefaultPreview).ResizeWithRatio(_zoom);
|
|
||||||
var x_offset = img.Width * _xOffset;
|
|
||||||
var y_offset = img.Height * -_yOffset;
|
|
||||||
c.DrawBitmap(img, new SKRect(Width + x_offset - img.Width, y_offset, Width + x_offset, img.Height + y_offset), ImagePaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawDisplayName(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(DisplayName)) return;
|
|
||||||
c.DrawText(DisplayName.ToUpper(), 50, 100, DisplayNamePaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawFighterInfo(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (_fighterType.Item1 != null)
|
|
||||||
c.DrawBitmap(_fighterType.Item1, new SKRect(50, 112.5f, 98, 160.5f), ImagePaint);
|
|
||||||
|
|
||||||
c.DrawText(string.Join(" | ", _fighterType.Item2), 98, 145, DescriptionPaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawRecommendedPerks(SKCanvas c)
|
|
||||||
{
|
|
||||||
const int x = 50;
|
|
||||||
const int y = 200;
|
|
||||||
const int size = 64;
|
|
||||||
|
|
||||||
ImagePaint.ImageFilter = null;
|
|
||||||
ImagePaint.BlendMode = SKBlendMode.SoftLight;
|
|
||||||
c.DrawBitmap(_perk, new SKRect(x, y, x + size / 2, y + size / 2), ImagePaint);
|
|
||||||
if (_recommendedPerks.Count < 1) return;
|
|
||||||
|
|
||||||
ImagePaint.BlendMode = SKBlendMode.SrcOver;
|
|
||||||
ImagePaint.ImageFilter = SKImageFilter.CreateDropShadow(0, 0, 2.5f, 2.5f, SKColors.Black);
|
|
||||||
c.DrawBitmap(_recommendedPerks[1], new SKRect(161, y, 225, y + size), ImagePaint);
|
|
||||||
c.DrawBitmap(_recommendedPerks[2], new SKRect(193, y + size / 2, 257, y + size * 1.5f), ImagePaint);
|
|
||||||
c.DrawBitmap(_recommendedPerks[3], new SKRect(161, y + size, 225, y + size * 2), ImagePaint);
|
|
||||||
|
|
||||||
ImagePaint.ImageFilter = SKImageFilter.CreateDropShadow(0, 0, 5, 5, SKColors.Black.WithAlpha(150));
|
|
||||||
c.DrawBitmap(_recommendedPerks[0], new SKRect(x, y, x + size * 2, y + size * 2), ImagePaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawAvailableTaunts(SKCanvas c)
|
|
||||||
{
|
|
||||||
var x = 300;
|
|
||||||
const int y = 232;
|
|
||||||
const int size = 64;
|
|
||||||
|
|
||||||
ImagePaint.ImageFilter = null;
|
|
||||||
ImagePaint.BlendMode = SKBlendMode.SoftLight;
|
|
||||||
c.DrawBitmap(_emote, new SKRect(x, y - size / 2, x + size / 2, y), ImagePaint);
|
|
||||||
if (_availableTaunts.Count < 1) return;
|
|
||||||
|
|
||||||
ImagePaint.BlendMode = SKBlendMode.SrcOver;
|
|
||||||
ImagePaint.ImageFilter = SKImageFilter.CreateDropShadow(0, 0, 1.5f, 1.5f, SKColors.Black);
|
|
||||||
|
|
||||||
foreach (var taunt in _availableTaunts)
|
|
||||||
{
|
|
||||||
c.DrawBitmap(taunt, new SKRect(x, y, x + size, y + size), ImagePaint);
|
|
||||||
x += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawSkins(SKCanvas c)
|
|
||||||
{
|
|
||||||
var x = 50;
|
|
||||||
const int y = 333;
|
|
||||||
const int size = 128;
|
|
||||||
|
|
||||||
ImagePaint.ImageFilter = null;
|
|
||||||
ImagePaint.BlendMode = SKBlendMode.SoftLight;
|
|
||||||
c.DrawBitmap(_skin, new SKRect(x, y, x + size / 4, y + size / 4), ImagePaint);
|
|
||||||
if (_skins.Count < 1) return;
|
|
||||||
|
|
||||||
ImagePaint.BlendMode = SKBlendMode.SrcOver;
|
|
||||||
ImagePaint.ImageFilter = SKImageFilter.CreateDropShadow(0, 0, 1.5f, 1.5f, SKColors.Black);
|
|
||||||
foreach (var skin in _skins)
|
|
||||||
{
|
|
||||||
c.DrawBitmap(skin, new SKRect(x, y, x + size, y + size), ImagePaint);
|
|
||||||
x += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EFighterClass : byte
|
|
||||||
{
|
|
||||||
Mage = 4,
|
|
||||||
Tank = 3,
|
|
||||||
Fighter = 2,
|
|
||||||
Bruiser = 2,
|
|
||||||
Assassin = 1,
|
|
||||||
Support = 0 // Default
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EFighterType : byte
|
|
||||||
{
|
|
||||||
[Description("B980C82D40FF37FD359C74A339CE1B3A")]
|
|
||||||
Hybrid = 2,
|
|
||||||
|
|
||||||
[Description("2C55443D47164019BE73A5ABDC670F36")]
|
|
||||||
Vertical = 1,
|
|
||||||
|
|
||||||
[Description("97A60DD54AA23D4B93D5B891F729BF5C")]
|
|
||||||
Horizontal = 0 // Default
|
|
||||||
}
|
|
||||||
|
|
@ -1,344 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Engine;
|
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
|
||||||
using CUE4Parse.UE4.Objects.Core.Math;
|
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.MV;
|
|
||||||
|
|
||||||
public class BasePandaIcon : UCreator
|
|
||||||
{
|
|
||||||
private float _y_offset;
|
|
||||||
private ERewardRarity _rarity;
|
|
||||||
private string _type;
|
|
||||||
|
|
||||||
protected readonly List<(SKBitmap, string)> Pictos;
|
|
||||||
|
|
||||||
public BasePandaIcon(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
Width = 1024;
|
|
||||||
Margin = 30;
|
|
||||||
DisplayNamePaint.TextSize = 50;
|
|
||||||
DisplayNamePaint.TextAlign = SKTextAlign.Left;
|
|
||||||
DisplayNamePaint.Color = SKColor.Parse("#191C33");
|
|
||||||
DescriptionPaint.TextSize = 25;
|
|
||||||
DefaultPreview = Utils.GetBitmap("/Game/Panda_Main/UI/PreMatch/Images/DiamondPortraits/0010_Random.0010_Random");
|
|
||||||
|
|
||||||
_y_offset = Height / 2 + DescriptionPaint.TextSize;
|
|
||||||
Pictos = new List<(SKBitmap, string)>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
var category = Object.GetOrDefault("Category", EPerkCategory.Offense);
|
|
||||||
_rarity = Object.GetOrDefault("Rarity", ERewardRarity.None);
|
|
||||||
|
|
||||||
_type = Object.ExportType;
|
|
||||||
var t = _type switch // ERewardType like
|
|
||||||
{
|
|
||||||
"StatTrackingBundleData" => EItemType.Badge,
|
|
||||||
"AnnouncerPackData" => EItemType.Announcer,
|
|
||||||
"CharacterGiftData" => EItemType.ExperiencePoints,
|
|
||||||
"ProfileIconData" => EItemType.ProfileIcon,
|
|
||||||
"RingOutVfxData" => EItemType.Ringout,
|
|
||||||
"BannerData" => EItemType.Banner,
|
|
||||||
"EmoteData" => EItemType.Sticker,
|
|
||||||
"QuestData" => EItemType.Mission,
|
|
||||||
"TauntData" => EItemType.Emote,
|
|
||||||
"SkinData" => EItemType.Variant,
|
|
||||||
"PerkData" when category == EPerkCategory.CharacterSpecific => EItemType.SignaturePerk,
|
|
||||||
"PerkData" => EItemType.Perk,
|
|
||||||
_ => EItemType.Unknown
|
|
||||||
};
|
|
||||||
|
|
||||||
if (t == EItemType.SignaturePerk) _rarity = ERewardRarity.Legendary;
|
|
||||||
Background = GetRarityBackground(_rarity);
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath rewardThumbnail, "RewardThumbnail", "DisplayTextureRef", "Texture"))
|
|
||||||
Preview = Utils.GetBitmap(rewardThumbnail);
|
|
||||||
else if (Object.TryGetValue(out FPackageIndex icon, "Icon"))
|
|
||||||
Preview = Utils.GetBitmap(icon);
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "QuestName"))
|
|
||||||
DisplayName = displayName.Text;
|
|
||||||
if (Object.TryGetValue(out FText description, "Description", "QuestDescription"))
|
|
||||||
Description = Utils.RemoveHtmlTags(description.Text);
|
|
||||||
|
|
||||||
var unlockLocation = Object.GetOrDefault("UnlockLocation", EUnlockLocation.None);
|
|
||||||
if (t == EItemType.Unknown && unlockLocation == EUnlockLocation.CharacterMastery) t = EItemType.MasteryLevel;
|
|
||||||
|
|
||||||
Pictos.Add((Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_unlocked.ui_icons_unlocked"), Utils.GetLocalizedResource(unlockLocation)));
|
|
||||||
if (Object.TryGetValue(out string slug, "Slug"))
|
|
||||||
{
|
|
||||||
t = _type switch
|
|
||||||
{
|
|
||||||
"HydraSyncedDataAsset" when slug == "gold" => EItemType.Gold,
|
|
||||||
"HydraSyncedDataAsset" when slug == "gleamium" => EItemType.Gleamium,
|
|
||||||
"HydraSyncedDataAsset" when slug == "match_toasts" => EItemType.Toast,
|
|
||||||
_ => t
|
|
||||||
};
|
|
||||||
Pictos.Add((Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_link.ui_icons_link"), slug));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Object.TryGetValue(out int xpValue, "XPValue"))
|
|
||||||
DisplayName += $" (+{xpValue})";
|
|
||||||
|
|
||||||
if (Utils.TryLoadObject("/Game/Panda_Main/UI/Prototype/Foundation/Types/DT_EconomyGlossary.DT_EconomyGlossary", out UDataTable dataTable))
|
|
||||||
{
|
|
||||||
if (t != EItemType.Unknown &&
|
|
||||||
dataTable.RowMap.ElementAt((int) t).Value.TryGetValue(out FText name, "Name_14_7F75AD6047CBDEA7B252B1BD76EF84B9"))
|
|
||||||
_type = name.Text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
|
||||||
{
|
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
||||||
using var c = new SKCanvas(ret);
|
|
||||||
|
|
||||||
DrawBackground(c);
|
|
||||||
DrawPreview(c);
|
|
||||||
DrawDisplayName(c);
|
|
||||||
DrawDescription(c);
|
|
||||||
DrawPictos(c);
|
|
||||||
|
|
||||||
return new[] { ret };
|
|
||||||
}
|
|
||||||
|
|
||||||
private SKColor[] GetRarityBackground(ERewardRarity rarity)
|
|
||||||
{
|
|
||||||
return rarity switch // the colors here are the base color and brighter color that the game uses for rarities from the "Rarity to Color" blueprint function
|
|
||||||
{
|
|
||||||
ERewardRarity.Common => new[]
|
|
||||||
{
|
|
||||||
SKColor.Parse(new FLinearColor(0.068478f, 0.651406f, 0.016807f, 1.000000f).Hex),
|
|
||||||
SKColor.Parse(new FLinearColor(0.081422f, 1.000000f, 0.000000f, 1.000000f).Hex)
|
|
||||||
},
|
|
||||||
ERewardRarity.Rare => new[]
|
|
||||||
{
|
|
||||||
SKColor.Parse(new FLinearColor(0.035911f, 0.394246f, 0.900000f, 1.000000f).Hex),
|
|
||||||
SKColor.Parse(new FLinearColor(0.033333f, 0.434207f, 1.000000f, 1.000000f).Hex)
|
|
||||||
},
|
|
||||||
ERewardRarity.Epic => new[]
|
|
||||||
{
|
|
||||||
SKColor.Parse(new FLinearColor(0.530391f, 0.060502f, 0.900000f, 1.000000f).Hex),
|
|
||||||
SKColor.Parse(new FLinearColor(0.579907f, 0.045833f, 1.000000f, 1.000000f).Hex)
|
|
||||||
},
|
|
||||||
ERewardRarity.Legendary => new[]
|
|
||||||
{
|
|
||||||
SKColor.Parse(new FLinearColor(1.000000f, 0.223228f, 0.002428f, 1.000000f).Hex),
|
|
||||||
SKColor.Parse(new FLinearColor(1.000000f, 0.479320f, 0.030713f, 1.000000f).Hex)
|
|
||||||
},
|
|
||||||
_ => new[]
|
|
||||||
{
|
|
||||||
SKColor.Parse(new FLinearColor(0.194618f, 0.651406f, 0.630757f, 1.000000f).Hex),
|
|
||||||
SKColor.Parse(new FLinearColor(0.273627f, 0.955208f, 0.914839f, 1.000000f).Hex)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawBackground(SKCanvas c)
|
|
||||||
{
|
|
||||||
c.DrawRect(new SKRect(0, 0, Width, Height),
|
|
||||||
new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true, FilterQuality = SKFilterQuality.High, Color = SKColor.Parse("#F3FCF0")
|
|
||||||
});
|
|
||||||
|
|
||||||
var has_tr = _rarity != ERewardRarity.None;
|
|
||||||
var tr = Utils.GetLocalizedResource(_rarity);
|
|
||||||
var tr_paint = new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true,
|
|
||||||
FilterQuality = SKFilterQuality.High,
|
|
||||||
TextAlign = SKTextAlign.Right,
|
|
||||||
TextSize = 35,
|
|
||||||
Color = SKColors.White,
|
|
||||||
Typeface = Utils.Typefaces.DisplayName
|
|
||||||
};
|
|
||||||
|
|
||||||
var path = new SKPath { FillType = SKPathFillType.EvenOdd };
|
|
||||||
path.MoveTo(0, Height);
|
|
||||||
path.LineTo(14, Height);
|
|
||||||
path.LineTo(20, 20);
|
|
||||||
if (has_tr)
|
|
||||||
{
|
|
||||||
const int margin = 15;
|
|
||||||
var width = tr_paint.MeasureText(tr);
|
|
||||||
path.LineTo(Width - width - margin * 2, 15);
|
|
||||||
path.LineTo(Width - width - margin * 2.5f, 60);
|
|
||||||
path.LineTo(Width, 55);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
path.LineTo(Width, 14);
|
|
||||||
}
|
|
||||||
path.LineTo(Width, 0);
|
|
||||||
path.LineTo(0, 0);
|
|
||||||
path.LineTo(0, Height);
|
|
||||||
path.Close();
|
|
||||||
c.DrawPath(path, new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true,
|
|
||||||
FilterQuality = SKFilterQuality.High,
|
|
||||||
Shader = SKShader.CreateLinearGradient(
|
|
||||||
new SKPoint(Width / 2, Height), new SKPoint(Width, Height / 4), Background, SKShaderTileMode.Clamp)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (has_tr)
|
|
||||||
{
|
|
||||||
var x = Width - 20f;
|
|
||||||
foreach (var a in tr.Select(character => character.ToString()).Reverse())
|
|
||||||
{
|
|
||||||
c.DrawText(a, x, 40, tr_paint);
|
|
||||||
x -= tr_paint.MeasureText(a) - 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawPreview(SKCanvas c)
|
|
||||||
{
|
|
||||||
const int size = 384;
|
|
||||||
var y = Height - size - Margin * 2;
|
|
||||||
c.DrawBitmap(Preview ?? DefaultPreview, new SKRect(Margin, y, size + Margin, y + size), ImagePaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawDisplayName(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(DisplayName))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var x = 450f;
|
|
||||||
while (DisplayNamePaint.MeasureText(DisplayName) > Width - x / 1.25)
|
|
||||||
{
|
|
||||||
DisplayNamePaint.TextSize -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var y = Height / 2 - DisplayNamePaint.TextSize / 4;
|
|
||||||
foreach (var a in DisplayName.Select(character => character.ToString()))
|
|
||||||
{
|
|
||||||
c.DrawText(a, x, y, DisplayNamePaint);
|
|
||||||
x += DisplayNamePaint.MeasureText(a) - 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private new void DrawDescription(SKCanvas c)
|
|
||||||
{
|
|
||||||
const int x = 450;
|
|
||||||
DescriptionPaint.Color = Background[0];
|
|
||||||
c.DrawText(_type.ToUpper(), x, 170, DescriptionPaint);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(Description)) return;
|
|
||||||
|
|
||||||
DescriptionPaint.Color = SKColor.Parse("#191C33");
|
|
||||||
Utils.DrawMultilineText(c, Description, Width - x, Margin, SKTextAlign.Left,
|
|
||||||
new SKRect(x, _y_offset, Width - Margin, Height - Margin), DescriptionPaint, out _y_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawPictos(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (Pictos.Count < 1) return;
|
|
||||||
|
|
||||||
const float x = 450f;
|
|
||||||
const int size = 24;
|
|
||||||
var color = SKColor.Parse("#495B6E");
|
|
||||||
var paint = new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true,
|
|
||||||
FilterQuality = SKFilterQuality.High,
|
|
||||||
TextSize = 27,
|
|
||||||
Color = color,
|
|
||||||
Typeface = Utils.Typefaces.Default
|
|
||||||
};
|
|
||||||
|
|
||||||
ImagePaint.ColorFilter = SKColorFilter.CreateBlendMode(color, SKBlendMode.SrcIn);
|
|
||||||
|
|
||||||
foreach (var picto in Pictos)
|
|
||||||
{
|
|
||||||
c.DrawBitmap(picto.Item1, new SKRect(x, _y_offset + 10, x + size, _y_offset + 10 + size), ImagePaint);
|
|
||||||
c.DrawText(picto.Item2, x + size + 10, _y_offset + size + 6, paint);
|
|
||||||
_y_offset += size + 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ERewardRarity : byte
|
|
||||||
{
|
|
||||||
[Description("0D4B15CE4FB6F2BC5E5F5FAA9E8B376C")]
|
|
||||||
None = 0, // Default
|
|
||||||
|
|
||||||
[Description("0FCDEF47485E2C3D0D477988C481D8E3")]
|
|
||||||
Common = 1,
|
|
||||||
|
|
||||||
[Description("18241CA7441AE16AAFB6EFAB499FF981")]
|
|
||||||
Rare = 2,
|
|
||||||
|
|
||||||
[Description("D999D9CB4754D1078BF9A1B34A231005")]
|
|
||||||
Epic = 3,
|
|
||||||
|
|
||||||
[Description("705AE967407D6EF8870E988A08C6900E")]
|
|
||||||
Legendary = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EUnlockLocation : byte
|
|
||||||
{
|
|
||||||
[Description("0D4B15CE4FB6F2BC5E5F5FAA9E8B376C")]
|
|
||||||
None = 0, // Default
|
|
||||||
|
|
||||||
[Description("0AFBCE5F41D930D6E9B5138C8EBCFE87")]
|
|
||||||
Shop = 1,
|
|
||||||
|
|
||||||
[Description("062F178B4EE74502C9AD9D878F3D7CEA")]
|
|
||||||
AccountLevel = 2,
|
|
||||||
|
|
||||||
[Description("1AE7A5DF477B2B5F4B3CCC8DCD732884")]
|
|
||||||
CharacterMastery = 3,
|
|
||||||
|
|
||||||
[Description("0B37731C49DC9AE1EAC566950C1A329D")]
|
|
||||||
Battlepass = 4,
|
|
||||||
|
|
||||||
[Description("16F160084187479E5D471786190AE5B7")]
|
|
||||||
CharacterAffinity = 5,
|
|
||||||
|
|
||||||
[Description("E5C1E35C406C585E83B5D18A817FA0B4")]
|
|
||||||
GuildBoss = 6,
|
|
||||||
|
|
||||||
[Description("4A89F5DD432113750EF52D8B58977DCE")]
|
|
||||||
Tutorial = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EPerkCategory : byte
|
|
||||||
{
|
|
||||||
Offense = 0, // Default
|
|
||||||
Defense = 1,
|
|
||||||
Utility = 2,
|
|
||||||
CharacterSpecific = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EItemType
|
|
||||||
{
|
|
||||||
Unknown = -1,
|
|
||||||
Announcer,
|
|
||||||
Badge,
|
|
||||||
Banner,
|
|
||||||
BattlePassPoints,
|
|
||||||
Emote,
|
|
||||||
ExperiencePoints,
|
|
||||||
Gleamium,
|
|
||||||
Gold,
|
|
||||||
MasteryLevel,
|
|
||||||
Mission,
|
|
||||||
Perk,
|
|
||||||
PlayerLevel,
|
|
||||||
ProfileIcon,
|
|
||||||
Rested,
|
|
||||||
Ringout,
|
|
||||||
SignaturePerk,
|
|
||||||
Sticker,
|
|
||||||
Toast,
|
|
||||||
Variant
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.MV;
|
|
||||||
|
|
||||||
public class BasePerkGroup : UCreator
|
|
||||||
{
|
|
||||||
private readonly List<BasePandaIcon> _perks;
|
|
||||||
|
|
||||||
public BasePerkGroup(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
_perks = new List<BasePandaIcon>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
if (Object.TryGetValue(out UScriptSet perks, "Perks")) // PORCO DIO WB USE ARRAYS!!!!!!
|
|
||||||
{
|
|
||||||
foreach (var perk in perks.Properties)
|
|
||||||
{
|
|
||||||
if (perk.GenericValue is not FPackageIndex packageIndex ||
|
|
||||||
!Utils.TryGetPackageIndexExport(packageIndex, out UObject export))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var icon = new BasePandaIcon(export, Style);
|
|
||||||
icon.ParseForInfo();
|
|
||||||
_perks.Add(icon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
|
||||||
{
|
|
||||||
var ret = new SKBitmap[_perks.Count];
|
|
||||||
for (var i = 0; i < ret.Length; i++)
|
|
||||||
{
|
|
||||||
ret[i] = _perks[i].Draw()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using FModel.Extensions;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.MV;
|
|
||||||
|
|
||||||
public class BaseQuest : BasePandaIcon
|
|
||||||
{
|
|
||||||
public BaseQuest(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
if (Object.TryGetValue(out FStructFallback[] questCompletionRewards, "QuestCompletionRewards") &&
|
|
||||||
questCompletionRewards.Length > 0 && questCompletionRewards[0] is { } actualReward)
|
|
||||||
{
|
|
||||||
var rewardType = actualReward.GetOrDefault("RewardType", EQuestRewardType.Inventory);
|
|
||||||
var count = actualReward.GetOrDefault("Count", 0);
|
|
||||||
Pictos.Add((Utils.GetBitmap("/Game/Panda_Main/UI/Assets/Icons/ui_icons_plus.ui_icons_plus"), count.ToString()));
|
|
||||||
|
|
||||||
base.ParseForInfo();
|
|
||||||
|
|
||||||
if (actualReward.TryGetValue(out FPackageIndex assetReward, "AssetReward") &&
|
|
||||||
Utils.TryGetPackageIndexExport(assetReward, out UObject export))
|
|
||||||
{
|
|
||||||
var item = new BasePandaIcon(export, Style);
|
|
||||||
item.ParseForInfo();
|
|
||||||
Preview = item.Preview;
|
|
||||||
}
|
|
||||||
else if (rewardType != EQuestRewardType.Inventory)
|
|
||||||
{
|
|
||||||
Preview = Utils.GetBitmap(rewardType.GetDescription());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base.ParseForInfo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EQuestRewardType : byte
|
|
||||||
{
|
|
||||||
Inventory = 0, // Default
|
|
||||||
|
|
||||||
[Description("/Game/Panda_Main/UI/Assets/Icons/UI_CharacterTicket.UI_CharacterTicket")]
|
|
||||||
AccountXP = 1,
|
|
||||||
|
|
||||||
[Description("/Game/Panda_Main/UI/Assets/Icons/UI_BattlepassToken.UI_BattlepassToken")]
|
|
||||||
BattlepassXP = 2
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
using CUE4Parse.UE4.Objects.Core.Math;
|
using CUE4Parse.UE4.Objects.Core.Math;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.SB;
|
namespace FModel.Creator.Bases.SB
|
||||||
|
{
|
||||||
public class BaseDivision : UCreator
|
public class BaseDivision : UCreator
|
||||||
{
|
{
|
||||||
public BaseDivision(UObject uObject, EIconStyle style) : base(uObject, style)
|
public BaseDivision(UObject uObject, EIconStyle style) : base(uObject, style)
|
||||||
|
|
@ -32,9 +32,9 @@ public class BaseDivision : UCreator
|
||||||
DisplayName = displayName.Text;
|
DisplayName = displayName.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawBackground(c);
|
DrawBackground(c);
|
||||||
|
|
@ -42,6 +42,7 @@ public class BaseDivision : UCreator
|
||||||
DrawTextBackground(c);
|
DrawTextBackground(c);
|
||||||
DrawDisplayName(c);
|
DrawDisplayName(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
|
||||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
|
||||||
using CUE4Parse.UE4.Objects.Core.i18N;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.SB;
|
|
||||||
|
|
||||||
public class BaseGameModeInfo : UCreator
|
|
||||||
{
|
|
||||||
private SKBitmap _icon;
|
|
||||||
|
|
||||||
public BaseGameModeInfo(UObject uObject, EIconStyle style) : base(uObject, style)
|
|
||||||
{
|
|
||||||
Width = 738;
|
|
||||||
Height = 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ParseForInfo()
|
|
||||||
{
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName"))
|
|
||||||
DisplayName = displayName.Text;
|
|
||||||
if (Object.TryGetValue(out FText description, "Description"))
|
|
||||||
Description = description.Text;
|
|
||||||
if (Object.TryGetValue(out UMaterialInstanceConstant portrait, "Portrait"))
|
|
||||||
Preview = Utils.GetBitmap(portrait);
|
|
||||||
if (Object.TryGetValue(out UTexture2D icon, "Icon"))
|
|
||||||
_icon = Utils.GetBitmap(icon).Resize(25);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
|
||||||
{
|
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
||||||
using var c = new SKCanvas(ret);
|
|
||||||
|
|
||||||
DrawPreview(c);
|
|
||||||
DrawTextBackground(c);
|
|
||||||
DrawDisplayName(c);
|
|
||||||
DrawIcon(c);
|
|
||||||
|
|
||||||
return new[] { ret };
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawIcon(SKCanvas c)
|
|
||||||
{
|
|
||||||
if (_icon == null) return;
|
|
||||||
c.DrawBitmap(_icon, new SKPoint(5, 5), ImagePaint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,8 +3,8 @@ using CUE4Parse.UE4.Objects.Core.i18N;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.SB;
|
namespace FModel.Creator.Bases.SB
|
||||||
|
{
|
||||||
public class BaseLeague : UCreator
|
public class BaseLeague : UCreator
|
||||||
{
|
{
|
||||||
private int _promotionXp, _xpLostPerMatch;
|
private int _promotionXp, _xpLostPerMatch;
|
||||||
|
|
@ -36,9 +36,9 @@ public class BaseLeague : UCreator
|
||||||
DisplayName = displayName.Text;
|
DisplayName = displayName.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawBackground(c);
|
DrawBackground(c);
|
||||||
|
|
@ -49,6 +49,7 @@ public class BaseLeague : UCreator
|
||||||
DrawToBottom(c, SKTextAlign.Left, $"PromotionXP: {_promotionXp}");
|
DrawToBottom(c, SKTextAlign.Left, $"PromotionXP: {_promotionXp}");
|
||||||
DrawToBottom(c, SKTextAlign.Right, $"XPLostPerMatch: {_xpLostPerMatch}");
|
DrawToBottom(c, SKTextAlign.Right, $"XPLostPerMatch: {_xpLostPerMatch}");
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,8 +7,8 @@ using CUE4Parse.UE4.Objects.UObject;
|
||||||
using FModel.Creator.Bases.FN;
|
using FModel.Creator.Bases.FN;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases.SB;
|
namespace FModel.Creator.Bases.SB
|
||||||
|
{
|
||||||
public class BaseSpellIcon : BaseIcon
|
public class BaseSpellIcon : BaseIcon
|
||||||
{
|
{
|
||||||
private SKBitmap _seriesBackground2;
|
private SKBitmap _seriesBackground2;
|
||||||
|
|
@ -24,8 +24,8 @@ public class BaseSpellIcon : BaseIcon
|
||||||
{
|
{
|
||||||
Background = new[] {SKColor.Parse("FFFFFF"), SKColor.Parse("636363")};
|
Background = new[] {SKColor.Parse("FFFFFF"), SKColor.Parse("636363")};
|
||||||
Border = new[] {SKColor.Parse("D0D0D0"), SKColor.Parse("FFFFFF")};
|
Border = new[] {SKColor.Parse("D0D0D0"), SKColor.Parse("FFFFFF")};
|
||||||
Width = Object.ExportType.StartsWith("GCosmeticCard") ? 1536 : 512;
|
Width = Object.ExportType.StartsWith("BP_Cosmetic_Card") ? 1536 : 512;
|
||||||
Height = Object.ExportType.StartsWith("GCosmeticCard") ? 450 : 512;
|
Height = Object.ExportType.StartsWith("BP_Cosmetic_Card") ? 450 : 512;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ParseForInfo()
|
public override void ParseForInfo()
|
||||||
|
|
@ -33,12 +33,12 @@ public class BaseSpellIcon : BaseIcon
|
||||||
if (Object.TryGetValue(out FName rarity, "Rarity"))
|
if (Object.TryGetValue(out FName rarity, "Rarity"))
|
||||||
GetRarity(rarity);
|
GetRarity(rarity);
|
||||||
|
|
||||||
if (Object.TryGetValue(out FSoftObjectPath preview, "IconTexture", "OfferTexture", "PortraitTexture"))
|
if (Object.TryGetValue(out FSoftObjectPath preview, "IconTexture"))
|
||||||
Preview = Utils.GetBitmap(preview);
|
Preview = Utils.GetBitmap(preview);
|
||||||
else if (Object.TryGetValue(out FPackageIndex icon, "IconTexture", "OfferTexture", "PortraitTexture"))
|
else if (Object.TryGetValue(out FPackageIndex icon, "IconTexture"))
|
||||||
Preview = Utils.GetBitmap(icon);
|
Preview = Utils.GetBitmap(icon);
|
||||||
|
|
||||||
if (Object.TryGetValue(out FText displayName, "DisplayName", "Title", "Name"))
|
if (Object.TryGetValue(out FText displayName, "DisplayName", "Title"))
|
||||||
DisplayName = displayName.Text;
|
DisplayName = displayName.Text;
|
||||||
if (Object.TryGetValue(out FText description, "Description"))
|
if (Object.TryGetValue(out FText description, "Description"))
|
||||||
Description = description.Text;
|
Description = description.Text;
|
||||||
|
|
@ -47,9 +47,9 @@ public class BaseSpellIcon : BaseIcon
|
||||||
_seriesBackground2 = Utils.GetBitmap("g3/Content/UI/Textures/assets/store/ItemBGStatic_UIT.ItemBGStatic_UIT");
|
_seriesBackground2 = Utils.GetBitmap("g3/Content/UI/Textures/assets/store/ItemBGStatic_UIT.ItemBGStatic_UIT");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SKBitmap[] Draw()
|
public override SKImage Draw()
|
||||||
{
|
{
|
||||||
var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
using var ret = new SKBitmap(Width, Height, SKColorType.Rgba8888, SKAlphaType.Premul);
|
||||||
using var c = new SKCanvas(ret);
|
using var c = new SKCanvas(ret);
|
||||||
|
|
||||||
DrawBackgrounds(c);
|
DrawBackgrounds(c);
|
||||||
|
|
@ -59,7 +59,7 @@ public class BaseSpellIcon : BaseIcon
|
||||||
DrawDisplayName(c);
|
DrawDisplayName(c);
|
||||||
DrawDescription(c);
|
DrawDescription(c);
|
||||||
|
|
||||||
return new[] { ret };
|
return SKImage.FromBitmap(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawBackgrounds(SKCanvas c)
|
private void DrawBackgrounds(SKCanvas c)
|
||||||
|
|
@ -95,3 +95,4 @@ public class BaseSpellIcon : BaseIcon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using FModel.Creator.Bases.FN;
|
using FModel.Creator.Bases.FN;
|
||||||
|
|
@ -6,8 +6,8 @@ using FModel.Framework;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator.Bases;
|
namespace FModel.Creator.Bases
|
||||||
|
{
|
||||||
public abstract class UCreator
|
public abstract class UCreator
|
||||||
{
|
{
|
||||||
protected UObject Object { get; }
|
protected UObject Object { get; }
|
||||||
|
|
@ -23,7 +23,7 @@ public abstract class UCreator
|
||||||
public int Height { get; protected set; }
|
public int Height { get; protected set; }
|
||||||
|
|
||||||
public abstract void ParseForInfo();
|
public abstract void ParseForInfo();
|
||||||
public abstract SKBitmap[] Draw();
|
public abstract SKImage Draw();
|
||||||
|
|
||||||
protected UCreator(UObject uObject, EIconStyle style)
|
protected UCreator(UObject uObject, EIconStyle style)
|
||||||
{
|
{
|
||||||
|
|
@ -166,7 +166,7 @@ public abstract class UCreator
|
||||||
|
|
||||||
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
var shaper = new CustomSKShaper(DisplayNamePaint.Typeface);
|
||||||
var shapedText = shaper.Shape(DisplayName, DisplayNamePaint);
|
var shapedText = shaper.Shape(DisplayName, DisplayNamePaint);
|
||||||
var x = Width / 2f;
|
var x = (Width - shapedText.Points[^1].X) / 2;
|
||||||
var y = _STARTER_TEXT_POSITION + _NAME_TEXT_SIZE;
|
var y = _STARTER_TEXT_POSITION + _NAME_TEXT_SIZE;
|
||||||
|
|
||||||
switch (Style)
|
switch (Style)
|
||||||
|
|
@ -174,15 +174,14 @@ public abstract class UCreator
|
||||||
case EIconStyle.Flat:
|
case EIconStyle.Flat:
|
||||||
{
|
{
|
||||||
DisplayNamePaint.TextAlign = SKTextAlign.Right;
|
DisplayNamePaint.TextAlign = SKTextAlign.Right;
|
||||||
x = Width - Margin * 2;
|
x = Width - Margin * 2 - shapedText.Points[^1].X;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
var halfWidth = shapedText.Width / 2f;
|
c.DrawLine(x, 0, x, Width, new SKPaint {Color = SKColors.Blue, IsStroke = true});
|
||||||
c.DrawLine(x - halfWidth, 0, x - halfWidth, Width, new SKPaint { Color = SKColors.Blue, IsStroke = true });
|
c.DrawLine(x + shapedText.Points[^1].X, 0, x + shapedText.Points[^1].X, Width, new SKPaint {Color = SKColors.Blue, IsStroke = true});
|
||||||
c.DrawLine(x + halfWidth, 0, x + halfWidth, Width, new SKPaint { Color = SKColors.Blue, IsStroke = true });
|
|
||||||
c.DrawRect(new SKRect(Margin, _STARTER_TEXT_POSITION, Width - Margin, y), new SKPaint {Color = SKColors.Blue, IsStroke = true});
|
c.DrawRect(new SKRect(Margin, _STARTER_TEXT_POSITION, Width - Margin, y), new SKPaint {Color = SKColors.Blue, IsStroke = true});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -217,6 +216,8 @@ public abstract class UCreator
|
||||||
case SKTextAlign.Left:
|
case SKTextAlign.Left:
|
||||||
_shortDescriptionPaint.Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.DisplayName;
|
_shortDescriptionPaint.Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.DisplayName;
|
||||||
var shaper = new CustomSKShaper(_shortDescriptionPaint.Typeface);
|
var shaper = new CustomSKShaper(_shortDescriptionPaint.Typeface);
|
||||||
|
shaper.Shape(text, _shortDescriptionPaint);
|
||||||
|
|
||||||
c.DrawShapedText(shaper, text, Margin * 2.5f, Width - Margin * 2.5f, _shortDescriptionPaint);
|
c.DrawShapedText(shaper, text, Margin * 2.5f, Width - Margin * 2.5f, _shortDescriptionPaint);
|
||||||
break;
|
break;
|
||||||
case SKTextAlign.Right:
|
case SKTextAlign.Right:
|
||||||
|
|
@ -226,3 +227,4 @@ public abstract class UCreator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,11 +4,10 @@ using CUE4Parse.UE4.Assets.Exports;
|
||||||
using FModel.Creator.Bases;
|
using FModel.Creator.Bases;
|
||||||
using FModel.Creator.Bases.BB;
|
using FModel.Creator.Bases.BB;
|
||||||
using FModel.Creator.Bases.FN;
|
using FModel.Creator.Bases.FN;
|
||||||
using FModel.Creator.Bases.MV;
|
|
||||||
using FModel.Creator.Bases.SB;
|
using FModel.Creator.Bases.SB;
|
||||||
|
|
||||||
namespace FModel.Creator;
|
namespace FModel.Creator
|
||||||
|
{
|
||||||
public class CreatorPackage : IDisposable
|
public class CreatorPackage : IDisposable
|
||||||
{
|
{
|
||||||
private UObject _object;
|
private UObject _object;
|
||||||
|
|
@ -33,7 +32,6 @@ public class CreatorPackage : IDisposable
|
||||||
switch (_object.ExportType)
|
switch (_object.ExportType)
|
||||||
{
|
{
|
||||||
// Fortnite
|
// Fortnite
|
||||||
case "FortCreativeWeaponMeleeItemDefinition":
|
|
||||||
case "AthenaConsumableEmoteItemDefinition":
|
case "AthenaConsumableEmoteItemDefinition":
|
||||||
case "AthenaSkyDiveContrailItemDefinition":
|
case "AthenaSkyDiveContrailItemDefinition":
|
||||||
case "AthenaLoadingScreenItemDefinition":
|
case "AthenaLoadingScreenItemDefinition":
|
||||||
|
|
@ -57,7 +55,6 @@ public class CreatorPackage : IDisposable
|
||||||
case "FortAbilityKit":
|
case "FortAbilityKit":
|
||||||
case "FortWorkerType":
|
case "FortWorkerType":
|
||||||
case "RewardGraphToken":
|
case "RewardGraphToken":
|
||||||
case "JunoKnowledgeBundle":
|
|
||||||
case "FortBannerTokenType":
|
case "FortBannerTokenType":
|
||||||
case "FortVariantTokenType":
|
case "FortVariantTokenType":
|
||||||
case "FortDecoItemDefinition":
|
case "FortDecoItemDefinition":
|
||||||
|
|
@ -65,101 +62,55 @@ public class CreatorPackage : IDisposable
|
||||||
case "FortAmmoItemDefinition":
|
case "FortAmmoItemDefinition":
|
||||||
case "FortEmoteItemDefinition":
|
case "FortEmoteItemDefinition":
|
||||||
case "FortBadgeItemDefinition":
|
case "FortBadgeItemDefinition":
|
||||||
case "SparksMicItemDefinition":
|
|
||||||
case "FortAwardItemDefinition":
|
case "FortAwardItemDefinition":
|
||||||
case "FortStackItemDefinition":
|
|
||||||
case "FortWorldItemDefinition":
|
|
||||||
case "SparksAuraItemDefinition":
|
|
||||||
case "SparksDrumItemDefinition":
|
|
||||||
case "SparksBassItemDefinition":
|
|
||||||
case "FortGadgetItemDefinition":
|
case "FortGadgetItemDefinition":
|
||||||
case "AthenaCharmItemDefinition":
|
|
||||||
case "FortPlaysetItemDefinition":
|
case "FortPlaysetItemDefinition":
|
||||||
case "FortGiftBoxItemDefinition":
|
case "FortGiftBoxItemDefinition":
|
||||||
case "FortOutpostItemDefinition":
|
case "FortOutpostItemDefinition":
|
||||||
case "FortVehicleItemDefinition":
|
case "FortVehicleItemDefinition":
|
||||||
case "FortMissionItemDefinition":
|
|
||||||
case "FortAccountItemDefinition":
|
|
||||||
case "SparksGuitarItemDefinition":
|
|
||||||
case "FortCardPackItemDefinition":
|
case "FortCardPackItemDefinition":
|
||||||
case "FortDefenderItemDefinition":
|
case "FortDefenderItemDefinition":
|
||||||
case "FortCurrencyItemDefinition":
|
case "FortCurrencyItemDefinition":
|
||||||
case "FortResourceItemDefinition":
|
case "FortResourceItemDefinition":
|
||||||
case "FortBackpackItemDefinition":
|
case "FortBackpackItemDefinition":
|
||||||
case "FortEventQuestMapDataAsset":
|
|
||||||
case "FortBuildingItemDefinition":
|
|
||||||
case "FortWeaponModItemDefinition":
|
|
||||||
case "FortCodeTokenItemDefinition":
|
case "FortCodeTokenItemDefinition":
|
||||||
case "FortSchematicItemDefinition":
|
case "FortSchematicItemDefinition":
|
||||||
case "FortAlterableItemDefinition":
|
|
||||||
case "SparksKeyboardItemDefinition":
|
|
||||||
case "FortWorldMultiItemDefinition":
|
case "FortWorldMultiItemDefinition":
|
||||||
case "FortAlterationItemDefinition":
|
case "FortAlterationItemDefinition":
|
||||||
case "FortExpeditionItemDefinition":
|
case "FortExpeditionItemDefinition":
|
||||||
case "FortIngredientItemDefinition":
|
case "FortIngredientItemDefinition":
|
||||||
case "FortConsumableItemDefinition":
|
|
||||||
case "StWFortAccoladeItemDefinition":
|
|
||||||
case "FortAccountBuffItemDefinition":
|
case "FortAccountBuffItemDefinition":
|
||||||
case "FortWeaponMeleeItemDefinition":
|
case "FortWeaponMeleeItemDefinition":
|
||||||
case "FortPlayerPerksItemDefinition":
|
case "FortPlayerPerksItemDefinition":
|
||||||
case "FortPlaysetPropItemDefinition":
|
case "FortPlaysetPropItemDefinition":
|
||||||
case "FortPrerollDataItemDefinition":
|
|
||||||
case "JunoRecipeBundleItemDefinition":
|
|
||||||
case "FortHomebaseNodeItemDefinition":
|
case "FortHomebaseNodeItemDefinition":
|
||||||
case "FortNeverPersistItemDefinition":
|
case "FortNeverPersistItemDefinition":
|
||||||
case "FortPlayerAugmentItemDefinition":
|
|
||||||
case "FortSmartBuildingItemDefinition":
|
|
||||||
case "FortGiftBoxUnlockItemDefinition":
|
|
||||||
case "FortWeaponModItemDefinitionOptic":
|
|
||||||
case "RadioContentSourceItemDefinition":
|
case "RadioContentSourceItemDefinition":
|
||||||
case "FortPlaysetGrenadeItemDefinition":
|
case "FortPlaysetGrenadeItemDefinition":
|
||||||
case "JunoWeaponCreatureItemDefinition":
|
|
||||||
case "FortEventDependentItemDefinition":
|
|
||||||
case "FortPersonalVehicleItemDefinition":
|
case "FortPersonalVehicleItemDefinition":
|
||||||
case "FortGameplayModifierItemDefinition":
|
case "FortGameplayModifierItemDefinition":
|
||||||
case "FortHardcoreModifierItemDefinition":
|
case "FortHardcoreModifierItemDefinition":
|
||||||
case "FortWeaponModItemDefinitionMagazine":
|
|
||||||
case "FortConsumableAccountItemDefinition":
|
case "FortConsumableAccountItemDefinition":
|
||||||
case "FortConversionControlItemDefinition":
|
case "FortConversionControlItemDefinition":
|
||||||
case "FortAccountBuffCreditItemDefinition":
|
case "FortAccountBuffCreditItemDefinition":
|
||||||
case "JunoBuildInstructionsItemDefinition":
|
|
||||||
case "FortCharacterCosmeticItemDefinition":
|
|
||||||
case "JunoBuildingSetAccountItemDefinition":
|
|
||||||
case "FortEventCurrencyItemDefinitionRedir":
|
case "FortEventCurrencyItemDefinitionRedir":
|
||||||
case "FortPersistentResourceItemDefinition":
|
case "FortPersistentResourceItemDefinition":
|
||||||
case "FortWeaponMeleeOffhandItemDefinition":
|
|
||||||
case "FortHomebaseBannerIconItemDefinition":
|
case "FortHomebaseBannerIconItemDefinition":
|
||||||
case "FortVehicleCosmeticsVariantTokenType":
|
|
||||||
case "JunoBuildingPropAccountItemDefinition":
|
|
||||||
case "FortCampaignHeroLoadoutItemDefinition":
|
case "FortCampaignHeroLoadoutItemDefinition":
|
||||||
case "FortConditionalResourceItemDefinition":
|
case "FortConditionalResourceItemDefinition":
|
||||||
case "FortChallengeBundleScheduleDefinition":
|
case "FortChallengeBundleScheduleDefinition":
|
||||||
case "FortWeaponMeleeDualWieldItemDefinition":
|
case "FortWeaponMeleeDualWieldItemDefinition":
|
||||||
case "FortDailyRewardScheduleTokenDefinition":
|
case "FortDailyRewardScheduleTokenDefinition":
|
||||||
case "FortCreativeWeaponRangedItemDefinition":
|
|
||||||
case "FortVehicleCosmeticsItemDefinition_Body":
|
|
||||||
case "FortVehicleCosmeticsItemDefinition_Skin":
|
|
||||||
case "FortVehicleCosmeticsItemDefinition_Wheel":
|
|
||||||
case "FortCreativeRealEstatePlotItemDefinition":
|
case "FortCreativeRealEstatePlotItemDefinition":
|
||||||
case "FortDeployableBaseCloudSaveItemDefinition":
|
|
||||||
case "FortVehicleCosmeticsItemDefinition_Booster":
|
|
||||||
case "AthenaDanceItemDefinition_AdHocSquadsJoin_C":
|
case "AthenaDanceItemDefinition_AdHocSquadsJoin_C":
|
||||||
case "FortVehicleCosmeticsItemDefinition_DriftSmoke":
|
|
||||||
case "FortVehicleCosmeticsItemDefinition_EngineAudio":
|
|
||||||
creator = _style switch
|
creator = _style switch
|
||||||
{
|
{
|
||||||
EIconStyle.Cataba => new BaseCommunity(_object, _style, "Cataba"),
|
EIconStyle.Cataba => new BaseCommunity(_object, _style, "Cataba"),
|
||||||
_ => new BaseIcon(_object, _style)
|
_ => new BaseIcon(_object, _style)
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
case "JunoAthenaCharacterItemOverrideDefinition":
|
|
||||||
case "JunoAthenaDanceItemOverrideDefinition":
|
|
||||||
creator = new BaseJuno(_object, _style);
|
|
||||||
return true;
|
|
||||||
case "FortTandemCharacterData":
|
|
||||||
creator = new BaseTandem(_object, _style);
|
|
||||||
return true;
|
|
||||||
case "FortTrapItemDefinition":
|
case "FortTrapItemDefinition":
|
||||||
|
case "FortTandemCharacterData":
|
||||||
case "FortSpyTechItemDefinition":
|
case "FortSpyTechItemDefinition":
|
||||||
case "FortAccoladeItemDefinition":
|
case "FortAccoladeItemDefinition":
|
||||||
case "FortContextTrapItemDefinition":
|
case "FortContextTrapItemDefinition":
|
||||||
|
|
@ -172,14 +123,10 @@ public class CreatorPackage : IDisposable
|
||||||
return true;
|
return true;
|
||||||
case "MaterialInstanceConstant"
|
case "MaterialInstanceConstant"
|
||||||
when _object.Owner != null &&
|
when _object.Owner != null &&
|
||||||
(_object.Owner.Name.Contains("/MI_OfferImages/", StringComparison.OrdinalIgnoreCase) ||
|
(_object.Owner.Name.EndsWith($"/MI_OfferImages/{_object.Name}") ||
|
||||||
_object.Owner.Name.EndsWith($"/RenderSwitch_Materials/{_object.Name}", StringComparison.OrdinalIgnoreCase) ||
|
_object.Owner.Name.EndsWith($"/RenderSwitch_Materials/{_object.Name}")):
|
||||||
_object.Owner.Name.EndsWith($"/MI_BPTile/{_object.Name}", StringComparison.OrdinalIgnoreCase)):
|
|
||||||
creator = new BaseMaterialInstance(_object, _style);
|
creator = new BaseMaterialInstance(_object, _style);
|
||||||
return true;
|
return true;
|
||||||
case "AthenaItemShopOfferDisplayData":
|
|
||||||
creator = new BaseOfferDisplayData(_object, _style);
|
|
||||||
return true;
|
|
||||||
case "FortMtxOfferData":
|
case "FortMtxOfferData":
|
||||||
creator = new BaseMtxOffer(_object, _style);
|
creator = new BaseMtxOffer(_object, _style);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -188,23 +135,20 @@ public class CreatorPackage : IDisposable
|
||||||
return true;
|
return true;
|
||||||
case "FortFeatItemDefinition":
|
case "FortFeatItemDefinition":
|
||||||
case "FortQuestItemDefinition":
|
case "FortQuestItemDefinition":
|
||||||
case "FortQuestItemDefinition_Athena":
|
|
||||||
case "FortQuestItemDefinition_Campaign":
|
|
||||||
case "AthenaDailyQuestDefinition":
|
case "AthenaDailyQuestDefinition":
|
||||||
case "FortUrgentQuestItemDefinition":
|
case "FortUrgentQuestItemDefinition":
|
||||||
creator = new Bases.FN.BaseQuest(_object, _style);
|
creator = new BaseQuest(_object, _style);
|
||||||
return true;
|
return true;
|
||||||
case "FortCompendiumItemDefinition":
|
case "FortCompendiumItemDefinition":
|
||||||
case "FortChallengeBundleItemDefinition":
|
case "FortChallengeBundleItemDefinition":
|
||||||
creator = new BaseBundle(_object, _style);
|
creator = new BaseBundle(_object, _style);
|
||||||
return true;
|
return true;
|
||||||
// case "AthenaSeasonItemDefinition":
|
case "AthenaSeasonItemDefinition":
|
||||||
// creator = new BaseSeason(_object, _style);
|
creator = new BaseSeason(_object, _style);
|
||||||
// return true;
|
return true;
|
||||||
case "FortItemAccessTokenType":
|
case "FortItemAccessTokenType":
|
||||||
creator = new BaseItemAccessToken(_object, _style);
|
creator = new BaseItemAccessToken(_object, _style);
|
||||||
return true;
|
return true;
|
||||||
case "FortCreativeOption":
|
|
||||||
case "PlaylistUserOptionEnum":
|
case "PlaylistUserOptionEnum":
|
||||||
case "PlaylistUserOptionBool":
|
case "PlaylistUserOptionBool":
|
||||||
case "PlaylistUserOptionString":
|
case "PlaylistUserOptionString":
|
||||||
|
|
@ -213,33 +157,34 @@ public class CreatorPackage : IDisposable
|
||||||
case "PlaylistUserOptionColorEnum":
|
case "PlaylistUserOptionColorEnum":
|
||||||
case "PlaylistUserOptionFloatEnum":
|
case "PlaylistUserOptionFloatEnum":
|
||||||
case "PlaylistUserOptionFloatRange":
|
case "PlaylistUserOptionFloatRange":
|
||||||
case "PlaylistUserTintedIconIntEnum":
|
|
||||||
case "PlaylistUserOptionPrimaryAsset":
|
case "PlaylistUserOptionPrimaryAsset":
|
||||||
case "PlaylistUserOptionCollisionProfileEnum":
|
case "PlaylistUserOptionCollisionProfileEnum":
|
||||||
creator = new BaseUserControl(_object, _style);
|
creator = new BaseUserControl(_object, _style);
|
||||||
return true;
|
return true;
|
||||||
// PandaGame
|
// Battle Breakers
|
||||||
case "CharacterData":
|
case "WExpGenericAccountItemDefinition":
|
||||||
creator = new BaseFighter(_object, _style);
|
creator = new BaseBreakersIcon(_object, EIconStyle.Default);
|
||||||
return true;
|
return true;
|
||||||
case "PerkGroup":
|
// Spellbreak
|
||||||
creator = new BasePerkGroup(_object, _style);
|
case "GQuest":
|
||||||
|
case "GAccolade":
|
||||||
|
case "GCosmeticCard":
|
||||||
|
case "GCosmeticSkin":
|
||||||
|
case "GCharacterPerk":
|
||||||
|
case "GCosmeticTitle":
|
||||||
|
case "GCosmeticBadge":
|
||||||
|
case "GCosmeticEmote":
|
||||||
|
case "GCosmeticTriumph":
|
||||||
|
case "GCosmeticRunTrail":
|
||||||
|
case "GCosmeticArtifact":
|
||||||
|
case "GCosmeticDropTrail":
|
||||||
|
creator = new BaseSpellIcon(_object, EIconStyle.Default);
|
||||||
return true;
|
return true;
|
||||||
case "StatTrackingBundleData":
|
case "GLeagueTier":
|
||||||
case "HydraSyncedDataAsset":
|
creator = new BaseLeague(_object, EIconStyle.Default);
|
||||||
case "AnnouncerPackData":
|
|
||||||
case "CharacterGiftData":
|
|
||||||
case "ProfileIconData":
|
|
||||||
case "RingOutVfxData":
|
|
||||||
case "BannerData":
|
|
||||||
case "EmoteData":
|
|
||||||
case "TauntData":
|
|
||||||
case "SkinData":
|
|
||||||
case "PerkData":
|
|
||||||
creator = new BasePandaIcon(_object, _style);
|
|
||||||
return true;
|
return true;
|
||||||
case "QuestData":
|
case "GLeagueDivision":
|
||||||
creator = new Bases.MV.BaseQuest(_object, _style);
|
creator = new BaseDivision(_object, EIconStyle.Default);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
creator = null;
|
creator = null;
|
||||||
|
|
@ -254,3 +199,4 @@ public class CreatorPackage : IDisposable
|
||||||
_object = null;
|
_object = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using CUE4Parse.UE4.Versions;
|
using CUE4Parse.UE4.Versions;
|
||||||
|
|
@ -6,11 +6,11 @@ using FModel.Settings;
|
||||||
using FModel.ViewModels;
|
using FModel.ViewModels;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FModel.Creator;
|
namespace FModel.Creator
|
||||||
|
{
|
||||||
public class Typefaces
|
public class Typefaces
|
||||||
{
|
{
|
||||||
private readonly Uri _BURBANK_BIG_CONDENSED_BOLD = new("pack://application:,,,/Resources/BurbankBigCondensed-Bold.ttf");
|
private readonly Uri _BURBANK_BIG_CONDENSED_BOLD = new Uri("pack://application:,,,/Resources/BurbankBigCondensed-Bold.ttf");
|
||||||
private const string _EXT = ".ufont";
|
private const string _EXT = ".ufont";
|
||||||
|
|
||||||
// FortniteGame
|
// FortniteGame
|
||||||
|
|
@ -21,6 +21,7 @@ public class Typefaces
|
||||||
private const string _BURBANK_BIG_REGULAR_BOLD = "BurbankBigRegular-Bold"; // official fortnite ig
|
private const string _BURBANK_BIG_REGULAR_BOLD = "BurbankBigRegular-Bold"; // official fortnite ig
|
||||||
private const string _BURBANK_SMALL_MEDIUM = "BurbankSmall-Medium";
|
private const string _BURBANK_SMALL_MEDIUM = "BurbankSmall-Medium";
|
||||||
private const string _DROID_SANS_FORTNITE_SUBSET = "DroidSans-Fortnite-Subset";
|
private const string _DROID_SANS_FORTNITE_SUBSET = "DroidSans-Fortnite-Subset";
|
||||||
|
private const string _NIS_JYAU = "NIS_JYAU"; // japanese fortnite
|
||||||
private const string _NOTO_COLOR_EMOJI = "NotoColorEmoji";
|
private const string _NOTO_COLOR_EMOJI = "NotoColorEmoji";
|
||||||
private const string _NOTO_SANS_BOLD = "NotoSans-Bold";
|
private const string _NOTO_SANS_BOLD = "NotoSans-Bold";
|
||||||
private const string _NOTO_SANS_FORTNITE_BOLD = "NotoSans-Fortnite-Bold";
|
private const string _NOTO_SANS_FORTNITE_BOLD = "NotoSans-Fortnite-Bold";
|
||||||
|
|
@ -31,7 +32,7 @@ public class Typefaces
|
||||||
private const string _NOTO_SANS_ARABIC_BLACK = "NotoSansArabic-Black"; // arabic fortnite
|
private const string _NOTO_SANS_ARABIC_BLACK = "NotoSansArabic-Black"; // arabic fortnite
|
||||||
private const string _NOTO_SANS_ARABIC_BOLD = "NotoSansArabic-Bold";
|
private const string _NOTO_SANS_ARABIC_BOLD = "NotoSansArabic-Bold";
|
||||||
private const string _NOTO_SANS_ARABIC_REGULAR = "NotoSansArabic-Regular";
|
private const string _NOTO_SANS_ARABIC_REGULAR = "NotoSansArabic-Regular";
|
||||||
private const string _NOTO_SANS_JP_BOLD = "NotoSansJP-Bold"; // japanese fortnite
|
private const string _NOTO_SANS_JP_BOLD = "NotoSansJP-Bold";
|
||||||
private const string _NOTO_SANS_KR_REGULAR = "NotoSansKR-Regular";
|
private const string _NOTO_SANS_KR_REGULAR = "NotoSansKR-Regular";
|
||||||
private const string _NOTO_SANS_SC_BLACK = "NotoSansSC-Black"; // simplified chinese fortnite
|
private const string _NOTO_SANS_SC_BLACK = "NotoSansSC-Black"; // simplified chinese fortnite
|
||||||
private const string _NOTO_SANS_SC_REGULAR = "NotoSansSC-Regular";
|
private const string _NOTO_SANS_SC_REGULAR = "NotoSansSC-Regular";
|
||||||
|
|
@ -40,13 +41,14 @@ public class Typefaces
|
||||||
private const string _BURBANK_SMALL_BLACK = "burbanksmall-black";
|
private const string _BURBANK_SMALL_BLACK = "burbanksmall-black";
|
||||||
private const string _BURBANK_SMALL_BOLD = "burbanksmall-bold";
|
private const string _BURBANK_SMALL_BOLD = "burbanksmall-bold";
|
||||||
|
|
||||||
// PandaGame
|
// WorldExplorers
|
||||||
private const string _PANDAGAME_BASE_PATH = "/Game/Panda_Main/UI/Fonts/";
|
private const string _BATTLE_BREAKERS_BASE_PATH = "/Game/UMG/Fonts/Faces/";
|
||||||
private const string _NORMS_STD_CONDENSED_EXTRABOLD_ITALIC = "Norms/TT_Norms_Std_Condensed_ExtraBold_Italic";
|
private const string _HEMIHEAD426 = "HemiHead426";
|
||||||
private const string _NORMS_PRO_EXTRABOLD_ITALIC = "Norms/TT_Norms_Pro_ExtraBold_Italic";
|
private const string _NOTO_SANS_JP_REGULAR = "NotoSansJP-Regular";
|
||||||
private const string _NORMS_STD_CONDENSED_MEDIUM = "Norms/TT_Norms_Std_Condensed_Medium";
|
private const string _LATO_BLACK = "Lato-Black";
|
||||||
private const string _XIANGHEHEI_SC_PRO_BLACK = "XiangHeHei_SC/MXiangHeHeiSCPro-Black";
|
private const string _LATO_BLACK_ITALIC = "Lato-BlackItalic";
|
||||||
private const string _XIANGHEHEI_SC_PRO_HEAVY = "XiangHeHei_SC/MXiangHeHeiSCPro-Heavy";
|
private const string _LATO_LIGHT = "Lato-Light";
|
||||||
|
private const string _LATO_MEDIUM = "Lato-Medium";
|
||||||
|
|
||||||
private readonly CUE4ParseViewModel _viewModel;
|
private readonly CUE4ParseViewModel _viewModel;
|
||||||
|
|
||||||
|
|
@ -56,34 +58,38 @@ public class Typefaces
|
||||||
public readonly SKTypeface Bottom; // must be null for non-latin base languages
|
public readonly SKTypeface Bottom; // must be null for non-latin base languages
|
||||||
public readonly SKTypeface Bundle;
|
public readonly SKTypeface Bundle;
|
||||||
public readonly SKTypeface BundleNumber;
|
public readonly SKTypeface BundleNumber;
|
||||||
public readonly SKTypeface TandemDisplayName;
|
|
||||||
public readonly SKTypeface TandemGenDescription;
|
|
||||||
public readonly SKTypeface TandemAddDescription;
|
|
||||||
|
|
||||||
public Typefaces(CUE4ParseViewModel viewModel)
|
public Typefaces(CUE4ParseViewModel viewModel)
|
||||||
{
|
{
|
||||||
|
byte[] data;
|
||||||
_viewModel = viewModel;
|
_viewModel = viewModel;
|
||||||
var language = UserSettings.Default.AssetLanguage;
|
var language = UserSettings.Default.AssetLanguage;
|
||||||
|
|
||||||
Default = SKTypeface.FromStream(Application.GetResourceStream(_BURBANK_BIG_CONDENSED_BOLD)?.Stream);
|
Default = SKTypeface.FromStream(Application.GetResourceStream(_BURBANK_BIG_CONDENSED_BOLD)?.Stream);
|
||||||
|
|
||||||
switch (viewModel.Provider.InternalGameName.ToUpperInvariant())
|
switch (viewModel.Game)
|
||||||
{
|
{
|
||||||
case "FORTNITEGAME":
|
case FGame.FortniteGame:
|
||||||
{
|
{
|
||||||
DisplayName = OnTheFly(_FORTNITE_BASE_PATH +
|
var namePath = _FORTNITE_BASE_PATH +
|
||||||
language switch
|
language switch
|
||||||
{
|
{
|
||||||
ELanguage.Korean => _ASIA_ERINM,
|
ELanguage.Korean => _ASIA_ERINM,
|
||||||
ELanguage.Russian => _BURBANK_BIG_CONDENSED_BLACK,
|
ELanguage.Russian => _BURBANK_BIG_CONDENSED_BLACK,
|
||||||
ELanguage.Japanese => _NOTO_SANS_JP_BOLD,
|
ELanguage.Japanese => _NIS_JYAU,
|
||||||
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
|
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
|
||||||
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
|
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
|
||||||
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
|
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
|
||||||
_ => string.Empty
|
_ => string.Empty
|
||||||
} + _EXT);
|
};
|
||||||
|
if (viewModel.Provider.TrySaveAsset(namePath + _EXT, out data))
|
||||||
|
{
|
||||||
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
|
DisplayName = SKTypeface.FromStream(m);
|
||||||
|
}
|
||||||
|
else DisplayName = Default;
|
||||||
|
|
||||||
Description = OnTheFly(_FORTNITE_BASE_PATH +
|
|
||||||
|
var descriptionPath = _FORTNITE_BASE_PATH +
|
||||||
language switch
|
language switch
|
||||||
{
|
{
|
||||||
ELanguage.Korean => _NOTO_SANS_KR_REGULAR,
|
ELanguage.Korean => _NOTO_SANS_KR_REGULAR,
|
||||||
|
|
@ -92,9 +98,16 @@ public class Typefaces
|
||||||
ELanguage.TraditionalChinese => _NOTO_SANS_TC_REGULAR,
|
ELanguage.TraditionalChinese => _NOTO_SANS_TC_REGULAR,
|
||||||
ELanguage.Chinese => _NOTO_SANS_SC_REGULAR,
|
ELanguage.Chinese => _NOTO_SANS_SC_REGULAR,
|
||||||
_ => _NOTO_SANS_REGULAR
|
_ => _NOTO_SANS_REGULAR
|
||||||
} + _EXT);
|
};
|
||||||
|
if (viewModel.Provider.TrySaveAsset(descriptionPath + _EXT, out data))
|
||||||
|
{
|
||||||
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
|
Description = SKTypeface.FromStream(m);
|
||||||
|
}
|
||||||
|
else Description = Default;
|
||||||
|
|
||||||
Bottom = OnTheFly(_FORTNITE_BASE_PATH +
|
|
||||||
|
var bottomPath = _FORTNITE_BASE_PATH +
|
||||||
language switch
|
language switch
|
||||||
{
|
{
|
||||||
ELanguage.Korean => string.Empty,
|
ELanguage.Korean => string.Empty,
|
||||||
|
|
@ -103,97 +116,109 @@ public class Typefaces
|
||||||
ELanguage.TraditionalChinese => string.Empty,
|
ELanguage.TraditionalChinese => string.Empty,
|
||||||
ELanguage.Chinese => string.Empty,
|
ELanguage.Chinese => string.Empty,
|
||||||
_ => _BURBANK_SMALL_BOLD
|
_ => _BURBANK_SMALL_BOLD
|
||||||
} + _EXT, true);
|
};
|
||||||
|
if (viewModel.Provider.TrySaveAsset(bottomPath + _EXT, out data))
|
||||||
|
{
|
||||||
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
|
Bottom = SKTypeface.FromStream(m);
|
||||||
|
}
|
||||||
|
// else keep it null
|
||||||
|
|
||||||
BundleNumber = OnTheFly(_FORTNITE_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK + _EXT);
|
|
||||||
|
|
||||||
Bundle = OnTheFly(_FORTNITE_BASE_PATH +
|
if (viewModel.Provider.TrySaveAsset(_FORTNITE_BASE_PATH + _BURBANK_BIG_CONDENSED_BLACK + _EXT, out data))
|
||||||
|
{
|
||||||
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
|
BundleNumber = SKTypeface.FromStream(m);
|
||||||
|
}
|
||||||
|
else BundleNumber = Default;
|
||||||
|
|
||||||
|
|
||||||
|
var bundleNamePath = _FORTNITE_BASE_PATH +
|
||||||
language switch
|
language switch
|
||||||
{
|
{
|
||||||
ELanguage.Korean => _ASIA_ERINM,
|
ELanguage.Korean => _ASIA_ERINM,
|
||||||
ELanguage.Russian => _BURBANK_BIG_CONDENSED_BLACK,
|
ELanguage.Russian => _BURBANK_BIG_CONDENSED_BLACK,
|
||||||
ELanguage.Japanese => _NOTO_SANS_JP_BOLD,
|
ELanguage.Japanese => _NIS_JYAU,
|
||||||
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
|
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
|
||||||
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
|
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
|
||||||
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
|
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
|
||||||
_ => string.Empty
|
_ => string.Empty
|
||||||
} + _EXT, true) ?? BundleNumber;
|
};
|
||||||
|
if (viewModel.Provider.TrySaveAsset(bundleNamePath + _EXT, out data))
|
||||||
TandemDisplayName = OnTheFly(_FORTNITE_BASE_PATH +
|
|
||||||
language switch
|
|
||||||
{
|
{
|
||||||
ELanguage.Korean => _ASIA_ERINM,
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
ELanguage.Russian => _BURBANK_BIG_CONDENSED_BLACK,
|
Bundle = SKTypeface.FromStream(m);
|
||||||
ELanguage.Japanese => _NOTO_SANS_JP_BOLD,
|
}
|
||||||
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
|
else Bundle = BundleNumber;
|
||||||
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
|
|
||||||
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
|
|
||||||
_ => _BURBANK_BIG_REGULAR_BLACK
|
|
||||||
} + _EXT);
|
|
||||||
|
|
||||||
TandemGenDescription = OnTheFly(_FORTNITE_BASE_PATH +
|
|
||||||
language switch
|
|
||||||
{
|
|
||||||
ELanguage.Korean => _ASIA_ERINM,
|
|
||||||
ELanguage.Japanese => _NOTO_SANS_JP_BOLD,
|
|
||||||
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
|
|
||||||
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
|
|
||||||
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
|
|
||||||
_ => _BURBANK_SMALL_BLACK
|
|
||||||
} + _EXT);
|
|
||||||
|
|
||||||
TandemAddDescription = OnTheFly(_FORTNITE_BASE_PATH +
|
|
||||||
language switch
|
|
||||||
{
|
|
||||||
ELanguage.Korean => _ASIA_ERINM,
|
|
||||||
ELanguage.Japanese => _NOTO_SANS_JP_BOLD,
|
|
||||||
ELanguage.Arabic => _NOTO_SANS_ARABIC_BLACK,
|
|
||||||
ELanguage.TraditionalChinese => _NOTO_SANS_TC_BLACK,
|
|
||||||
ELanguage.Chinese => _NOTO_SANS_SC_BLACK,
|
|
||||||
_ => _BURBANK_SMALL_BOLD
|
|
||||||
} + _EXT);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "MULTIVERSUS":
|
case FGame.WorldExplorers:
|
||||||
{
|
{
|
||||||
DisplayName = OnTheFly(_PANDAGAME_BASE_PATH + language switch
|
var namePath = _BATTLE_BREAKERS_BASE_PATH +
|
||||||
|
language switch
|
||||||
{
|
{
|
||||||
ELanguage.Chinese => _XIANGHEHEI_SC_PRO_HEAVY,
|
ELanguage.Korean => _NOTO_SANS_KR_REGULAR,
|
||||||
_ => _NORMS_PRO_EXTRABOLD_ITALIC
|
ELanguage.Russian => _LATO_BLACK,
|
||||||
} + _EXT);
|
ELanguage.Japanese => _NOTO_SANS_JP_REGULAR,
|
||||||
|
ELanguage.Chinese => _NOTO_SANS_SC_REGULAR,
|
||||||
|
_ => _HEMIHEAD426
|
||||||
|
};
|
||||||
|
if (viewModel.Provider.TrySaveAsset(namePath + _EXT, out data))
|
||||||
|
{
|
||||||
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
|
DisplayName = SKTypeface.FromStream(m);
|
||||||
|
}
|
||||||
|
else DisplayName = Default;
|
||||||
|
|
||||||
Description = OnTheFly(_PANDAGAME_BASE_PATH + language switch
|
var descriptionPath = _BATTLE_BREAKERS_BASE_PATH +
|
||||||
|
language switch
|
||||||
{
|
{
|
||||||
ELanguage.Chinese => _XIANGHEHEI_SC_PRO_BLACK,
|
ELanguage.Korean => _NOTO_SANS_KR_REGULAR,
|
||||||
_ => _NORMS_STD_CONDENSED_MEDIUM
|
ELanguage.Russian => _LATO_BLACK,
|
||||||
} + _EXT);
|
ELanguage.Japanese => _NOTO_SANS_JP_REGULAR,
|
||||||
|
ELanguage.Chinese => _NOTO_SANS_SC_REGULAR,
|
||||||
|
_ => _HEMIHEAD426
|
||||||
|
};
|
||||||
|
if (viewModel.Provider.TrySaveAsset(descriptionPath + _EXT, out data))
|
||||||
|
{
|
||||||
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
|
Description = SKTypeface.FromStream(m);
|
||||||
|
}
|
||||||
|
else Description = Default;
|
||||||
|
|
||||||
TandemDisplayName = OnTheFly(_PANDAGAME_BASE_PATH + language switch
|
|
||||||
{
|
|
||||||
ELanguage.Chinese => _XIANGHEHEI_SC_PRO_BLACK,
|
|
||||||
_ => _NORMS_STD_CONDENSED_EXTRABOLD_ITALIC
|
|
||||||
} + _EXT);
|
|
||||||
|
|
||||||
TandemGenDescription = OnTheFly(_PANDAGAME_BASE_PATH + language switch
|
|
||||||
{
|
|
||||||
ELanguage.Chinese => _XIANGHEHEI_SC_PRO_HEAVY,
|
|
||||||
_ => _NORMS_STD_CONDENSED_MEDIUM
|
|
||||||
} + _EXT);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
case FGame.ShooterGame:
|
||||||
{
|
break;
|
||||||
DisplayName = Default;
|
case FGame.DeadByDaylight:
|
||||||
Description = Default;
|
break;
|
||||||
|
case FGame.OakGame:
|
||||||
|
break;
|
||||||
|
case FGame.Dungeons:
|
||||||
|
break;
|
||||||
|
case FGame.g3:
|
||||||
|
break;
|
||||||
|
case FGame.StateOfDecay2:
|
||||||
|
break;
|
||||||
|
case FGame.Prospect:
|
||||||
|
break;
|
||||||
|
case FGame.Indiana:
|
||||||
|
break;
|
||||||
|
case FGame.RogueCompany:
|
||||||
|
break;
|
||||||
|
case FGame.SwGame:
|
||||||
|
break;
|
||||||
|
case FGame.Platform:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public SKTypeface OnTheFly(string path, bool fallback = false)
|
public SKTypeface OnTheFly(string path)
|
||||||
{
|
{
|
||||||
if (!_viewModel.Provider.TrySaveAsset(path, out var data)) return fallback ? null : Default;
|
if (!_viewModel.Provider.TrySaveAsset(path, out var data)) return Default;
|
||||||
var m = new MemoryStream(data) {Position = 0};
|
var m = new MemoryStream(data) {Position = 0};
|
||||||
return SKTypeface.FromStream(m);
|
return SKTypeface.FromStream(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,27 +1,23 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using CUE4Parse.UE4.Assets.Exports;
|
using CUE4Parse.UE4.Assets.Exports;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
|
||||||
using CUE4Parse.UE4.Versions;
|
|
||||||
using CUE4Parse_Conversion.Textures;
|
|
||||||
using CUE4Parse.UE4.Assets.Objects;
|
using CUE4Parse.UE4.Assets.Objects;
|
||||||
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
|
using CUE4Parse.Utils;
|
||||||
|
using CUE4Parse_Conversion.Textures;
|
||||||
using FModel.Framework;
|
using FModel.Framework;
|
||||||
using FModel.Extensions;
|
|
||||||
using FModel.Services;
|
using FModel.Services;
|
||||||
using FModel.Settings;
|
|
||||||
using FModel.ViewModels;
|
using FModel.ViewModels;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
|
|
||||||
namespace FModel.Creator;
|
namespace FModel.Creator
|
||||||
|
{
|
||||||
public static class Utils
|
public static class Utils
|
||||||
{
|
{
|
||||||
private static ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
|
private static ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
|
||||||
|
|
@ -42,6 +38,12 @@ public static class Utils
|
||||||
|
|
||||||
public static bool TryGetDisplayAsset(UObject uObject, out SKBitmap preview)
|
public static bool TryGetDisplayAsset(UObject uObject, out SKBitmap preview)
|
||||||
{
|
{
|
||||||
|
if (uObject.TryGetValue(out FSoftObjectPath displayAsset, "DisplayAssetPath"))
|
||||||
|
{
|
||||||
|
preview = GetDisplayAsset(displayAsset);
|
||||||
|
return preview != null;
|
||||||
|
}
|
||||||
|
|
||||||
if (uObject.TryGetValue(out FSoftObjectPath sidePanelIcon, "SidePanelIcon"))
|
if (uObject.TryGetValue(out FSoftObjectPath sidePanelIcon, "SidePanelIcon"))
|
||||||
{
|
{
|
||||||
preview = GetBitmap(sidePanelIcon);
|
preview = GetBitmap(sidePanelIcon);
|
||||||
|
|
@ -59,23 +61,35 @@ public static class Utils
|
||||||
return preview != null;
|
return preview != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SKBitmap GetDisplayAsset(FSoftObjectPath path)
|
||||||
|
{
|
||||||
|
if (!TryLoadObject(path.AssetPathName.Text, out UObject obj)) return null;
|
||||||
|
|
||||||
|
if (obj.TryGetValue(out FStructFallback type, "DetailsImage") &&
|
||||||
|
type.TryGetValue(out FPackageIndex resource, "ResourceObject") && resource.ResolvedObject?.Outer != null &&
|
||||||
|
!resource.ResolvedObject.Outer.Name.Text.Contains("FortniteGame/Content/Athena/Prototype/Textures/"))
|
||||||
|
{
|
||||||
|
return GetBitmap(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
public static SKBitmap GetBitmap(FPackageIndex packageIndex)
|
public static SKBitmap GetBitmap(FPackageIndex packageIndex)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!TryGetPackageIndexExport(packageIndex, out UObject export)) return null;
|
if (!TryGetPackageIndexExport(packageIndex, out UExport export)) return null;
|
||||||
switch (export)
|
switch (export)
|
||||||
{
|
{
|
||||||
case UTexture2D texture:
|
case UTexture2D texture:
|
||||||
return GetBitmap(texture);
|
return GetBitmap(texture);
|
||||||
case UMaterialInstanceConstant material:
|
case UMaterialInstanceConstant material:
|
||||||
return GetBitmap(material);
|
return GetBitmap(material);
|
||||||
default:
|
case UObject uObject:
|
||||||
{
|
{
|
||||||
if (export.TryGetValue(out FInstancedStruct[] dataList, "DataList")) return GetBitmap(dataList);
|
if (uObject.TryGetValue(out FSoftObjectPath previewImage, "LargePreviewImage", "SmallPreviewImage")) return GetBitmap(previewImage);
|
||||||
if (export.TryGetValue(out FSoftObjectPath previewImage, "LargePreviewImage", "SmallPreviewImage")) return GetBitmap(previewImage);
|
if (uObject.TryGetValue(out string largePreview, "LargePreviewImage")) return GetBitmap(largePreview);
|
||||||
if (export.TryGetValue(out string largePreview, "LargePreviewImage")) return GetBitmap(largePreview);
|
if (uObject.TryGetValue(out FPackageIndex smallPreview, "SmallPreviewImage"))
|
||||||
if (export.TryGetValue(out FPackageIndex smallPreview, "SmallPreviewImage"))
|
|
||||||
{
|
{
|
||||||
packageIndex = smallPreview;
|
packageIndex = smallPreview;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -83,40 +97,22 @@ public static class Utils
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
default:
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SKBitmap GetBitmap(FInstancedStruct[] structs)
|
|
||||||
{
|
|
||||||
if (structs.FirstOrDefault(d => d.NonConstStruct?.TryGetValue(out FSoftObjectPath p, "LargeIcon") == true && !p.AssetPathName.IsNone) is { NonConstStruct: not null } isl)
|
|
||||||
{
|
|
||||||
return GetBitmap(isl.NonConstStruct.Get<FSoftObjectPath>("LargeIcon"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (structs.FirstOrDefault(d => d.NonConstStruct?.TryGetValue(out FSoftObjectPath p, "Icon") == true && !p.AssetPathName.IsNone) is { NonConstStruct: not null } isi)
|
|
||||||
{
|
|
||||||
return GetBitmap(isi.NonConstStruct.Get<FSoftObjectPath>("Icon"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
public static SKBitmap GetBitmap(UMaterialInstanceConstant material)
|
public static SKBitmap GetBitmap(UMaterialInstanceConstant material)
|
||||||
{
|
{
|
||||||
if (material == null) return null;
|
if (material == null) return null;
|
||||||
foreach (var textureParameter in material.TextureParameterValues)
|
foreach (var textureParameter in material.TextureParameterValues)
|
||||||
{
|
{
|
||||||
if (!textureParameter.ParameterValue.TryLoad<UTexture2D>(out var texture)) continue;
|
if (!(textureParameter.ParameterValue is UTexture2D texture)) continue;
|
||||||
switch (textureParameter.ParameterInfo.Name.Text)
|
switch (textureParameter.ParameterInfo.Name.Text)
|
||||||
{
|
{
|
||||||
case "MainTex":
|
|
||||||
case "Texture":
|
|
||||||
case "TextureA":
|
case "TextureA":
|
||||||
case "TextureB":
|
case "TextureB":
|
||||||
case "OfferImage":
|
case "OfferImage":
|
||||||
case "KeyArtTexture":
|
|
||||||
case "NPC-Portrait":
|
|
||||||
{
|
{
|
||||||
return GetBitmap(texture);
|
return GetBitmap(texture);
|
||||||
}
|
}
|
||||||
|
|
@ -125,25 +121,14 @@ public static class Utils
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SKBitmap GetB64Bitmap(string b64) => SKBitmap.Decode(new MemoryStream(Convert.FromBase64String(b64)) {Position = 0});
|
public static SKBitmap GetB64Bitmap(string b64) => SKBitmap.Decode(new MemoryStream(Convert.FromBase64String(b64)) {Position = 0});
|
||||||
public static SKBitmap GetBitmap(FSoftObjectPath softObjectPath) => GetBitmap(softObjectPath.AssetPathName.Text);
|
public static SKBitmap GetBitmap(FSoftObjectPath softObjectPath) => GetBitmap(softObjectPath.AssetPathName.Text);
|
||||||
public static SKBitmap GetBitmap(string fullPath) => TryLoadObject(fullPath, out UTexture2D texture) ? GetBitmap(texture) : null;
|
public static SKBitmap GetBitmap(string fullPath) => TryLoadObject(fullPath, out UTexture2D texture) ? GetBitmap(texture) : null;
|
||||||
public static SKBitmap GetBitmap(UTexture2D texture) => texture.Decode(UserSettings.Default.CurrentDir.TexturePlatform);
|
public static SKBitmap GetBitmap(UTexture2D texture) => texture.IsVirtual ? null : SKBitmap.Decode(texture.Decode()?.Encode());
|
||||||
public static SKBitmap GetBitmap(byte[] data) => SKBitmap.Decode(data);
|
public static SKBitmap GetBitmap(byte[] data) => SKBitmap.Decode(data);
|
||||||
|
|
||||||
public static SKBitmap ResizeWithRatio(this SKBitmap me, double width, double height)
|
|
||||||
{
|
|
||||||
var ratioX = width / me.Width;
|
|
||||||
var ratioY = height / me.Height;
|
|
||||||
return ResizeWithRatio(me, ratioX < ratioY ? ratioX : ratioY);
|
|
||||||
}
|
|
||||||
public static SKBitmap ResizeWithRatio(this SKBitmap me, double ratio)
|
|
||||||
{
|
|
||||||
return me.Resize(Convert.ToInt32(me.Width * ratio), Convert.ToInt32(me.Height * ratio));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SKBitmap Resize(this SKBitmap me, int size) => me.Resize(size, size);
|
public static SKBitmap Resize(this SKBitmap me, int size) => me.Resize(size, size);
|
||||||
|
|
||||||
public static SKBitmap Resize(this SKBitmap me, int width, int height)
|
public static SKBitmap Resize(this SKBitmap me, int width, int height)
|
||||||
{
|
{
|
||||||
var bmp = new SKBitmap(new SKImageInfo(width, height), SKBitmapAllocFlags.ZeroPixels);
|
var bmp = new SKBitmap(new SKImageInfo(width, height), SKBitmapAllocFlags.ZeroPixels);
|
||||||
|
|
@ -152,59 +137,52 @@ public static class Utils
|
||||||
return bmp;
|
return bmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetPackageIndexExport<T>(FPackageIndex packageIndex, out T export) where T : UObject
|
public static bool TryGetPackageIndexExport<T>(FPackageIndex packageIndex, out T export) where T : UExport
|
||||||
{
|
{
|
||||||
return packageIndex.TryLoad(out export);
|
if (packageIndex.ResolvedObject == null)
|
||||||
|
{
|
||||||
|
export = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outerChain = new List<string>();
|
||||||
|
var current = packageIndex.ResolvedObject.Outer;
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
outerChain.Add(current.Name.Text);
|
||||||
|
current = current.Outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outerChain.Count < 1)
|
||||||
|
{
|
||||||
|
export = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_applicationView.CUE4Parse.Provider.TryLoadPackage(outerChain[^1], out var pkg))
|
||||||
|
{
|
||||||
|
export = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = pkg.GetExport(packageIndex.ResolvedObject.Index) as T;
|
||||||
|
return export != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fullpath must be either without any extension or with the export objectname
|
// fullpath must be either without any extension or with the export objectname
|
||||||
public static bool TryLoadObject<T>(string fullPath, out T export) where T : UObject
|
public static bool TryLoadObject<T>(string fullPath, out T export) where T : UExport
|
||||||
{
|
{
|
||||||
return _applicationView.CUE4Parse.Provider.TryLoadObject(fullPath, out export);
|
return _applicationView.CUE4Parse.Provider.TryLoadObject(fullPath, out export);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<UObject> LoadExports(string packagePath)
|
public static IEnumerable<UExport> LoadExports(string fullPath)
|
||||||
{
|
{
|
||||||
return _applicationView.CUE4Parse.Provider.LoadAllObjects(packagePath);
|
return _applicationView.CUE4Parse.Provider.LoadObjectExports(fullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float GetMaxFontSize(double sectorSize, SKTypeface typeface, string text, float degreeOfCertainty = 1f, float maxFont = 100f)
|
public static string GetLocalizedResource(string namespacee, string key, string defaultValue)
|
||||||
{
|
{
|
||||||
var max = maxFont;
|
return _applicationView.CUE4Parse.Provider.GetLocalizedString(namespacee, key, defaultValue);
|
||||||
var min = 0f;
|
|
||||||
var last = -1f;
|
|
||||||
float value;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
value = min + ((max - min) / 2);
|
|
||||||
using (SKFont ft = new SKFont(typeface, value))
|
|
||||||
using (SKPaint paint = new SKPaint(ft))
|
|
||||||
{
|
|
||||||
if (paint.MeasureText(text) > sectorSize)
|
|
||||||
{
|
|
||||||
last = value;
|
|
||||||
max = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
min = value;
|
|
||||||
if (Math.Abs(last - value) <= degreeOfCertainty)
|
|
||||||
return last;
|
|
||||||
|
|
||||||
last = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetLocalizedResource(string @namespace, string key, string defaultValue)
|
|
||||||
{
|
|
||||||
return _applicationView.CUE4Parse.Provider.GetLocalizedString(@namespace, key, defaultValue);
|
|
||||||
}
|
|
||||||
public static string GetLocalizedResource<T>(T @enum) where T : Enum
|
|
||||||
{
|
|
||||||
var resource = _applicationView.CUE4Parse.Provider.GetLocalizedString("", @enum.GetDescription(), @enum.ToString());
|
|
||||||
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(resource.ToLower());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetFullPath(string partialPath)
|
public static string GetFullPath(string partialPath)
|
||||||
|
|
@ -247,8 +225,8 @@ public static class Utils
|
||||||
y += lineHeight;
|
y += lineHeight;
|
||||||
var x = side switch
|
var x = side switch
|
||||||
{
|
{
|
||||||
SKTextAlign.Center => area.MidX - shapedText.Width / 2,
|
SKTextAlign.Center => area.MidX - shapedText.Points[^1].X / 2,
|
||||||
SKTextAlign.Right => size - margin - shapedText.Width,
|
SKTextAlign.Right => size - margin - shapedText.Points[^1].X,
|
||||||
SKTextAlign.Left => margin,
|
SKTextAlign.Left => margin,
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
};
|
};
|
||||||
|
|
@ -266,13 +244,6 @@ public static class Utils
|
||||||
|
|
||||||
foreach (var line in lines)
|
foreach (var line in lines)
|
||||||
{
|
{
|
||||||
var fontSize = GetMaxFontSize(area.Width, paint.Typeface, line);
|
|
||||||
if (paint.TextSize > fontSize) // if the text is not fitting in the line decrease the font size (CKJ languages)
|
|
||||||
{
|
|
||||||
paint.TextSize = fontSize;
|
|
||||||
lineHeight = paint.TextSize * 1.2f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line == null) continue;
|
if (line == null) continue;
|
||||||
var lineText = line.Trim();
|
var lineText = line.Trim();
|
||||||
var shaper = new CustomSKShaper(paint.Typeface);
|
var shaper = new CustomSKShaper(paint.Typeface);
|
||||||
|
|
@ -280,8 +251,8 @@ public static class Utils
|
||||||
|
|
||||||
var x = side switch
|
var x = side switch
|
||||||
{
|
{
|
||||||
SKTextAlign.Center => area.MidX - shapedText.Width / 2,
|
SKTextAlign.Center => area.MidX - shapedText.Points[^1].X / 2,
|
||||||
SKTextAlign.Right => size - margin - shapedText.Width,
|
SKTextAlign.Right => size - margin - shapedText.Points[^1].X,
|
||||||
SKTextAlign.Left => area.Left,
|
SKTextAlign.Left => area.Left,
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
};
|
};
|
||||||
|
|
@ -295,81 +266,6 @@ public static class Utils
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Chinese, Korean and Japanese text split
|
|
||||||
|
|
||||||
// https://github.com/YoungjaeKim/mikan.sharp/blob/master/MikanSharp/Mikan/Mikan.cs
|
|
||||||
|
|
||||||
static string joshi = @"(でなければ|について|かしら|くらい|けれど|なのか|ばかり|ながら|ことよ|こそ|こと|さえ|しか|した|たり|だけ|だに|だの|つつ|ても|てよ|でも|とも|から|など|なり|ので|のに|ほど|まで|もの|やら|より|って|で|と|な|に|ね|の|も|は|ば|へ|や|わ|を|か|が|さ|し|ぞ|て)";
|
|
||||||
static string keywords = @"(\ |[a-zA-Z0-9]+\.[a-z]{2,}|[一-龠々〆ヵヶゝ]+|[ぁ-んゝ]+|[ァ-ヴー]+|[a-zA-Z0-9]+|[a-zA-Z0-9]+)";
|
|
||||||
static string periods = @"([\.\,。、!\!?\?]+)$";
|
|
||||||
static string bracketsBegin = @"([〈《「『「((\[【〔〚〖〘❮❬❪❨(<{❲❰{❴])";
|
|
||||||
static string bracketsEnd = @"([〉》」』」))\]】〕〗〙〛}>\)❩❫❭❯❱❳❵}])";
|
|
||||||
|
|
||||||
public static string[] SplitCKJText(string str)
|
|
||||||
{
|
|
||||||
var line1 = Regex.Split(str, keywords).ToList();
|
|
||||||
var line2 = line1.SelectMany((o, _) => Regex.Split(o, joshi)).ToList();
|
|
||||||
var line3 = line2.SelectMany((o, _) => Regex.Split(o, bracketsBegin)).ToList();
|
|
||||||
var line4 = line3.SelectMany((o, _) => Regex.Split(o, bracketsEnd)).ToList();
|
|
||||||
var words = line4.Where(o => !string.IsNullOrEmpty(o)).ToList();
|
|
||||||
|
|
||||||
var prevType = string.Empty;
|
|
||||||
var prevWord = string.Empty;
|
|
||||||
List<string> result = new List<string>();
|
|
||||||
|
|
||||||
words.ForEach(word =>
|
|
||||||
{
|
|
||||||
var token = Regex.IsMatch(word, periods) || Regex.IsMatch(word, joshi);
|
|
||||||
|
|
||||||
if (Regex.IsMatch(word, bracketsBegin))
|
|
||||||
{
|
|
||||||
prevType = "braketBegin";
|
|
||||||
prevWord = word;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Regex.IsMatch(word, bracketsEnd))
|
|
||||||
{
|
|
||||||
result[result.Count - 1] += word;
|
|
||||||
prevType = "braketEnd";
|
|
||||||
prevWord = word;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prevType == "braketBegin")
|
|
||||||
{
|
|
||||||
word = prevWord + word;
|
|
||||||
prevWord = string.Empty;
|
|
||||||
prevType = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
// すでに文字が入っている上で助詞が続く場合は結合する
|
|
||||||
if (result.Count > 0 && token && prevType == string.Empty)
|
|
||||||
{
|
|
||||||
result[result.Count - 1] += word;
|
|
||||||
prevType = "keyword";
|
|
||||||
prevWord = word;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 単語のあとの文字がひらがななら結合する
|
|
||||||
if (result.Count > 1 && token || (prevType == "keyword" && Regex.IsMatch(word, @"[ぁ-んゝ]+")))
|
|
||||||
{
|
|
||||||
result[result.Count - 1] += word;
|
|
||||||
prevType = string.Empty;
|
|
||||||
prevWord = word;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Add(word);
|
|
||||||
prevType = "keyword";
|
|
||||||
prevWord = word;
|
|
||||||
});
|
|
||||||
return result.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public static List<string> SplitLines(string text, SKPaint paint, float maxWidth)
|
public static List<string> SplitLines(string text, SKPaint paint, float maxWidth)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(text)) return null;
|
if (string.IsNullOrEmpty(text)) return null;
|
||||||
|
|
@ -383,21 +279,13 @@ public static class Utils
|
||||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||||
|
|
||||||
float width = 0;
|
float width = 0;
|
||||||
var isCJK = false;
|
|
||||||
var words = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
var words = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
if (words.Length <= 1 && UserSettings.Default.AssetLanguage is ELanguage.Japanese or ELanguage.Korean or ELanguage.Chinese or ELanguage.TraditionalChinese)
|
|
||||||
{
|
|
||||||
words = SplitCKJText(line);
|
|
||||||
isCJK = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lineResult = new StringBuilder();
|
var lineResult = new StringBuilder();
|
||||||
foreach (var word in words)
|
foreach (var word in words)
|
||||||
{
|
{
|
||||||
var wordWidth = paint.MeasureText(word);
|
var wordWidth = paint.MeasureText(word);
|
||||||
var wordWithSpaceWidth = wordWidth + spaceWidth;
|
var wordWithSpaceWidth = wordWidth + spaceWidth;
|
||||||
var wordWithSpace = isCJK ? word : word + " ";
|
var wordWithSpace = word + " ";
|
||||||
|
|
||||||
if (width + wordWidth > maxWidth)
|
if (width + wordWidth > maxWidth)
|
||||||
{
|
{
|
||||||
|
|
@ -418,3 +306,4 @@ public static class Utils
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
using System;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace FModel;
|
|
||||||
|
|
||||||
|
namespace FModel
|
||||||
|
{
|
||||||
public enum EBuildKind
|
public enum EBuildKind
|
||||||
{
|
{
|
||||||
Debug,
|
Debug,
|
||||||
|
|
@ -12,15 +11,16 @@ public enum EBuildKind
|
||||||
|
|
||||||
public enum EErrorKind
|
public enum EErrorKind
|
||||||
{
|
{
|
||||||
|
Close,
|
||||||
Ignore,
|
Ignore,
|
||||||
Restart,
|
Restart
|
||||||
ResetSettings
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SettingsOut
|
public enum SettingsOut
|
||||||
{
|
{
|
||||||
|
Restart,
|
||||||
ReloadLocres,
|
ReloadLocres,
|
||||||
ReloadMappings
|
Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EStatusKind
|
public enum EStatusKind
|
||||||
|
|
@ -51,8 +51,50 @@ public enum EDiscordRpc
|
||||||
Never
|
Never
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum EEnabledDisabled
|
||||||
|
{
|
||||||
|
[Description("Disabled")]
|
||||||
|
Disabled,
|
||||||
|
[Description("Enabled")]
|
||||||
|
Enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum FGame
|
||||||
|
{
|
||||||
|
[Description("Unknown")]
|
||||||
|
Unknown,
|
||||||
|
[Description("Fortnite")]
|
||||||
|
FortniteGame,
|
||||||
|
[Description("Valorant")]
|
||||||
|
ShooterGame,
|
||||||
|
[Description("Dead By Daylight")]
|
||||||
|
DeadByDaylight,
|
||||||
|
[Description("Borderlands 3")]
|
||||||
|
OakGame,
|
||||||
|
[Description("Minecraft Dungeons")]
|
||||||
|
Dungeons,
|
||||||
|
[Description("Battle Breakers")]
|
||||||
|
WorldExplorers,
|
||||||
|
[Description("Spellbreak")]
|
||||||
|
g3,
|
||||||
|
[Description("State Of Decay 2")]
|
||||||
|
StateOfDecay2,
|
||||||
|
[Description("The Cycle")]
|
||||||
|
Prospect,
|
||||||
|
[Description("The Outer Worlds")]
|
||||||
|
Indiana,
|
||||||
|
[Description("Rogue Company")]
|
||||||
|
RogueCompany,
|
||||||
|
[Description("Star Wars: Jedi Fallen Order")]
|
||||||
|
SwGame,
|
||||||
|
[Description("Core")]
|
||||||
|
Platform
|
||||||
|
}
|
||||||
|
|
||||||
public enum ELoadingMode
|
public enum ELoadingMode
|
||||||
{
|
{
|
||||||
|
[Description("Single")]
|
||||||
|
Single,
|
||||||
[Description("Multiple")]
|
[Description("Multiple")]
|
||||||
Multiple,
|
Multiple,
|
||||||
[Description("All")]
|
[Description("All")]
|
||||||
|
|
@ -63,15 +105,13 @@ public enum ELoadingMode
|
||||||
AllButModified
|
AllButModified
|
||||||
}
|
}
|
||||||
|
|
||||||
// public enum EUpdateMode
|
public enum EUpdateMode
|
||||||
// {
|
{
|
||||||
// [Description("Stable")]
|
[Description("Stable")]
|
||||||
// Stable,
|
Stable,
|
||||||
// [Description("Beta")]
|
[Description("Beta")]
|
||||||
// Beta,
|
Beta
|
||||||
// [Description("QA Testing")]
|
}
|
||||||
// Qa
|
|
||||||
// }
|
|
||||||
|
|
||||||
public enum ECompressedAudio
|
public enum ECompressedAudio
|
||||||
{
|
{
|
||||||
|
|
@ -96,21 +136,4 @@ public enum EIconStyle
|
||||||
// [Description("Community")]
|
// [Description("Community")]
|
||||||
// CommunityMade
|
// CommunityMade
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum EEndpointType
|
|
||||||
{
|
|
||||||
Aes,
|
|
||||||
Mapping
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum EBulkType
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Auto = 1 << 0,
|
|
||||||
Properties = 1 << 1,
|
|
||||||
Textures = 1 << 2,
|
|
||||||
Meshes = 1 << 3,
|
|
||||||
Skeletons = 1 << 4,
|
|
||||||
Animations = 1 << 5
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,16 +4,14 @@ using System.Xml;
|
||||||
using ICSharpCode.AvalonEdit.Highlighting;
|
using ICSharpCode.AvalonEdit.Highlighting;
|
||||||
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
|
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
|
||||||
|
|
||||||
namespace FModel.Extensions;
|
namespace FModel.Extensions
|
||||||
|
{
|
||||||
public static class AvalonExtensions
|
public static class AvalonExtensions
|
||||||
{
|
{
|
||||||
private static readonly IHighlightingDefinition _jsonHighlighter = LoadHighlighter("Json.xshd");
|
private static readonly IHighlightingDefinition _jsonHighlighter = LoadHighlighter("Json.xshd");
|
||||||
private static readonly IHighlightingDefinition _iniHighlighter = LoadHighlighter("Ini.xshd");
|
private static readonly IHighlightingDefinition _iniHighlighter = LoadHighlighter("Ini.xshd");
|
||||||
private static readonly IHighlightingDefinition _xmlHighlighter = LoadHighlighter("Xml.xshd");
|
private static readonly IHighlightingDefinition _xmlHighlighter = LoadHighlighter("Xml.xshd");
|
||||||
private static readonly IHighlightingDefinition _cppHighlighter = LoadHighlighter("Cpp.xshd");
|
private static readonly IHighlightingDefinition _cppHighlighter = LoadHighlighter("Cpp.xshd");
|
||||||
private static readonly IHighlightingDefinition _changelogHighlighter = LoadHighlighter("Changelog.xshd");
|
|
||||||
private static readonly IHighlightingDefinition _verseHighlighter = LoadHighlighter("Verse.xshd");
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static IHighlightingDefinition LoadHighlighter(string resourceName)
|
private static IHighlightingDefinition LoadHighlighter(string resourceName)
|
||||||
|
|
@ -33,18 +31,12 @@ public static class AvalonExtensions
|
||||||
case "csv":
|
case "csv":
|
||||||
return _iniHighlighter;
|
return _iniHighlighter;
|
||||||
case "xml":
|
case "xml":
|
||||||
case "tps":
|
|
||||||
return _xmlHighlighter;
|
return _xmlHighlighter;
|
||||||
case "h":
|
case "h":
|
||||||
case "cpp":
|
case "cpp":
|
||||||
return _cppHighlighter;
|
return _cppHighlighter;
|
||||||
case "changelog":
|
|
||||||
return _changelogHighlighter;
|
|
||||||
case "verse":
|
|
||||||
return _verseHighlighter;
|
|
||||||
case "bat":
|
case "bat":
|
||||||
case "txt":
|
case "txt":
|
||||||
case "pem":
|
|
||||||
case "po":
|
case "po":
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
|
|
@ -52,3 +44,4 @@ public static class AvalonExtensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,198 +0,0 @@
|
||||||
using SkiaSharp;
|
|
||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace FModel.Extensions;
|
|
||||||
|
|
||||||
public static class ClipboardExtensions
|
|
||||||
{
|
|
||||||
public static void SetImage(byte[] pngBytes, string fileName = null)
|
|
||||||
{
|
|
||||||
Clipboard.Clear();
|
|
||||||
var data = new DataObject();
|
|
||||||
using var pngMs = new MemoryStream(pngBytes);
|
|
||||||
using var image = Image.FromStream(pngMs);
|
|
||||||
// As standard bitmap, without transparency support
|
|
||||||
data.SetData(DataFormats.Bitmap, image, true);
|
|
||||||
// As PNG. Gimp will prefer this over the other two
|
|
||||||
data.SetData("PNG", pngMs, false);
|
|
||||||
// As DIB. This is (wrongly) accepted as ARGB by many applications
|
|
||||||
using var dibMemStream = new MemoryStream(ConvertToDib(image));
|
|
||||||
data.SetData(DataFormats.Dib, dibMemStream, false);
|
|
||||||
// Optional fileName
|
|
||||||
if (!string.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
var htmlFragment = GenerateHTMLFragment($"<img src=\"{fileName}\"/>");
|
|
||||||
data.SetData(DataFormats.Html, htmlFragment);
|
|
||||||
}
|
|
||||||
// The 'copy=true' argument means the MemoryStreams can be safely disposed after the operation
|
|
||||||
Clipboard.SetDataObject(data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] ConvertToDib(Image image)
|
|
||||||
{
|
|
||||||
byte[] bm32bData;
|
|
||||||
var width = image.Width;
|
|
||||||
var height = image.Height;
|
|
||||||
|
|
||||||
// Ensure image is 32bppARGB by painting it on a new 32bppARGB image.
|
|
||||||
using (var bm32b = new Bitmap(width, height, PixelFormat.Format32bppPArgb))
|
|
||||||
{
|
|
||||||
using (var gr = Graphics.FromImage(bm32b))
|
|
||||||
{
|
|
||||||
gr.DrawImage(image, new Rectangle(0, 0, width, height));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bitmap format has its lines reversed.
|
|
||||||
bm32b.RotateFlip(RotateFlipType.Rotate180FlipX);
|
|
||||||
bm32bData = GetRawBytes(bm32b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BITMAPINFOHEADER struct for DIB.
|
|
||||||
const int hdrSize = 0x28;
|
|
||||||
var fullImage = new byte[hdrSize + 12 + bm32bData.Length];
|
|
||||||
//Int32 biSize;
|
|
||||||
WriteIntToByteArray(fullImage, 0x00, 4, true, hdrSize);
|
|
||||||
//Int32 biWidth;
|
|
||||||
WriteIntToByteArray(fullImage, 0x04, 4, true, (uint) width);
|
|
||||||
//Int32 biHeight;
|
|
||||||
WriteIntToByteArray(fullImage, 0x08, 4, true, (uint) height);
|
|
||||||
//Int16 biPlanes;
|
|
||||||
WriteIntToByteArray(fullImage, 0x0C, 2, true, 1);
|
|
||||||
//Int16 biBitCount;
|
|
||||||
WriteIntToByteArray(fullImage, 0x0E, 2, true, 32);
|
|
||||||
//BITMAPCOMPRESSION biCompression = BITMAPCOMPRESSION.BITFIELDS;
|
|
||||||
WriteIntToByteArray(fullImage, 0x10, 4, true, 3);
|
|
||||||
//Int32 biSizeImage;
|
|
||||||
WriteIntToByteArray(fullImage, 0x14, 4, true, (uint) bm32bData.Length);
|
|
||||||
// These are all 0. Since .net clears new arrays, don't bother writing them.
|
|
||||||
//Int32 biXPelsPerMeter = 0;
|
|
||||||
//Int32 biYPelsPerMeter = 0;
|
|
||||||
//Int32 biClrUsed = 0;
|
|
||||||
//Int32 biClrImportant = 0;
|
|
||||||
|
|
||||||
// The aforementioned "BITFIELDS": colour masks applied to the Int32 pixel value to get the R, G and B values.
|
|
||||||
WriteIntToByteArray(fullImage, hdrSize + 0, 4, true, 0x00FF0000);
|
|
||||||
WriteIntToByteArray(fullImage, hdrSize + 4, 4, true, 0x0000FF00);
|
|
||||||
WriteIntToByteArray(fullImage, hdrSize + 8, 4, true, 0x000000FF);
|
|
||||||
|
|
||||||
Unsafe.CopyBlockUnaligned(ref fullImage[hdrSize + 12], ref bm32bData[0], (uint) bm32bData.Length);
|
|
||||||
return fullImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] ConvertToDib(byte[] pngBytes = null)
|
|
||||||
{
|
|
||||||
byte[] bm32bData;
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
using (var skBmp = SKBitmap.Decode(pngBytes))
|
|
||||||
{
|
|
||||||
width = skBmp.Width;
|
|
||||||
height = skBmp.Height;
|
|
||||||
using var rotated = new SKBitmap(new SKImageInfo(width, height, skBmp.ColorType));
|
|
||||||
using var canvas = new SKCanvas(rotated);
|
|
||||||
canvas.Scale(1, -1, 0, height / 2.0f);
|
|
||||||
canvas.DrawBitmap(skBmp, SKPoint.Empty);
|
|
||||||
canvas.Flush();
|
|
||||||
bm32bData = rotated.Bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BITMAPINFOHEADER struct for DIB.
|
|
||||||
const int hdrSize = 0x28;
|
|
||||||
var fullImage = new byte[hdrSize + 12 + bm32bData.Length];
|
|
||||||
//Int32 biSize;
|
|
||||||
WriteIntToByteArray(fullImage, 0x00, 4, true, hdrSize);
|
|
||||||
//Int32 biWidth;
|
|
||||||
WriteIntToByteArray(fullImage, 0x04, 4, true, (uint) width);
|
|
||||||
//Int32 biHeight;
|
|
||||||
WriteIntToByteArray(fullImage, 0x08, 4, true, (uint) height);
|
|
||||||
//Int16 biPlanes;
|
|
||||||
WriteIntToByteArray(fullImage, 0x0C, 2, true, 1);
|
|
||||||
//Int16 biBitCount;
|
|
||||||
WriteIntToByteArray(fullImage, 0x0E, 2, true, 32);
|
|
||||||
//BITMAPCOMPRESSION biCompression = BITMAPCOMPRESSION.BITFIELDS;
|
|
||||||
WriteIntToByteArray(fullImage, 0x10, 4, true, 3);
|
|
||||||
//Int32 biSizeImage;
|
|
||||||
WriteIntToByteArray(fullImage, 0x14, 4, true, (uint) bm32bData.Length);
|
|
||||||
// These are all 0. Since .net clears new arrays, don't bother writing them.
|
|
||||||
//Int32 biXPelsPerMeter = 0;
|
|
||||||
//Int32 biYPelsPerMeter = 0;
|
|
||||||
//Int32 biClrUsed = 0;
|
|
||||||
//Int32 biClrImportant = 0;
|
|
||||||
|
|
||||||
// The aforementioned "BITFIELDS": colour masks applied to the Int32 pixel value to get the R, G and B values.
|
|
||||||
WriteIntToByteArray(fullImage, hdrSize + 0, 4, true, 0x00FF0000);
|
|
||||||
WriteIntToByteArray(fullImage, hdrSize + 4, 4, true, 0x0000FF00);
|
|
||||||
WriteIntToByteArray(fullImage, hdrSize + 8, 4, true, 0x000000FF);
|
|
||||||
|
|
||||||
Unsafe.CopyBlockUnaligned(ref fullImage[hdrSize + 12], ref bm32bData[0], (uint) bm32bData.Length);
|
|
||||||
return fullImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static unsafe byte[] GetRawBytes(Bitmap bmp)
|
|
||||||
{
|
|
||||||
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
|
||||||
var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
|
||||||
var bytes = (uint) (Math.Abs(bmpData.Stride) * bmp.Height);
|
|
||||||
var buffer = new byte[bytes];
|
|
||||||
fixed (byte* pBuffer = buffer)
|
|
||||||
{
|
|
||||||
Unsafe.CopyBlockUnaligned(pBuffer, bmpData.Scan0.ToPointer(), bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
bmp.UnlockBits(bmpData);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void WriteIntToByteArray(byte[] data, int startIndex, int bytes, bool littleEndian, uint value)
|
|
||||||
{
|
|
||||||
var lastByte = bytes - 1;
|
|
||||||
|
|
||||||
if (data.Length < startIndex + bytes)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(startIndex), "Data array is too small to write a " + bytes + "-byte value at offset " + startIndex + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var index = 0; index < bytes; index++)
|
|
||||||
{
|
|
||||||
var offs = startIndex + (littleEndian ? index : lastByte - index);
|
|
||||||
data[offs] = (byte) (value >> 8 * index & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateHTMLFragment(string html)
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
const string header = "Version:0.9\r\nStartHTML:<<<<<<<<<1\r\nEndHTML:<<<<<<<<<2\r\nStartFragment:<<<<<<<<<3\r\nEndFragment:<<<<<<<<<4\r\n";
|
|
||||||
const string startHTML = "<html>\r\n<body>\r\n";
|
|
||||||
const string startFragment = "<!--StartFragment-->";
|
|
||||||
const string endFragment = "<!--EndFragment-->";
|
|
||||||
const string endHTML = "\r\n</body>\r\n</html>";
|
|
||||||
|
|
||||||
sb.Append(header);
|
|
||||||
|
|
||||||
var startHTMLLength = header.Length;
|
|
||||||
var startFragmentLength = startHTMLLength + startHTML.Length + startFragment.Length;
|
|
||||||
var endFragmentLength = startFragmentLength + Encoding.UTF8.GetByteCount(html);
|
|
||||||
var endHTMLLength = endFragmentLength + endFragment.Length + endHTML.Length;
|
|
||||||
|
|
||||||
sb.Replace("<<<<<<<<<1", startHTMLLength.ToString("D10"));
|
|
||||||
sb.Replace("<<<<<<<<<2", endHTMLLength.ToString("D10"));
|
|
||||||
sb.Replace("<<<<<<<<<3", startFragmentLength.ToString("D10"));
|
|
||||||
sb.Replace("<<<<<<<<<4", endFragmentLength.ToString("D10"));
|
|
||||||
|
|
||||||
sb.Append(startHTML);
|
|
||||||
sb.Append(startFragment);
|
|
||||||
sb.Append(html);
|
|
||||||
sb.Append(endFragment);
|
|
||||||
sb.Append(endHTML);
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace FModel.Extensions;
|
namespace FModel.Extensions
|
||||||
|
{
|
||||||
public static class CollectionExtensions
|
public static class CollectionExtensions
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|
@ -34,3 +34,4 @@ public static class CollectionExtensions
|
||||||
return i < 0 ? collection.Last() : collection[i];
|
return i < 0 ? collection.Last() : collection[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
using FModel.Properties;
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Resources;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace FModel.Extensions;
|
namespace FModel.Extensions
|
||||||
|
{
|
||||||
public static class EnumExtensions
|
public static class EnumExtensions
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|
@ -11,25 +13,47 @@ public static class EnumExtensions
|
||||||
{
|
{
|
||||||
var fi = value.GetType().GetField(value.ToString());
|
var fi = value.GetType().GetField(value.ToString());
|
||||||
if (fi == null) return $"{value} ({value:D})";
|
if (fi == null) return $"{value} ({value:D})";
|
||||||
|
|
||||||
var attributes = (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
var attributes = (DescriptionAttribute[]) fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||||
if (attributes.Length > 0) return attributes[0].Description;
|
return attributes.Length > 0 ? attributes[0].Description : $"{value} ({value:D})";
|
||||||
|
|
||||||
|
|
||||||
var suffix = $"{value:D}";
|
|
||||||
var current = Convert.ToInt32(suffix);
|
|
||||||
var target = current & ~0xF;
|
|
||||||
if (current != target)
|
|
||||||
{
|
|
||||||
var values = Enum.GetValues(value.GetType());
|
|
||||||
var index = Array.IndexOf(values, value);
|
|
||||||
suffix = values.GetValue(index - (current - target))?.ToString();
|
|
||||||
}
|
|
||||||
return $"{value} ({suffix})";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T ToEnum<T>(this string value, T defaultValue) where T : struct => !Enum.TryParse(value, true, out T ret) ? defaultValue : ret;
|
public static string GetLocalizedDescription(this Enum value) => value.GetLocalizedDescription(Resources.ResourceManager);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static string GetLocalizedDescription(this Enum value, ResourceManager resourceManager)
|
||||||
|
{
|
||||||
|
var resourceName = value.GetType().Name + "_" + value;
|
||||||
|
var description = resourceManager.GetString(resourceName);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(description))
|
||||||
|
{
|
||||||
|
description = value.GetDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static string GetLocalizedCategory(this Enum value) => value.GetLocalizedCategory(Resources.ResourceManager);
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static string GetLocalizedCategory(this Enum value, ResourceManager resourceManager)
|
||||||
|
{
|
||||||
|
var resourceName = value.GetType().Name + "_" + value + "_Category";
|
||||||
|
var description = resourceManager.GetString(resourceName);
|
||||||
|
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static T ToEnum<T>(this string value, T defaultValue)
|
||||||
|
{
|
||||||
|
if (!Enum.TryParse(typeof(T), value, true, out var ret))
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
return (T) ret;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool HasAnyFlags<T>(this T flags, T contains) where T : Enum, IConvertible => (flags.ToInt32(null) & contains.ToInt32(null)) != 0;
|
public static bool HasAnyFlags<T>(this T flags, T contains) where T : Enum, IConvertible => (flags.ToInt32(null) & contains.ToInt32(null)) != 0;
|
||||||
|
|
@ -57,3 +81,4 @@ public static class EnumExtensions
|
||||||
return i == -1 ? (T) values.GetValue(values.Length - 1) : (T) values.GetValue(i);
|
return i == -1 ? (T) values.GetValue(values.Length - 1) : (T) values.GetValue(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace FModel.Extensions;
|
namespace FModel.Extensions
|
||||||
|
{
|
||||||
public enum Endianness
|
public enum Endianness
|
||||||
{
|
{
|
||||||
LittleEndian,
|
LittleEndian,
|
||||||
BigEndian
|
BigEndian,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StreamExtensions
|
public static class StreamExtensions
|
||||||
|
|
@ -28,3 +28,4 @@ public static class StreamExtensions
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using ICSharpCode.AvalonEdit.Document;
|
|
||||||
|
|
||||||
namespace FModel.Extensions;
|
|
||||||
|
|
||||||
|
namespace FModel.Extensions
|
||||||
|
{
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|
@ -95,7 +93,7 @@ public static class StringExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetNameLineNumber(this string s, string lineToFind)
|
public static int GetLineNumber(this string s, string lineToFind)
|
||||||
{
|
{
|
||||||
if (int.TryParse(lineToFind, out var index))
|
if (int.TryParse(lineToFind, out var index))
|
||||||
return s.GetLineNumber(index);
|
return s.GetLineNumber(index);
|
||||||
|
|
@ -114,56 +112,6 @@ public static class StringExtensions
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static string GetParentExportType(this TextDocument doc, int startOffset)
|
|
||||||
{
|
|
||||||
var line = doc.GetLineByOffset(startOffset);
|
|
||||||
var lineNumber = line.LineNumber - 1;
|
|
||||||
|
|
||||||
while (doc.GetText(line.Offset, line.Length) is { } content)
|
|
||||||
{
|
|
||||||
if (content.StartsWith(" \"Type\": \"", StringComparison.OrdinalIgnoreCase))
|
|
||||||
return content.Split("\"")[3];
|
|
||||||
|
|
||||||
lineNumber--;
|
|
||||||
if (lineNumber < 1) break;
|
|
||||||
line = doc.GetLineByNumber(lineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int GetKismetLineNumber(this string s, string input)
|
|
||||||
{
|
|
||||||
var match = Regex.Match(input, @"^(.+)\[(\d+)\]$");
|
|
||||||
var name = match.Groups[1].Value;
|
|
||||||
int index = int.Parse(match.Groups[2].Value);
|
|
||||||
var lineToFind = $" \"Name\": \"{name}\",";
|
|
||||||
var offset = $"\"StatementIndex\": {index}";
|
|
||||||
using var reader = new StringReader(s);
|
|
||||||
var lineNum = 0;
|
|
||||||
string line;
|
|
||||||
|
|
||||||
while ((line = reader.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
lineNum++;
|
|
||||||
if (line.Equals(lineToFind, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var objectLine = lineNum;
|
|
||||||
while ((line = reader.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
lineNum++;
|
|
||||||
if (line.Contains(offset, StringComparison.OrdinalIgnoreCase))
|
|
||||||
return lineNum;
|
|
||||||
}
|
|
||||||
return objectLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetLineNumber(this string s, int index)
|
private static int GetLineNumber(this string s, int index)
|
||||||
{
|
{
|
||||||
|
|
@ -183,3 +131,4 @@ public static class StringExtensions
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,18 +2,17 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net5.0-windows</TargetFramework>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<ApplicationIcon>FModel.ico</ApplicationIcon>
|
<ApplicationIcon>FModel.ico</ApplicationIcon>
|
||||||
<Version>4.4.4.0</Version>
|
<Version>4.0.0</Version>
|
||||||
<AssemblyVersion>4.4.4.0</AssemblyVersion>
|
<AssemblyVersion>4.0.0.0</AssemblyVersion>
|
||||||
<FileVersion>4.4.4.0</FileVersion>
|
<FileVersion>4.0.0.0</FileVersion>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<IsPublishable>true</IsPublishable>
|
<IsPublishable>true</IsPublishable>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<PublishSingleFile Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">true</PublishSingleFile>
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||||
<StartupObject>FModel.App</StartupObject>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
|
@ -39,18 +38,11 @@
|
||||||
<None Remove="Resources\fallenorder.png" />
|
<None Remove="Resources\fallenorder.png" />
|
||||||
<None Remove="Resources\FModel.ico" />
|
<None Remove="Resources\FModel.ico" />
|
||||||
<None Remove="Resources\folder.png" />
|
<None Remove="Resources\folder.png" />
|
||||||
<None Remove="Resources\label.png" />
|
|
||||||
<None Remove="Resources\fortnite.png" />
|
<None Remove="Resources\fortnite.png" />
|
||||||
<None Remove="Resources\fortnitebr.png" />
|
<None Remove="Resources\fortnitebr.png" />
|
||||||
<None Remove="Resources\gear.png" />
|
<None Remove="Resources\gear.png" />
|
||||||
<None Remove="Resources\localization.png" />
|
<None Remove="Resources\localization.png" />
|
||||||
<None Remove="Resources\materialicon.png" />
|
<None Remove="Resources\materialicon.png" />
|
||||||
<None Remove="Resources\square.png" />
|
|
||||||
<None Remove="Resources\square_off.png" />
|
|
||||||
<None Remove="Resources\cube.png" />
|
|
||||||
<None Remove="Resources\cube_off.png" />
|
|
||||||
<None Remove="Resources\light.png" />
|
|
||||||
<None Remove="Resources\light_off.png" />
|
|
||||||
<None Remove="Resources\pc.png" />
|
<None Remove="Resources\pc.png" />
|
||||||
<None Remove="Resources\puzzle.png" />
|
<None Remove="Resources\puzzle.png" />
|
||||||
<None Remove="Resources\roguecompany.png" />
|
<None Remove="Resources\roguecompany.png" />
|
||||||
|
|
@ -75,20 +67,18 @@
|
||||||
<None Remove="Resources\athena.png" />
|
<None Remove="Resources\athena.png" />
|
||||||
<None Remove="Resources\Json.xshd" />
|
<None Remove="Resources\Json.xshd" />
|
||||||
<None Remove="Resources\Ini.xshd" />
|
<None Remove="Resources\Ini.xshd" />
|
||||||
<None Remove="Resources\Verse.xshd" />
|
|
||||||
<None Remove="Resources\Xml.xshd" />
|
<None Remove="Resources\Xml.xshd" />
|
||||||
<None Remove="Resources\Cpp.xshd" />
|
<None Remove="Resources\Cpp.xshd" />
|
||||||
<None Remove="Resources\Changelog.xshd" />
|
|
||||||
<None Remove="Resources\unix.png" />
|
<None Remove="Resources\unix.png" />
|
||||||
<None Remove="Resources\linux.png" />
|
<None Remove="Resources\linux.png" />
|
||||||
<None Remove="Resources\stateofdecay2.png" />
|
|
||||||
<None Remove="Resources\T_Placeholder_Item_Image.png" />
|
<None Remove="Resources\T_Placeholder_Item_Image.png" />
|
||||||
<None Remove="Resources\checker.png" />
|
|
||||||
<None Remove="Resources\T_ClipSize_Weapon_Stats.png" />
|
<None Remove="Resources\T_ClipSize_Weapon_Stats.png" />
|
||||||
<None Remove="Resources\T_DamagePerBullet_Weapon_Stats.png" />
|
<None Remove="Resources\T_DamagePerBullet_Weapon_Stats.png" />
|
||||||
<None Remove="Resources\T_ReloadTime_Weapon_Stats.png" />
|
<None Remove="Resources\T_ReloadTime_Weapon_Stats.png" />
|
||||||
<None Remove="Resources\T-Icon-Pets-64.png" />
|
<None Remove="Resources\T-Icon-Pets-64.png" />
|
||||||
<None Remove="Resources\T-Icon-Quests-64.png" />
|
<None Remove="Resources\T-Icon-Quests-64.png" />
|
||||||
|
<None Remove="Resources\city_pin.png" />
|
||||||
|
<None Remove="Resources\pin.png" />
|
||||||
<None Remove="Resources\Default.png" />
|
<None Remove="Resources\Default.png" />
|
||||||
<None Remove="Resources\NoBackground.png" />
|
<None Remove="Resources\NoBackground.png" />
|
||||||
<None Remove="Resources\NoText.png" />
|
<None Remove="Resources\NoText.png" />
|
||||||
|
|
@ -99,76 +89,36 @@
|
||||||
<None Remove="Resources\delete.png" />
|
<None Remove="Resources\delete.png" />
|
||||||
<None Remove="Resources\edit.png" />
|
<None Remove="Resources\edit.png" />
|
||||||
<None Remove="Resources\go_to_directory.png" />
|
<None Remove="Resources\go_to_directory.png" />
|
||||||
<None Remove="Resources\npcleftside.png" />
|
|
||||||
<None Remove="Resources\default.frag" />
|
|
||||||
<None Remove="Resources\default.vert" />
|
|
||||||
<None Remove="Resources\grid.frag" />
|
|
||||||
<None Remove="Resources\grid.vert" />
|
|
||||||
<None Remove="Resources\skybox.frag" />
|
|
||||||
<None Remove="Resources\skybox.vert" />
|
|
||||||
<None Remove="Resources\framebuffer.frag" />
|
|
||||||
<None Remove="Resources\framebuffer.vert" />
|
|
||||||
<None Remove="Resources\outline.frag" />
|
|
||||||
<None Remove="Resources\outline.vert" />
|
|
||||||
<None Remove="Resources\picking.frag" />
|
|
||||||
<None Remove="Resources\picking.vert" />
|
|
||||||
<None Remove="Resources\light.frag" />
|
|
||||||
<None Remove="Resources\light.vert" />
|
|
||||||
<None Remove="Resources\bone.frag" />
|
|
||||||
<None Remove="Resources\bone.vert" />
|
|
||||||
<None Remove="Resources\collision.vert" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Resources\Json.xshd" />
|
<EmbeddedResource Include="Resources\Json.xshd" />
|
||||||
<EmbeddedResource Include="Resources\Ini.xshd" />
|
<EmbeddedResource Include="Resources\Ini.xshd" />
|
||||||
<EmbeddedResource Include="Resources\Verse.xshd" />
|
|
||||||
<EmbeddedResource Include="Resources\Xml.xshd" />
|
<EmbeddedResource Include="Resources\Xml.xshd" />
|
||||||
<EmbeddedResource Include="Resources\Cpp.xshd" />
|
<EmbeddedResource Include="Resources\Cpp.xshd" />
|
||||||
<EmbeddedResource Include="Resources\Changelog.xshd" />
|
|
||||||
<EmbeddedResource Include="Resources\default.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\default.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\grid.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\grid.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\skybox.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\skybox.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\framebuffer.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\framebuffer.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\outline.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\outline.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\picking.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\picking.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\light.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\light.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\bone.frag" />
|
|
||||||
<EmbeddedResource Include="Resources\bone.vert" />
|
|
||||||
<EmbeddedResource Include="Resources\collision.vert" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AdonisUI" Version="1.17.1" />
|
<PackageReference Include="AdonisUI.ClassicTheme.NET5" Version="1.17.1" />
|
||||||
<PackageReference Include="AdonisUI.ClassicTheme" Version="1.17.1" />
|
<PackageReference Include="AdonisUI.NET5" Version="1.17.1" />
|
||||||
<PackageReference Include="Autoupdater.NET.Official" Version="1.9.2" />
|
<PackageReference Include="Autoupdater.NET.Official" Version="1.6.4" />
|
||||||
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
|
<PackageReference Include="AvalonEdit" Version="6.0.1" />
|
||||||
<PackageReference Include="CSCore" Version="1.2.1.2" />
|
<PackageReference Include="CSCore" Version="1.2.1.2" />
|
||||||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
|
||||||
<PackageReference Include="EpicManifestParser" Version="2.3.3" />
|
<PackageReference Include="EpicManifestParser" Version="1.2.0" />
|
||||||
<PackageReference Include="ImGui.NET" Version="1.91.0.1" />
|
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.6" />
|
||||||
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.8" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="NVorbis" Version="0.10.1" />
|
||||||
<PackageReference Include="NVorbis" Version="0.10.5" />
|
<PackageReference Include="Ookii.Dialogs.Wpf" Version="3.1.0" />
|
||||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
<PackageReference Include="RestSharp" Version="106.11.7" />
|
||||||
<PackageReference Include="OpenTK" Version="4.8.2" />
|
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
|
||||||
<PackageReference Include="Serilog" Version="4.0.2" />
|
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.80.2" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
|
|
||||||
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.8" />
|
|
||||||
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CUE4Parse\CUE4Parse-Conversion\CUE4Parse-Conversion.csproj" />
|
<ProjectReference Include="..\CUE4Parse\CUE4Parse-Conversion\CUE4Parse-Conversion.csproj" />
|
||||||
|
<ProjectReference Include="..\CUE4Parse\CUE4Parse-Fortnite\CUE4Parse-Fortnite.csproj" />
|
||||||
<ProjectReference Include="..\CUE4Parse\CUE4Parse\CUE4Parse.csproj" />
|
<ProjectReference Include="..\CUE4Parse\CUE4Parse\CUE4Parse.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
@ -181,7 +131,6 @@
|
||||||
<Resource Include="Resources\fallenorder.png" />
|
<Resource Include="Resources\fallenorder.png" />
|
||||||
<Resource Include="Resources\FModel.ico" />
|
<Resource Include="Resources\FModel.ico" />
|
||||||
<Resource Include="Resources\folder.png" />
|
<Resource Include="Resources\folder.png" />
|
||||||
<Resource Include="Resources\label.png" />
|
|
||||||
<Resource Include="Resources\fortnite.png" />
|
<Resource Include="Resources\fortnite.png" />
|
||||||
<Resource Include="Resources\fortnitebr.png" />
|
<Resource Include="Resources\fortnitebr.png" />
|
||||||
<Resource Include="Resources\empty_folder.png" />
|
<Resource Include="Resources\empty_folder.png" />
|
||||||
|
|
@ -189,12 +138,6 @@
|
||||||
<Resource Include="Resources\gear.png" />
|
<Resource Include="Resources\gear.png" />
|
||||||
<Resource Include="Resources\localization.png" />
|
<Resource Include="Resources\localization.png" />
|
||||||
<Resource Include="Resources\materialicon.png" />
|
<Resource Include="Resources\materialicon.png" />
|
||||||
<Resource Include="Resources\square.png" />
|
|
||||||
<Resource Include="Resources\square_off.png" />
|
|
||||||
<Resource Include="Resources\cube.png" />
|
|
||||||
<Resource Include="Resources\cube_off.png" />
|
|
||||||
<Resource Include="Resources\light.png" />
|
|
||||||
<Resource Include="Resources\light_off.png" />
|
|
||||||
<Resource Include="Resources\pc.png" />
|
<Resource Include="Resources\pc.png" />
|
||||||
<Resource Include="Resources\puzzle.png" />
|
<Resource Include="Resources\puzzle.png" />
|
||||||
<Resource Include="Resources\roguecompany.png" />
|
<Resource Include="Resources\roguecompany.png" />
|
||||||
|
|
@ -219,14 +162,14 @@
|
||||||
<Resource Include="Resources\athena.png" />
|
<Resource Include="Resources\athena.png" />
|
||||||
<Resource Include="Resources\unix.png" />
|
<Resource Include="Resources\unix.png" />
|
||||||
<Resource Include="Resources\linux.png" />
|
<Resource Include="Resources\linux.png" />
|
||||||
<Resource Include="Resources\stateofdecay2.png" />
|
|
||||||
<Resource Include="Resources\T_Placeholder_Item_Image.png" />
|
<Resource Include="Resources\T_Placeholder_Item_Image.png" />
|
||||||
<Resource Include="Resources\checker.png" />
|
|
||||||
<Resource Include="Resources\T_ClipSize_Weapon_Stats.png" />
|
<Resource Include="Resources\T_ClipSize_Weapon_Stats.png" />
|
||||||
<Resource Include="Resources\T_DamagePerBullet_Weapon_Stats.png" />
|
<Resource Include="Resources\T_DamagePerBullet_Weapon_Stats.png" />
|
||||||
<Resource Include="Resources\T_ReloadTime_Weapon_Stats.png" />
|
<Resource Include="Resources\T_ReloadTime_Weapon_Stats.png" />
|
||||||
<Resource Include="Resources\T-Icon-Pets-64.png" />
|
<Resource Include="Resources\T-Icon-Pets-64.png" />
|
||||||
<Resource Include="Resources\T-Icon-Quests-64.png" />
|
<Resource Include="Resources\T-Icon-Quests-64.png" />
|
||||||
|
<Resource Include="Resources\city_pin.png" />
|
||||||
|
<Resource Include="Resources\pin.png" />
|
||||||
<Resource Include="Resources\Default.png" />
|
<Resource Include="Resources\Default.png" />
|
||||||
<Resource Include="Resources\NoBackground.png" />
|
<Resource Include="Resources\NoBackground.png" />
|
||||||
<Resource Include="Resources\NoText.png" />
|
<Resource Include="Resources\NoText.png" />
|
||||||
|
|
@ -237,24 +180,6 @@
|
||||||
<Resource Include="Resources\delete.png" />
|
<Resource Include="Resources\delete.png" />
|
||||||
<Resource Include="Resources\edit.png" />
|
<Resource Include="Resources\edit.png" />
|
||||||
<Resource Include="Resources\go_to_directory.png" />
|
<Resource Include="Resources\go_to_directory.png" />
|
||||||
<Resource Include="Resources\npcleftside.png" />
|
|
||||||
<Resource Include="Resources\nx.png" />
|
|
||||||
<Resource Include="Resources\ny.png" />
|
|
||||||
<Resource Include="Resources\nz.png" />
|
|
||||||
<Resource Include="Resources\px.png" />
|
|
||||||
<Resource Include="Resources\py.png" />
|
|
||||||
<Resource Include="Resources\pz.png" />
|
|
||||||
<Resource Include="Resources\pointlight.png" />
|
|
||||||
<Resource Include="Resources\spotlight.png" />
|
|
||||||
<Resource Include="Resources\link_on.png" />
|
|
||||||
<Resource Include="Resources\link_off.png" />
|
|
||||||
<Resource Include="Resources\link_has.png" />
|
|
||||||
<Resource Include="Resources\tl_play.png" />
|
|
||||||
<Resource Include="Resources\tl_pause.png" />
|
|
||||||
<Resource Include="Resources\tl_rewind.png" />
|
|
||||||
<Resource Include="Resources\tl_forward.png" />
|
|
||||||
<Resource Include="Resources\tl_previous.png" />
|
|
||||||
<Resource Include="Resources\tl_next.png" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 17.0.31912.275
|
VisualStudioVersion = 16.0.30804.86
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FModel", "FModel.csproj", "{B1F494EA-90A6-4C24-800E-2F724A1884CA}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FModel", "FModel.csproj", "{B1F494EA-90A6-4C24-800E-2F724A1884CA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUE4Parse", "..\CUE4Parse\CUE4Parse\CUE4Parse.csproj", "{C4620341-BBB7-4384-AC7D-5082D3E0386E}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUE4Parse", "..\CUE4Parse\CUE4Parse\CUE4Parse.csproj", "{C4620341-BBB7-4384-AC7D-5082D3E0386E}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUE4Parse-Fortnite", "..\CUE4Parse\CUE4Parse-Fortnite\CUE4Parse-Fortnite.csproj", "{7765FB4C-B54D-427B-ABB6-1073687E56BD}"
|
||||||
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUE4Parse-Conversion", "..\CUE4Parse\CUE4Parse-Conversion\CUE4Parse-Conversion.csproj", "{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CUE4Parse-Conversion", "..\CUE4Parse\CUE4Parse-Conversion\CUE4Parse-Conversion.csproj", "{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
|
|
@ -23,6 +25,10 @@ Global
|
||||||
{C4620341-BBB7-4384-AC7D-5082D3E0386E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C4620341-BBB7-4384-AC7D-5082D3E0386E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C4620341-BBB7-4384-AC7D-5082D3E0386E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C4620341-BBB7-4384-AC7D-5082D3E0386E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C4620341-BBB7-4384-AC7D-5082D3E0386E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C4620341-BBB7-4384-AC7D-5082D3E0386E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7765FB4C-B54D-427B-ABB6-1073687E56BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7765FB4C-B54D-427B-ABB6-1073687E56BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7765FB4C-B54D-427B-ABB6-1073687E56BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7765FB4C-B54D-427B-ABB6-1073687E56BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D0E1E8F7-F56D-469A-8E24-C2439B9FFD83}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks.Dataflow;
|
using System.Threading.Tasks.Dataflow;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public class AsyncQueue<T> : IAsyncEnumerable<T>
|
public class AsyncQueue<T> : IAsyncEnumerable<T>
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _semaphore = new(1);
|
private readonly SemaphoreSlim _semaphore = new(1);
|
||||||
|
|
@ -30,3 +30,4 @@ public class AsyncQueue<T> : IAsyncEnumerable<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public abstract class Command : ICommand
|
public abstract class Command : ICommand
|
||||||
{
|
{
|
||||||
public abstract void Execute(object parameter);
|
public abstract void Execute(object parameter);
|
||||||
|
|
@ -16,3 +16,4 @@ public abstract class Command : ICommand
|
||||||
|
|
||||||
public event EventHandler CanExecuteChanged;
|
public event EventHandler CanExecuteChanged;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,17 +4,19 @@ using SkiaSharp;
|
||||||
using SkiaSharp.HarfBuzz;
|
using SkiaSharp.HarfBuzz;
|
||||||
using Buffer = HarfBuzzSharp.Buffer;
|
using Buffer = HarfBuzzSharp.Buffer;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public class CustomSKShaper : SKShaper
|
public class CustomSKShaper : SKShaper
|
||||||
{
|
{
|
||||||
private const int _FONT_SIZE_SCALE = 512;
|
private const int _FONT_SIZE_SCALE = 512;
|
||||||
private readonly Font _font;
|
private readonly Font _font;
|
||||||
|
private readonly Buffer _buffer;
|
||||||
|
|
||||||
public CustomSKShaper(SKTypeface typeface) : base(typeface)
|
public CustomSKShaper(SKTypeface typeface) : base(typeface)
|
||||||
{
|
{
|
||||||
using var blob = Typeface.OpenStream(out var index).ToHarfBuzzBlob();
|
using (var blob = Typeface.OpenStream(out var index).ToHarfBuzzBlob())
|
||||||
using var face = new Face(blob, index);
|
using (var face = new Face(blob, index))
|
||||||
|
{
|
||||||
face.Index = index;
|
face.Index = index;
|
||||||
face.UnitsPerEm = Typeface.UnitsPerEm;
|
face.UnitsPerEm = Typeface.UnitsPerEm;
|
||||||
|
|
||||||
|
|
@ -23,6 +25,9 @@ public class CustomSKShaper : SKShaper
|
||||||
_font.SetFunctionsOpenType();
|
_font.SetFunctionsOpenType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_buffer = new Buffer();
|
||||||
|
}
|
||||||
|
|
||||||
public new Result Shape(Buffer buffer, float xOffset, float yOffset, SKPaint paint)
|
public new Result Shape(Buffer buffer, float xOffset, float yOffset, SKPaint paint)
|
||||||
{
|
{
|
||||||
if (buffer == null)
|
if (buffer == null)
|
||||||
|
|
@ -58,7 +63,7 @@ public class CustomSKShaper : SKShaper
|
||||||
points[i] = new SKPoint(xOffset + pos[i].XOffset * textSizeX, yOffset - pos[i].YOffset * textSizeY);
|
points[i] = new SKPoint(xOffset + pos[i].XOffset * textSizeX, yOffset - pos[i].YOffset * textSizeY);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Result(codepoints, clusters, points, points[^1].X);
|
return new Result(codepoints, clusters, points);
|
||||||
}
|
}
|
||||||
|
|
||||||
public new Result Shape(string text, SKPaint paint) => Shape(text, 0, 0, paint);
|
public new Result Shape(string text, SKPaint paint) => Shape(text, 0, 0, paint);
|
||||||
|
|
@ -88,3 +93,4 @@ public class CustomSKShaper : SKShaper
|
||||||
return Shape(buffer, xOffset, yOffset, paint);
|
return Shape(buffer, xOffset, yOffset, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
using System;
|
|
||||||
using RestSharp;
|
|
||||||
|
|
||||||
namespace FModel.Framework;
|
|
||||||
|
|
||||||
public class FRestRequest : RestRequest
|
|
||||||
{
|
|
||||||
private const int TimeoutSeconds = 5;
|
|
||||||
|
|
||||||
public FRestRequest(string url, Method method = Method.Get) : base(url, method)
|
|
||||||
{
|
|
||||||
Timeout = TimeSpan.FromSeconds(TimeoutSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FRestRequest(Uri uri, Method method = Method.Get) : base(uri, method)
|
|
||||||
{
|
|
||||||
Timeout = TimeSpan.FromSeconds(TimeoutSeconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
namespace FModel.Framework;
|
|
||||||
|
|
||||||
public class FStatus : ViewModel
|
|
||||||
{
|
|
||||||
private bool _isReady;
|
|
||||||
public bool IsReady
|
|
||||||
{
|
|
||||||
get => _isReady;
|
|
||||||
private set => SetProperty(ref _isReady, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private EStatusKind _kind;
|
|
||||||
public EStatusKind Kind
|
|
||||||
{
|
|
||||||
get => _kind;
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
SetProperty(ref _kind, value);
|
|
||||||
IsReady = Kind != EStatusKind.Loading && Kind != EStatusKind.Stopping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string _label;
|
|
||||||
public string Label
|
|
||||||
{
|
|
||||||
get => _label;
|
|
||||||
private set => SetProperty(ref _label, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FStatus()
|
|
||||||
{
|
|
||||||
SetStatus(EStatusKind.Loading);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStatus(EStatusKind kind, string label = "")
|
|
||||||
{
|
|
||||||
Kind = kind;
|
|
||||||
UpdateStatusLabel(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateStatusLabel(string label, string prefix = null)
|
|
||||||
{
|
|
||||||
Label = Kind == EStatusKind.Loading ? $"{prefix ?? Kind.ToString()} {label}".Trim() : Kind.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,8 +4,8 @@ using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public class FullyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
|
public class FullyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -66,7 +66,7 @@ public class FullyObservableCollection<T> : ObservableCollection<T> where T : IN
|
||||||
|
|
||||||
private void ObserveAll()
|
private void ObserveAll()
|
||||||
{
|
{
|
||||||
foreach (var item in Items)
|
foreach (T item in Items)
|
||||||
item.PropertyChanged += ChildPropertyChanged;
|
item.PropertyChanged += ChildPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,3 +114,4 @@ public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public class Hotkey : ViewModel
|
public class Hotkey : ViewModel
|
||||||
{
|
{
|
||||||
private Key _key;
|
private Key _key;
|
||||||
|
|
@ -47,3 +47,4 @@ public class Hotkey : ViewModel
|
||||||
return str.ToString();
|
return str.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,608 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using FModel.Settings;
|
|
||||||
using ImGuiNET;
|
|
||||||
using OpenTK.Graphics.OpenGL4;
|
|
||||||
using OpenTK.Windowing.Desktop;
|
|
||||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
|
||||||
using ErrorCode = OpenTK.Graphics.OpenGL4.ErrorCode;
|
|
||||||
using Keys = OpenTK.Windowing.GraphicsLibraryFramework.Keys;
|
|
||||||
|
|
||||||
namespace FModel.Framework;
|
|
||||||
|
|
||||||
public class ImGuiController : IDisposable
|
|
||||||
{
|
|
||||||
private bool _frameBegun;
|
|
||||||
|
|
||||||
private int _vertexArray;
|
|
||||||
private int _vertexBuffer;
|
|
||||||
private int _vertexBufferSize;
|
|
||||||
private int _indexBuffer;
|
|
||||||
private int _indexBufferSize;
|
|
||||||
|
|
||||||
//private Texture _fontTexture;
|
|
||||||
|
|
||||||
private int _fontTexture;
|
|
||||||
|
|
||||||
private int _shader;
|
|
||||||
private int _shaderFontTextureLocation;
|
|
||||||
private int _shaderProjectionMatrixLocation;
|
|
||||||
|
|
||||||
private int _windowWidth;
|
|
||||||
private int _windowHeight;
|
|
||||||
|
|
||||||
public ImFontPtr FontNormal;
|
|
||||||
public ImFontPtr FontBold;
|
|
||||||
public ImFontPtr FontSemiBold;
|
|
||||||
|
|
||||||
private readonly Vector2 _scaleFactor = Vector2.One;
|
|
||||||
public readonly float DpiScale = GetDpiScale();
|
|
||||||
|
|
||||||
private static bool KHRDebugAvailable = false;
|
|
||||||
|
|
||||||
public ImGuiController(int width, int height)
|
|
||||||
{
|
|
||||||
_windowWidth = width;
|
|
||||||
_windowHeight = height;
|
|
||||||
|
|
||||||
int major = GL.GetInteger(GetPName.MajorVersion);
|
|
||||||
int minor = GL.GetInteger(GetPName.MinorVersion);
|
|
||||||
|
|
||||||
KHRDebugAvailable = (major == 4 && minor >= 3) || IsExtensionSupported("KHR_debug");
|
|
||||||
|
|
||||||
IntPtr context = ImGui.CreateContext();
|
|
||||||
ImGui.SetCurrentContext(context);
|
|
||||||
|
|
||||||
var io = ImGui.GetIO();
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
var iniFileNamePtr = Marshal.StringToCoTaskMemUTF8(Path.Combine(UserSettings.Default.OutputDirectory, ".data", "imgui.ini"));
|
|
||||||
io.NativePtr->IniFilename = (byte*)iniFileNamePtr;
|
|
||||||
}
|
|
||||||
FontNormal = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeui.ttf", 16 * DpiScale);
|
|
||||||
FontBold = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeuib.ttf", 16 * DpiScale);
|
|
||||||
FontSemiBold = io.Fonts.AddFontFromFileTTF("C:\\Windows\\Fonts\\seguisb.ttf", 16 * DpiScale);
|
|
||||||
|
|
||||||
io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset;
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard;
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags.DockingEnable;
|
|
||||||
io.Fonts.Flags |= ImFontAtlasFlags.NoBakedLines;
|
|
||||||
|
|
||||||
CreateDeviceResources();
|
|
||||||
|
|
||||||
SetPerFrameImGuiData(1f / 60f);
|
|
||||||
|
|
||||||
ImGui.NewFrame();
|
|
||||||
_frameBegun = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Bold() => PushFont(FontBold);
|
|
||||||
public void SemiBold() => PushFont(FontSemiBold);
|
|
||||||
|
|
||||||
public void PopFont()
|
|
||||||
{
|
|
||||||
ImGui.PopFont();
|
|
||||||
PushFont(FontNormal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PushFont(ImFontPtr ptr) => ImGui.PushFont(ptr);
|
|
||||||
|
|
||||||
public void WindowResized(int width, int height)
|
|
||||||
{
|
|
||||||
_windowWidth = width;
|
|
||||||
_windowHeight = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DestroyDeviceObjects()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CreateDeviceResources()
|
|
||||||
{
|
|
||||||
_vertexBufferSize = 10000;
|
|
||||||
_indexBufferSize = 2000;
|
|
||||||
|
|
||||||
int prevVAO = GL.GetInteger(GetPName.VertexArrayBinding);
|
|
||||||
int prevArrayBuffer = GL.GetInteger(GetPName.ArrayBufferBinding);
|
|
||||||
|
|
||||||
_vertexArray = GL.GenVertexArray();
|
|
||||||
GL.BindVertexArray(_vertexArray);
|
|
||||||
LabelObject(ObjectLabelIdentifier.VertexArray, _vertexArray, "ImGui");
|
|
||||||
|
|
||||||
_vertexBuffer = GL.GenBuffer();
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffer);
|
|
||||||
LabelObject(ObjectLabelIdentifier.Buffer, _vertexBuffer, "VBO: ImGui");
|
|
||||||
GL.BufferData(BufferTarget.ArrayBuffer, _vertexBufferSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
|
|
||||||
|
|
||||||
_indexBuffer = GL.GenBuffer();
|
|
||||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer);
|
|
||||||
LabelObject(ObjectLabelIdentifier.Buffer, _indexBuffer, "EBO: ImGui");
|
|
||||||
GL.BufferData(BufferTarget.ElementArrayBuffer, _indexBufferSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
|
|
||||||
|
|
||||||
RecreateFontDeviceTexture();
|
|
||||||
|
|
||||||
string VertexSource = @"#version 460 core
|
|
||||||
uniform mat4 projection_matrix;
|
|
||||||
layout(location = 0) in vec2 in_position;
|
|
||||||
layout(location = 1) in vec2 in_texCoord;
|
|
||||||
layout(location = 2) in vec4 in_color;
|
|
||||||
out vec4 color;
|
|
||||||
out vec2 texCoord;
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = projection_matrix * vec4(in_position, 0, 1);
|
|
||||||
color = in_color;
|
|
||||||
texCoord = in_texCoord;
|
|
||||||
}";
|
|
||||||
string FragmentSource = @"#version 460 core
|
|
||||||
uniform sampler2D in_fontTexture;
|
|
||||||
in vec4 color;
|
|
||||||
in vec2 texCoord;
|
|
||||||
out vec4 outputColor;
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
outputColor = color * texture(in_fontTexture, texCoord);
|
|
||||||
}";
|
|
||||||
|
|
||||||
_shader = CreateProgram("ImGui", VertexSource, FragmentSource);
|
|
||||||
_shaderProjectionMatrixLocation = GL.GetUniformLocation(_shader, "projection_matrix");
|
|
||||||
_shaderFontTextureLocation = GL.GetUniformLocation(_shader, "in_fontTexture");
|
|
||||||
|
|
||||||
int stride = Unsafe.SizeOf<ImDrawVert>();
|
|
||||||
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, stride, 0);
|
|
||||||
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, stride, 8);
|
|
||||||
GL.VertexAttribPointer(2, 4, VertexAttribPointerType.UnsignedByte, true, stride, 16);
|
|
||||||
|
|
||||||
GL.EnableVertexAttribArray(0);
|
|
||||||
GL.EnableVertexAttribArray(1);
|
|
||||||
GL.EnableVertexAttribArray(2);
|
|
||||||
|
|
||||||
GL.BindVertexArray(prevVAO);
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, prevArrayBuffer);
|
|
||||||
|
|
||||||
CheckGLError("End of ImGui setup");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recreates the device texture used to render text.
|
|
||||||
/// </summary>
|
|
||||||
public void RecreateFontDeviceTexture()
|
|
||||||
{
|
|
||||||
ImGuiIOPtr io = ImGui.GetIO();
|
|
||||||
io.Fonts.GetTexDataAsRGBA32(out IntPtr pixels, out int width, out int height, out int bytesPerPixel);
|
|
||||||
|
|
||||||
int mips = (int)Math.Floor(Math.Log(Math.Max(width, height), 2));
|
|
||||||
|
|
||||||
int prevActiveTexture = GL.GetInteger(GetPName.ActiveTexture);
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
|
||||||
int prevTexture2D = GL.GetInteger(GetPName.TextureBinding2D);
|
|
||||||
|
|
||||||
_fontTexture = GL.GenTexture();
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, _fontTexture);
|
|
||||||
GL.TexStorage2D(TextureTarget2d.Texture2D, mips, SizedInternalFormat.Rgba8, width, height);
|
|
||||||
LabelObject(ObjectLabelIdentifier.Texture, _fontTexture, "ImGui Text Atlas");
|
|
||||||
|
|
||||||
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, width, height, PixelFormat.Bgra, PixelType.UnsignedByte, pixels);
|
|
||||||
|
|
||||||
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
|
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, mips - 1);
|
|
||||||
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
|
||||||
|
|
||||||
// Restore state
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, prevTexture2D);
|
|
||||||
GL.ActiveTexture((TextureUnit)prevActiveTexture);
|
|
||||||
|
|
||||||
io.Fonts.SetTexID((IntPtr)_fontTexture);
|
|
||||||
|
|
||||||
io.Fonts.ClearTexData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Renders the ImGui draw list data.
|
|
||||||
/// </summary>
|
|
||||||
public void Render()
|
|
||||||
{
|
|
||||||
if (_frameBegun)
|
|
||||||
{
|
|
||||||
_frameBegun = false;
|
|
||||||
ImGui.Render();
|
|
||||||
RenderImDrawData(ImGui.GetDrawData());
|
|
||||||
}
|
|
||||||
CheckGLError("End of frame");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates ImGui input and IO configuration state.
|
|
||||||
/// </summary>
|
|
||||||
public void Update(GameWindow wnd, float deltaSeconds)
|
|
||||||
{
|
|
||||||
if (_frameBegun)
|
|
||||||
{
|
|
||||||
ImGui.Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
SetPerFrameImGuiData(deltaSeconds);
|
|
||||||
UpdateImGuiInput(wnd);
|
|
||||||
|
|
||||||
_frameBegun = true;
|
|
||||||
ImGui.NewFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets per-frame data based on the associated window.
|
|
||||||
/// This is called by Update(float).
|
|
||||||
/// </summary>
|
|
||||||
private void SetPerFrameImGuiData(float deltaSeconds)
|
|
||||||
{
|
|
||||||
ImGuiIOPtr io = ImGui.GetIO();
|
|
||||||
// if (io.WantSaveIniSettings) ImGui.SaveIniSettingsToDisk(_iniPath);
|
|
||||||
io.DisplaySize = new Vector2(
|
|
||||||
_windowWidth / _scaleFactor.X,
|
|
||||||
_windowHeight / _scaleFactor.Y);
|
|
||||||
io.DisplayFramebufferScale = _scaleFactor;
|
|
||||||
io.DeltaTime = deltaSeconds; // DeltaTime is in seconds.
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly List<char> PressedChars = new List<char>();
|
|
||||||
|
|
||||||
private void UpdateImGuiInput(GameWindow wnd)
|
|
||||||
{
|
|
||||||
ImGuiIOPtr io = ImGui.GetIO();
|
|
||||||
var mState = wnd.MouseState;
|
|
||||||
var kState = wnd.KeyboardState;
|
|
||||||
|
|
||||||
io.AddMousePosEvent(mState.X, mState.Y);
|
|
||||||
io.AddMouseButtonEvent(0, mState[MouseButton.Left]);
|
|
||||||
io.AddMouseButtonEvent(1, mState[MouseButton.Right]);
|
|
||||||
io.AddMouseButtonEvent(2, mState[MouseButton.Middle]);
|
|
||||||
io.AddMouseButtonEvent(3, mState[MouseButton.Button1]);
|
|
||||||
io.AddMouseButtonEvent(4, mState[MouseButton.Button2]);
|
|
||||||
io.AddMouseWheelEvent(mState.ScrollDelta.X, mState.ScrollDelta.Y);
|
|
||||||
|
|
||||||
foreach (Keys key in Enum.GetValues(typeof(Keys)))
|
|
||||||
{
|
|
||||||
if (key == Keys.Unknown) continue;
|
|
||||||
io.AddKeyEvent(TranslateKey(key), kState.IsKeyDown(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var c in PressedChars)
|
|
||||||
{
|
|
||||||
io.AddInputCharacter(c);
|
|
||||||
}
|
|
||||||
PressedChars.Clear();
|
|
||||||
|
|
||||||
io.KeyShift = kState.IsKeyDown(Keys.LeftShift) || kState.IsKeyDown(Keys.RightShift);
|
|
||||||
io.KeyCtrl = kState.IsKeyDown(Keys.LeftControl) || kState.IsKeyDown(Keys.RightControl);
|
|
||||||
io.KeyAlt = kState.IsKeyDown(Keys.LeftAlt) || kState.IsKeyDown(Keys.RightAlt);
|
|
||||||
io.KeySuper = kState.IsKeyDown(Keys.LeftSuper) || kState.IsKeyDown(Keys.RightSuper);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PressChar(char keyChar)
|
|
||||||
{
|
|
||||||
PressedChars.Add(keyChar);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RenderImDrawData(ImDrawDataPtr draw_data)
|
|
||||||
{
|
|
||||||
if (draw_data.CmdListsCount == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get intial state.
|
|
||||||
int prevVAO = GL.GetInteger(GetPName.VertexArrayBinding);
|
|
||||||
int prevArrayBuffer = GL.GetInteger(GetPName.ArrayBufferBinding);
|
|
||||||
int prevProgram = GL.GetInteger(GetPName.CurrentProgram);
|
|
||||||
bool prevBlendEnabled = GL.GetBoolean(GetPName.Blend);
|
|
||||||
bool prevScissorTestEnabled = GL.GetBoolean(GetPName.ScissorTest);
|
|
||||||
int prevBlendEquationRgb = GL.GetInteger(GetPName.BlendEquationRgb);
|
|
||||||
int prevBlendEquationAlpha = GL.GetInteger(GetPName.BlendEquationAlpha);
|
|
||||||
int prevBlendFuncSrcRgb = GL.GetInteger(GetPName.BlendSrcRgb);
|
|
||||||
int prevBlendFuncSrcAlpha = GL.GetInteger(GetPName.BlendSrcAlpha);
|
|
||||||
int prevBlendFuncDstRgb = GL.GetInteger(GetPName.BlendDstRgb);
|
|
||||||
int prevBlendFuncDstAlpha = GL.GetInteger(GetPName.BlendDstAlpha);
|
|
||||||
bool prevCullFaceEnabled = GL.GetBoolean(GetPName.CullFace);
|
|
||||||
bool prevDepthTestEnabled = GL.GetBoolean(GetPName.DepthTest);
|
|
||||||
int prevActiveTexture = GL.GetInteger(GetPName.ActiveTexture);
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
|
||||||
int prevTexture2D = GL.GetInteger(GetPName.TextureBinding2D);
|
|
||||||
Span<int> prevScissorBox = stackalloc int[4];
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (int* iptr = &prevScissorBox[0])
|
|
||||||
{
|
|
||||||
GL.GetInteger(GetPName.ScissorBox, iptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the element buffer (thru the VAO) so that we can resize it.
|
|
||||||
GL.BindVertexArray(_vertexArray);
|
|
||||||
// Bind the vertex buffer so that we can resize it.
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffer);
|
|
||||||
for (int i = 0; i < draw_data.CmdListsCount; i++)
|
|
||||||
{
|
|
||||||
ImDrawListPtr cmd_list = draw_data.CmdLists[i];
|
|
||||||
|
|
||||||
int vertexSize = cmd_list.VtxBuffer.Size * Unsafe.SizeOf<ImDrawVert>();
|
|
||||||
if (vertexSize > _vertexBufferSize)
|
|
||||||
{
|
|
||||||
int newSize = (int)Math.Max(_vertexBufferSize * 1.5f, vertexSize);
|
|
||||||
|
|
||||||
GL.BufferData(BufferTarget.ArrayBuffer, newSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
|
|
||||||
_vertexBufferSize = newSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
int indexSize = cmd_list.IdxBuffer.Size * sizeof(ushort);
|
|
||||||
if (indexSize > _indexBufferSize)
|
|
||||||
{
|
|
||||||
int newSize = (int)Math.Max(_indexBufferSize * 1.5f, indexSize);
|
|
||||||
GL.BufferData(BufferTarget.ElementArrayBuffer, newSize, IntPtr.Zero, BufferUsageHint.DynamicDraw);
|
|
||||||
_indexBufferSize = newSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup orthographic projection matrix into our constant buffer
|
|
||||||
ImGuiIOPtr io = ImGui.GetIO();
|
|
||||||
var mvp = OpenTK.Mathematics.Matrix4.CreateOrthographicOffCenter(
|
|
||||||
0.0f,
|
|
||||||
io.DisplaySize.X,
|
|
||||||
io.DisplaySize.Y,
|
|
||||||
0.0f,
|
|
||||||
-1.0f,
|
|
||||||
1.0f);
|
|
||||||
|
|
||||||
GL.UseProgram(_shader);
|
|
||||||
GL.UniformMatrix4(_shaderProjectionMatrixLocation, false, ref mvp);
|
|
||||||
GL.Uniform1(_shaderFontTextureLocation, 0);
|
|
||||||
CheckGLError("Projection");
|
|
||||||
|
|
||||||
GL.BindVertexArray(_vertexArray);
|
|
||||||
CheckGLError("VAO");
|
|
||||||
|
|
||||||
draw_data.ScaleClipRects(io.DisplayFramebufferScale);
|
|
||||||
|
|
||||||
GL.Enable(EnableCap.Blend);
|
|
||||||
GL.Enable(EnableCap.ScissorTest);
|
|
||||||
GL.BlendEquation(BlendEquationMode.FuncAdd);
|
|
||||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
|
||||||
GL.Disable(EnableCap.CullFace);
|
|
||||||
GL.Disable(EnableCap.DepthTest);
|
|
||||||
|
|
||||||
// Render command lists
|
|
||||||
for (int n = 0; n < draw_data.CmdListsCount; n++)
|
|
||||||
{
|
|
||||||
ImDrawListPtr cmd_list = draw_data.CmdLists[n];
|
|
||||||
|
|
||||||
GL.BufferSubData(BufferTarget.ArrayBuffer, IntPtr.Zero, cmd_list.VtxBuffer.Size * Unsafe.SizeOf<ImDrawVert>(), cmd_list.VtxBuffer.Data);
|
|
||||||
CheckGLError($"Data Vert {n}");
|
|
||||||
|
|
||||||
GL.BufferSubData(BufferTarget.ElementArrayBuffer, IntPtr.Zero, cmd_list.IdxBuffer.Size * sizeof(ushort), cmd_list.IdxBuffer.Data);
|
|
||||||
CheckGLError($"Data Idx {n}");
|
|
||||||
|
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++)
|
|
||||||
{
|
|
||||||
ImDrawCmdPtr pcmd = cmd_list.CmdBuffer[cmd_i];
|
|
||||||
if (pcmd.UserCallback != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, (int)pcmd.TextureId);
|
|
||||||
CheckGLError("Texture");
|
|
||||||
|
|
||||||
// We do _windowHeight - (int)clip.W instead of (int)clip.Y because gl has flipped Y when it comes to these coordinates
|
|
||||||
var clip = pcmd.ClipRect;
|
|
||||||
GL.Scissor((int)clip.X, _windowHeight - (int)clip.W, (int)(clip.Z - clip.X), (int)(clip.W - clip.Y));
|
|
||||||
CheckGLError("Scissor");
|
|
||||||
|
|
||||||
if ((io.BackendFlags & ImGuiBackendFlags.RendererHasVtxOffset) != 0)
|
|
||||||
{
|
|
||||||
GL.DrawElementsBaseVertex(PrimitiveType.Triangles, (int)pcmd.ElemCount, DrawElementsType.UnsignedShort, (IntPtr)(pcmd.IdxOffset * sizeof(ushort)), unchecked((int)pcmd.VtxOffset));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GL.DrawElements(BeginMode.Triangles, (int)pcmd.ElemCount, DrawElementsType.UnsignedShort, (int)pcmd.IdxOffset * sizeof(ushort));
|
|
||||||
}
|
|
||||||
CheckGLError("Draw");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.Disable(EnableCap.Blend);
|
|
||||||
GL.Disable(EnableCap.ScissorTest);
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
GL.BindTexture(TextureTarget.Texture2D, prevTexture2D);
|
|
||||||
GL.ActiveTexture((TextureUnit)prevActiveTexture);
|
|
||||||
GL.UseProgram(prevProgram);
|
|
||||||
GL.BindVertexArray(prevVAO);
|
|
||||||
GL.Scissor(prevScissorBox[0], prevScissorBox[1], prevScissorBox[2], prevScissorBox[3]);
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, prevArrayBuffer);
|
|
||||||
GL.BlendEquationSeparate((BlendEquationMode)prevBlendEquationRgb, (BlendEquationMode)prevBlendEquationAlpha);
|
|
||||||
GL.BlendFuncSeparate(
|
|
||||||
(BlendingFactorSrc)prevBlendFuncSrcRgb,
|
|
||||||
(BlendingFactorDest)prevBlendFuncDstRgb,
|
|
||||||
(BlendingFactorSrc)prevBlendFuncSrcAlpha,
|
|
||||||
(BlendingFactorDest)prevBlendFuncDstAlpha);
|
|
||||||
if (prevBlendEnabled) GL.Enable(EnableCap.Blend); else GL.Disable(EnableCap.Blend);
|
|
||||||
if (prevDepthTestEnabled) GL.Enable(EnableCap.DepthTest); else GL.Disable(EnableCap.DepthTest);
|
|
||||||
if (prevCullFaceEnabled) GL.Enable(EnableCap.CullFace); else GL.Disable(EnableCap.CullFace);
|
|
||||||
if (prevScissorTestEnabled) GL.Enable(EnableCap.ScissorTest); else GL.Disable(EnableCap.ScissorTest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Frees all graphics resources used by the renderer.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
GL.DeleteVertexArray(_vertexArray);
|
|
||||||
GL.DeleteBuffer(_vertexBuffer);
|
|
||||||
GL.DeleteBuffer(_indexBuffer);
|
|
||||||
|
|
||||||
GL.DeleteTexture(_fontTexture);
|
|
||||||
GL.DeleteProgram(_shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void LabelObject(ObjectLabelIdentifier objLabelIdent, int glObject, string name)
|
|
||||||
{
|
|
||||||
if (KHRDebugAvailable)
|
|
||||||
GL.ObjectLabel(objLabelIdent, glObject, name.Length, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsExtensionSupported(string name)
|
|
||||||
{
|
|
||||||
int n = GL.GetInteger(GetPName.NumExtensions);
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
string extension = GL.GetString(StringNameIndexed.Extensions, i);
|
|
||||||
if (extension == name) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int CreateProgram(string name, string vertexSource, string fragmentSoruce)
|
|
||||||
{
|
|
||||||
int program = GL.CreateProgram();
|
|
||||||
LabelObject(ObjectLabelIdentifier.Program, program, $"Program: {name}");
|
|
||||||
|
|
||||||
int vertex = CompileShader(name, ShaderType.VertexShader, vertexSource);
|
|
||||||
int fragment = CompileShader(name, ShaderType.FragmentShader, fragmentSoruce);
|
|
||||||
|
|
||||||
GL.AttachShader(program, vertex);
|
|
||||||
GL.AttachShader(program, fragment);
|
|
||||||
|
|
||||||
GL.LinkProgram(program);
|
|
||||||
|
|
||||||
GL.GetProgram(program, GetProgramParameterName.LinkStatus, out int success);
|
|
||||||
if (success == 0)
|
|
||||||
{
|
|
||||||
string info = GL.GetProgramInfoLog(program);
|
|
||||||
Debug.WriteLine($"GL.LinkProgram had info log [{name}]:\n{info}");
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.DetachShader(program, vertex);
|
|
||||||
GL.DetachShader(program, fragment);
|
|
||||||
|
|
||||||
GL.DeleteShader(vertex);
|
|
||||||
GL.DeleteShader(fragment);
|
|
||||||
|
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int CompileShader(string name, ShaderType type, string source)
|
|
||||||
{
|
|
||||||
int shader = GL.CreateShader(type);
|
|
||||||
LabelObject(ObjectLabelIdentifier.Shader, shader, $"Shader: {name}");
|
|
||||||
|
|
||||||
GL.ShaderSource(shader, source);
|
|
||||||
GL.CompileShader(shader);
|
|
||||||
|
|
||||||
GL.GetShader(shader, ShaderParameter.CompileStatus, out int success);
|
|
||||||
if (success == 0)
|
|
||||||
{
|
|
||||||
string info = GL.GetShaderInfoLog(shader);
|
|
||||||
Debug.WriteLine($"GL.CompileShader for shader '{name}' [{type}] had info log:\n{info}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CheckGLError(string title)
|
|
||||||
{
|
|
||||||
ErrorCode error;
|
|
||||||
int i = 1;
|
|
||||||
while ((error = GL.GetError()) != ErrorCode.NoError)
|
|
||||||
{
|
|
||||||
Debug.Print($"{title} ({i++}): {error}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float GetDpiScale()
|
|
||||||
{
|
|
||||||
return Math.Max((float)(Screen.PrimaryScreen.Bounds.Width / SystemParameters.PrimaryScreenWidth), (float)(Screen.PrimaryScreen.Bounds.Height / SystemParameters.PrimaryScreenHeight));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ImGuiKey TranslateKey(Keys key)
|
|
||||||
{
|
|
||||||
if (key is >= Keys.D0 and <= Keys.D9)
|
|
||||||
return key - Keys.D0 + ImGuiKey._0;
|
|
||||||
|
|
||||||
if (key is >= Keys.A and <= Keys.Z)
|
|
||||||
return key - Keys.A + ImGuiKey.A;
|
|
||||||
|
|
||||||
if (key is >= Keys.KeyPad0 and <= Keys.KeyPad9)
|
|
||||||
return key - Keys.KeyPad0 + ImGuiKey.Keypad0;
|
|
||||||
|
|
||||||
if (key is >= Keys.F1 and <= Keys.F24)
|
|
||||||
return key - Keys.F1 + ImGuiKey.F24;
|
|
||||||
|
|
||||||
return key switch
|
|
||||||
{
|
|
||||||
Keys.Tab => ImGuiKey.Tab,
|
|
||||||
Keys.Left => ImGuiKey.LeftArrow,
|
|
||||||
Keys.Right => ImGuiKey.RightArrow,
|
|
||||||
Keys.Up => ImGuiKey.UpArrow,
|
|
||||||
Keys.Down => ImGuiKey.DownArrow,
|
|
||||||
Keys.PageUp => ImGuiKey.PageUp,
|
|
||||||
Keys.PageDown => ImGuiKey.PageDown,
|
|
||||||
Keys.Home => ImGuiKey.Home,
|
|
||||||
Keys.End => ImGuiKey.End,
|
|
||||||
Keys.Insert => ImGuiKey.Insert,
|
|
||||||
Keys.Delete => ImGuiKey.Delete,
|
|
||||||
Keys.Backspace => ImGuiKey.Backspace,
|
|
||||||
Keys.Space => ImGuiKey.Space,
|
|
||||||
Keys.Enter => ImGuiKey.Enter,
|
|
||||||
Keys.Escape => ImGuiKey.Escape,
|
|
||||||
Keys.Apostrophe => ImGuiKey.Apostrophe,
|
|
||||||
Keys.Comma => ImGuiKey.Comma,
|
|
||||||
Keys.Minus => ImGuiKey.Minus,
|
|
||||||
Keys.Period => ImGuiKey.Period,
|
|
||||||
Keys.Slash => ImGuiKey.Slash,
|
|
||||||
Keys.Semicolon => ImGuiKey.Semicolon,
|
|
||||||
Keys.Equal => ImGuiKey.Equal,
|
|
||||||
Keys.LeftBracket => ImGuiKey.LeftBracket,
|
|
||||||
Keys.Backslash => ImGuiKey.Backslash,
|
|
||||||
Keys.RightBracket => ImGuiKey.RightBracket,
|
|
||||||
Keys.GraveAccent => ImGuiKey.GraveAccent,
|
|
||||||
Keys.CapsLock => ImGuiKey.CapsLock,
|
|
||||||
Keys.ScrollLock => ImGuiKey.ScrollLock,
|
|
||||||
Keys.NumLock => ImGuiKey.NumLock,
|
|
||||||
Keys.PrintScreen => ImGuiKey.PrintScreen,
|
|
||||||
Keys.Pause => ImGuiKey.Pause,
|
|
||||||
Keys.KeyPadDecimal => ImGuiKey.KeypadDecimal,
|
|
||||||
Keys.KeyPadDivide => ImGuiKey.KeypadDivide,
|
|
||||||
Keys.KeyPadMultiply => ImGuiKey.KeypadMultiply,
|
|
||||||
Keys.KeyPadSubtract => ImGuiKey.KeypadSubtract,
|
|
||||||
Keys.KeyPadAdd => ImGuiKey.KeypadAdd,
|
|
||||||
Keys.KeyPadEnter => ImGuiKey.KeypadEnter,
|
|
||||||
Keys.KeyPadEqual => ImGuiKey.KeypadEqual,
|
|
||||||
Keys.LeftShift => ImGuiKey.LeftShift,
|
|
||||||
Keys.LeftControl => ImGuiKey.LeftCtrl,
|
|
||||||
Keys.LeftAlt => ImGuiKey.LeftAlt,
|
|
||||||
Keys.LeftSuper => ImGuiKey.LeftSuper,
|
|
||||||
Keys.RightShift => ImGuiKey.RightShift,
|
|
||||||
Keys.RightControl => ImGuiKey.RightCtrl,
|
|
||||||
Keys.RightAlt => ImGuiKey.RightAlt,
|
|
||||||
Keys.RightSuper => ImGuiKey.RightSuper,
|
|
||||||
Keys.Menu => ImGuiKey.Menu,
|
|
||||||
_ => ImGuiKey.None
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using RestSharp.Serializers;
|
using RestSharp.Serialization;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public class JsonNetSerializer : IRestSerializer, ISerializer, IDeserializer
|
public class JsonNetSerializer : IRestSerializer
|
||||||
{
|
{
|
||||||
public static readonly JsonSerializerSettings SerializerSettings = new()
|
public static readonly JsonSerializerSettings SerializerSettings = new()
|
||||||
{
|
{
|
||||||
|
|
@ -15,16 +15,29 @@ public class JsonNetSerializer : IRestSerializer, ISerializer, IDeserializer
|
||||||
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||||
};
|
};
|
||||||
|
|
||||||
public string Serialize(Parameter parameter) => JsonConvert.SerializeObject(parameter.Value);
|
public string Serialize(object obj)
|
||||||
public string Serialize(object obj) => JsonConvert.SerializeObject(obj);
|
{
|
||||||
public T Deserialize<T>(RestResponse response) => JsonConvert.DeserializeObject<T>(response.Content!, SerializerSettings);
|
return JsonConvert.SerializeObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
public ISerializer Serializer => this;
|
[Obsolete]
|
||||||
public IDeserializer Deserializer => this;
|
public string Serialize(Parameter parameter)
|
||||||
|
{
|
||||||
|
return JsonConvert.SerializeObject(parameter.Value);
|
||||||
|
}
|
||||||
|
|
||||||
public ContentType ContentType { get; set; } = ContentType.Json;
|
public T Deserialize<T>(IRestResponse response)
|
||||||
public string[] AcceptedContentTypes => ContentType.JsonAccept;
|
{
|
||||||
public SupportsContentType SupportsContentType => contentType => contentType.Value.EndsWith("json", StringComparison.InvariantCultureIgnoreCase);
|
return JsonConvert.DeserializeObject<T>(response.Content, SerializerSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] SupportedContentTypes { get; } =
|
||||||
|
{
|
||||||
|
"application/json", "application/json; charset=UTF-8"
|
||||||
|
};
|
||||||
|
|
||||||
|
public string ContentType { get; set; } = "application/json; charset=UTF-8";
|
||||||
|
|
||||||
public DataFormat DataFormat => DataFormat.Json;
|
public DataFormat DataFormat => DataFormat.Json;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace FModel.Framework;
|
|
||||||
|
|
||||||
public class NavigationList<T> : List<T>
|
|
||||||
{
|
|
||||||
private int _currentIndex;
|
|
||||||
public int CurrentIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_currentIndex > Count - 1)
|
|
||||||
{
|
|
||||||
_currentIndex = Count - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_currentIndex < 0)
|
|
||||||
{
|
|
||||||
_currentIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _currentIndex;
|
|
||||||
}
|
|
||||||
set => _currentIndex = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T MoveNext
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
_currentIndex++;
|
|
||||||
return this[CurrentIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T MovePrevious
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
_currentIndex--;
|
|
||||||
return this[CurrentIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current => this[CurrentIndex];
|
|
||||||
}
|
|
||||||
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public sealed class RangeObservableCollection<T> : ObservableCollection<T>
|
public sealed class RangeObservableCollection<T> : ObservableCollection<T>
|
||||||
{
|
{
|
||||||
private bool _suppressNotification;
|
private bool _suppressNotification;
|
||||||
|
|
@ -39,3 +39,4 @@ public sealed class RangeObservableCollection<T> : ObservableCollection<T>
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(changedAction));
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(changedAction));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,8 @@ using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public class ViewModel : INotifyPropertyChanged, INotifyDataErrorInfo, IDataErrorInfo
|
public class ViewModel : INotifyPropertyChanged, INotifyDataErrorInfo, IDataErrorInfo
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, IList<string>> _validationErrors = new();
|
private readonly Dictionary<string, IList<string>> _validationErrors = new();
|
||||||
|
|
@ -73,3 +73,4 @@ public class ViewModel : INotifyPropertyChanged, INotifyDataErrorInfo, IDataErro
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FModel.Framework;
|
namespace FModel.Framework
|
||||||
|
{
|
||||||
public abstract class ViewModelCommand<TContextViewModel> : Command where TContextViewModel : ViewModel
|
public abstract class ViewModelCommand<TContextViewModel> : Command where TContextViewModel : ViewModel
|
||||||
{
|
{
|
||||||
private WeakReference _parent;
|
private WeakReference _parent;
|
||||||
|
|
@ -47,3 +47,4 @@ public abstract class ViewModelCommand<TContextViewModel> : Command where TConte
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,32 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace FModel;
|
namespace FModel
|
||||||
|
{
|
||||||
public static class Helper
|
public static class Helper
|
||||||
{
|
{
|
||||||
public static string FixKey(string key)
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
private struct NanUnion
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(key))
|
[FieldOffset(0)]
|
||||||
return string.Empty;
|
internal double DoubleValue;
|
||||||
|
[FieldOffset(0)]
|
||||||
var keySpan = key.AsSpan().Trim();
|
internal readonly ulong UlongValue;
|
||||||
if (keySpan.Length > sizeof(char) * (2 /* 0x */ + 32 /* FAES = 256 bit */)) // maybe strictly check for length?
|
|
||||||
return string.Empty; // bullshit key
|
|
||||||
|
|
||||||
Span<char> resultSpan = stackalloc char[keySpan.Length + 2 /* pad for 0x */];
|
|
||||||
keySpan.ToUpperInvariant(resultSpan[2..]);
|
|
||||||
|
|
||||||
if (resultSpan[2..].StartsWith("0X"))
|
|
||||||
resultSpan = resultSpan[2..];
|
|
||||||
else
|
|
||||||
resultSpan[0] = '0';
|
|
||||||
|
|
||||||
resultSpan[1] = 'x';
|
|
||||||
|
|
||||||
return new string(resultSpan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenWindow<T>(string windowName, Action action) where T : Window
|
public static void OpenWindow<T>(string windowName, Action action) where T : Window
|
||||||
|
|
@ -76,9 +63,9 @@ public static class Helper
|
||||||
|
|
||||||
public static bool IsNaN(double value)
|
public static bool IsNaN(double value)
|
||||||
{
|
{
|
||||||
var ulongValue = Unsafe.As<double, ulong>(ref value);
|
var t = new NanUnion {DoubleValue = value};
|
||||||
var exp = ulongValue & 0xfff0000000000000;
|
var exp = t.UlongValue & 0xfff0000000000000;
|
||||||
var man = ulongValue & 0x000fffffffffffff;
|
var man = t.UlongValue & 0x000fffffffffffff;
|
||||||
return exp is 0x7ff0000000000000 or 0xfff0000000000000 && man != 0;
|
return exp is 0x7ff0000000000000 or 0xfff0000000000000 && man != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,18 +84,5 @@ public static class Helper
|
||||||
var d = (Math.Abs(d1) + Math.Abs(d2) + 10) * 1.0e-15;
|
var d = (Math.Abs(d1) + Math.Abs(d2) + 10) * 1.0e-15;
|
||||||
return -d < n && d > n;
|
return -d < n && d > n;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float DegreesToRadians(float degrees)
|
|
||||||
{
|
|
||||||
const float ratio = MathF.PI / 180f;
|
|
||||||
return ratio * degrees;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static float RadiansToDegrees(float radians)
|
|
||||||
{
|
|
||||||
const float ratio = 180f / MathF.PI;
|
|
||||||
return radians * ratio;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,8 +4,6 @@
|
||||||
xmlns:local="clr-namespace:FModel"
|
xmlns:local="clr-namespace:FModel"
|
||||||
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"
|
xmlns:controls="clr-namespace:FModel.Views.Resources.Controls"
|
||||||
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
|
xmlns:converters="clr-namespace:FModel.Views.Resources.Converters"
|
||||||
xmlns:settings="clr-namespace:FModel.Settings"
|
|
||||||
xmlns:services="clr-namespace:FModel.Services"
|
|
||||||
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
|
xmlns:adonisUi="clr-namespace:AdonisUI;assembly=AdonisUI"
|
||||||
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
|
xmlns:adonisControls="clr-namespace:AdonisUI.Controls;assembly=AdonisUI"
|
||||||
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
|
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
|
||||||
|
|
@ -14,18 +12,13 @@
|
||||||
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.75'}">
|
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.75'}">
|
||||||
<adonisControls:AdonisWindow.Style>
|
<adonisControls:AdonisWindow.Style>
|
||||||
<Style TargetType="adonisControls:AdonisWindow" BasedOn="{StaticResource {x:Type adonisControls:AdonisWindow}}" >
|
<Style TargetType="adonisControls:AdonisWindow" BasedOn="{StaticResource {x:Type adonisControls:AdonisWindow}}" >
|
||||||
<Setter Property="Title" Value="{Binding DataContext.InitialWindowTitle, RelativeSource={RelativeSource Self}}" />
|
<Setter Property="Title" Value="FModel" />
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding DataContext.TitleExtra, RelativeSource={RelativeSource Self}, Converter={x:Static converters:IsNullToBoolReversedConverter.Instance}}" Value="True">
|
<DataTrigger
|
||||||
<Setter Property="Title">
|
Binding="{Binding DataContext.TitleExtra, RelativeSource={RelativeSource Self}, Converter={x:Static converters:IsNullToBoolReversedConverter.Instance}}"
|
||||||
<Setter.Value>
|
Value="True">
|
||||||
<MultiBinding StringFormat="{}{0} - {1} {2}">
|
<Setter Property="Title"
|
||||||
<Binding Path="DataContext.InitialWindowTitle" RelativeSource="{RelativeSource Self}" />
|
Value="{Binding DataContext.TitleExtra, RelativeSource={RelativeSource Self}, StringFormat={}FModel - {0}}" />
|
||||||
<Binding Path="DataContext.GameDisplayName" RelativeSource="{RelativeSource Self}" />
|
|
||||||
<Binding Path="DataContext.TitleExtra" RelativeSource="{RelativeSource Self}" />
|
|
||||||
</MultiBinding>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
@ -56,7 +49,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="AES" Command="{Binding MenuCommand}" CommandParameter="Directory_AES" IsEnabled="{Binding Status.IsReady}">
|
<MenuItem Header="AES" Command="{Binding MenuCommand}" CommandParameter="Directory_AES" IsEnabled="{Binding IsReady}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -65,7 +58,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Backup" Command="{Binding MenuCommand}" CommandParameter="Directory_Backup" IsEnabled="{Binding Status.IsReady}">
|
<MenuItem Header="Backup" Command="{Binding MenuCommand}" CommandParameter="Directory_Backup" IsEnabled="{Binding IsReady}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -74,18 +67,9 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Archives Info" Command="{Binding MenuCommand}" CommandParameter="Directory_ArchivesInfo" IsEnabled="{Binding Status.IsReady}">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<Viewbox Width="16" Height="16">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource InfoIcon}" />
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
<MenuItem Header="Assets">
|
||||||
<MenuItem Header="Packages">
|
<MenuItem Header="Search" IsEnabled="{Binding IsReady}" InputGestureText="Ctrl+Shift+F" Click="OnSearchViewClick">
|
||||||
<MenuItem Header="Search" IsEnabled="{Binding Status.IsReady}" InputGestureText="Ctrl+Shift+F" Click="OnSearchViewClick">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -94,7 +78,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Favorite Directories" ItemsSource="{Binding CustomDirectories.Directories}" IsEnabled="{Binding Status.IsReady}">
|
<MenuItem Header="Directories" ItemsSource="{Binding CustomDirectories.Directories}" IsEnabled="{Binding IsReady}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -104,19 +88,62 @@
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="Auto Open Sounds" IsCheckable="True" StaysOpenOnClick="True"
|
<MenuItem Header="Export Data" Command="{Binding ExportDataCommand}" CommandParameter="{Binding SelectedItems, ElementName=AssetsListName}">
|
||||||
IsChecked="{Binding IsAutoOpenSounds, Source={x:Static settings:UserSettings.Default}}" />
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Views">
|
|
||||||
<MenuItem Header="3D Viewer" Command="{Binding MenuCommand}" CommandParameter="Views_3dViewer">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource MeshIcon}" />
|
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExportIcon}" />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem Header="Save Property" Command="{Binding SavePropertyCommand}" CommandParameter="{Binding SelectedItems, ElementName=AssetsListName}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Viewbox Width="16" Height="16">
|
||||||
|
<Canvas Width="24" Height="24">
|
||||||
|
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource SaveIcon}" />
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Save Texture" Command="{Binding SaveTextureCommand}" CommandParameter="{Binding SelectedItems, ElementName=AssetsListName}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Viewbox Width="16" Height="16">
|
||||||
|
<Canvas Width="24" Height="24">
|
||||||
|
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource TextureIcon}" />
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Auto">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Viewbox Width="16" Height="16">
|
||||||
|
<Canvas Width="24" Height="24">
|
||||||
|
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource StatusBarIcon}" />
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</MenuItem.Icon>
|
||||||
|
<MenuItem Header="Export Data" IsCheckable="True" StaysOpenOnClick="True"
|
||||||
|
InputGestureText="{Binding AutoExportData, Source={x:Static local:Settings.UserSettings.Default}}"
|
||||||
|
IsChecked="{Binding IsAutoExportData, Source={x:Static local:Settings.UserSettings.Default}}" />
|
||||||
|
<MenuItem Header="Save Properties" IsCheckable="True" StaysOpenOnClick="True"
|
||||||
|
InputGestureText="{Binding AutoSaveProps, Source={x:Static local:Settings.UserSettings.Default}}"
|
||||||
|
IsChecked="{Binding IsAutoSaveProps, Source={x:Static local:Settings.UserSettings.Default}}" />
|
||||||
|
<MenuItem Header="Save Textures" IsCheckable="True" StaysOpenOnClick="True"
|
||||||
|
InputGestureText="{Binding AutoSaveTextures, Source={x:Static local:Settings.UserSettings.Default}}"
|
||||||
|
IsChecked="{Binding IsAutoSaveTextures, Source={x:Static local:Settings.UserSettings.Default}}" />
|
||||||
|
<!--<MenuItem Header="Save Meshes" IsCheckable="True" StaysOpenOnClick="True"
|
||||||
|
InputGestureText="{Binding AutoSaveMeshes, Source={x:Static local:Settings.UserSettings.Default}}"
|
||||||
|
IsChecked="{Binding IsAutoSaveMeshes, Source={x:Static local:Settings.UserSettings.Default}}" />-->
|
||||||
|
<MenuItem Header="Save Materials" IsCheckable="True" StaysOpenOnClick="True"
|
||||||
|
InputGestureText="{Binding AutoSaveMaterials, Source={x:Static local:Settings.UserSettings.Default}}"
|
||||||
|
IsChecked="{Binding IsAutoSaveMaterials, Source={x:Static local:Settings.UserSettings.Default}}" />
|
||||||
|
<MenuItem Header="Open Sounds" IsCheckable="True" StaysOpenOnClick="True"
|
||||||
|
InputGestureText="{Binding AutoOpenSounds, Source={x:Static local:Settings.UserSettings.Default}}"
|
||||||
|
IsChecked="{Binding IsAutoOpenSounds, Source={x:Static local:Settings.UserSettings.Default}}" />
|
||||||
|
</MenuItem>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Views">
|
||||||
<MenuItem Header="Audio Player" Command="{Binding MenuCommand}" CommandParameter="Views_AudioPlayer">
|
<MenuItem Header="Audio Player" Command="{Binding MenuCommand}" CommandParameter="Views_AudioPlayer">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
|
|
@ -126,6 +153,25 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem Header="Map Viewer" Command="{Binding MenuCommand}" CommandParameter="Views_MapViewer" IsEnabled="{Binding IsReady}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<Viewbox Width="16" Height="16">
|
||||||
|
<Canvas Width="24" Height="24">
|
||||||
|
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource MapIcon}" />
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</MenuItem.Icon>
|
||||||
|
<MenuItem.Style>
|
||||||
|
<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding CUE4Parse.Game}" Value="{x:Static local:FGame.FortniteGame}">
|
||||||
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</MenuItem.Style>
|
||||||
|
</MenuItem>
|
||||||
<MenuItem Header="Image Merger" Command="{Binding MenuCommand}" CommandParameter="Views_ImageMerger">
|
<MenuItem Header="Image Merger" Command="{Binding MenuCommand}" CommandParameter="Views_ImageMerger">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
|
|
@ -147,7 +193,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Releases" Command="{Binding MenuCommand}" CommandParameter="Help_Releases">
|
<MenuItem Header="Changelog" Command="{Binding MenuCommand}" CommandParameter="Help_Changelog">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -196,7 +242,7 @@
|
||||||
<GroupBox Grid.Column="0" adonisExtensions:LayerExtension.Layer="2"
|
<GroupBox Grid.Column="0" adonisExtensions:LayerExtension.Layer="2"
|
||||||
Padding="{adonisUi:Space 0}" Background="Transparent">
|
Padding="{adonisUi:Space 0}" Background="Transparent">
|
||||||
<TabControl x:Name="LeftTabControl" SelectionChanged="OnTabItemChange">
|
<TabControl x:Name="LeftTabControl" SelectionChanged="OnTabItemChange">
|
||||||
<TabItem Style="{StaticResource TabItemFillSpace}" Header="Archives">
|
<TabItem Style="{StaticResource TabItemFillSpace}" Header="Directory">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Grid DockPanel.Dock="Top">
|
<Grid DockPanel.Dock="Top">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
|
@ -211,8 +257,8 @@
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Loading Mode" VerticalAlignment="Center" />
|
<TextBlock Grid.Row="0" Grid.Column="0" Text="Loading Mode" VerticalAlignment="Center" />
|
||||||
<ComboBox Grid.Row="0" Grid.Column="2" ItemsSource="{Binding LoadingModes.Modes}" IsEnabled="{Binding Status.IsReady}"
|
<ComboBox Grid.Row="0" Grid.Column="2" ItemsSource="{Binding LoadingModes.Modes}" IsEnabled="{Binding IsReady}"
|
||||||
SelectedItem="{Binding LoadingMode, Source={x:Static settings:UserSettings.Default}, Mode=TwoWay}">
|
SelectedItem="{Binding LoadingMode, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding Converter={x:Static converters:EnumToStringConverter.Instance}}" />
|
<TextBlock Text="{Binding Converter={x:Static converters:EnumToStringConverter.Instance}}" />
|
||||||
|
|
@ -220,7 +266,7 @@
|
||||||
</ComboBox.ItemTemplate>
|
</ComboBox.ItemTemplate>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Content="Load"
|
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Content="Load"
|
||||||
Command="{Binding LoadingModes.LoadCommand}" IsEnabled="{Binding Status.IsReady}"
|
Command="{Binding LoadingModes.LoadCommand}" IsEnabled="{Binding IsReady}"
|
||||||
CommandParameter="{Binding SelectedItems, ElementName=DirectoryFilesListBox}" />
|
CommandParameter="{Binding SelectedItems, ElementName=DirectoryFilesListBox}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid DockPanel.Dock="Top">
|
<Grid DockPanel.Dock="Top">
|
||||||
|
|
@ -231,8 +277,8 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Separator Grid.Row="0" Style="{StaticResource CustomSeparator}" Tag="GAME ARCHIVES" />
|
<Separator Grid.Row="0" Style="{StaticResource CustomSeparator}" Tag="GAME DIRECTORY" />
|
||||||
<ListBox Grid.Row="1" x:Name="DirectoryFilesListBox" Style="{StaticResource DirectoryFilesListBox}" MouseDoubleClick="OnMouseDoubleClick" />
|
<ListBox Grid.Row="1" x:Name="DirectoryFilesListBox" Style="{StaticResource DirectoryFilesListBox}" />
|
||||||
<Separator Grid.Row="2" Style="{StaticResource CustomSeparator}" Tag="INFORMATION" />
|
<Separator Grid.Row="2" Style="{StaticResource CustomSeparator}" Tag="INFORMATION" />
|
||||||
<StackPanel Grid.Row="3" Orientation="Vertical" Margin="0 0 0 5">
|
<StackPanel Grid.Row="3" Orientation="Vertical" Margin="0 0 0 5">
|
||||||
<Grid HorizontalAlignment="Stretch">
|
<Grid HorizontalAlignment="Stretch">
|
||||||
|
|
@ -261,77 +307,31 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Style="{StaticResource TabItemFillSpace}" Header="Folders">
|
<TabItem Style="{StaticResource TabItemFillSpace}" Header="Folders">
|
||||||
<Grid>
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Top" TextAlignment="Center" TextWrapping="Wrap" HorizontalAlignment="Center" MaxWidth="375"
|
||||||
|
Text="Open folders to navigate through your loaded files. Badges indicate how many assets are in the folder. To better optimize things, it is recommended to use your hotkeys, to quickly switch between tabs." />
|
||||||
|
<Grid DockPanel.Dock="Top">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Grid Grid.Row="0">
|
<Separator Grid.Row="0" Style="{StaticResource CustomSeparator}" />
|
||||||
<Grid.ColumnDefinitions>
|
<TreeView Grid.Row="1" x:Name="AssetsFolderName" Style="{StaticResource AssetsFolderTreeView}" PreviewMouseDoubleClick="OnAssetsTreeMouseDoubleClick">
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="5" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
|
||||||
<Image Source="/FModel;component/Resources/label.png"
|
|
||||||
Width="16" Height="16" HorizontalAlignment="Center" Margin="0 0 3.5 0" />
|
|
||||||
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" TextTrimming="CharacterEllipsis">
|
|
||||||
<TextBlock.Text>
|
|
||||||
<MultiBinding StringFormat="{}'{0}' has {1} folders and {2} packages">
|
|
||||||
<Binding Path="SelectedItem.Header" ElementName="AssetsFolderName" FallbackValue="None" />
|
|
||||||
<Binding Path="SelectedItem.FoldersView.Count" ElementName="AssetsFolderName" FallbackValue="0" />
|
|
||||||
<Binding Path="SelectedItem.AssetsList.Assets.Count" ElementName="AssetsFolderName" FallbackValue="0" />
|
|
||||||
</MultiBinding>
|
|
||||||
</TextBlock.Text>
|
|
||||||
</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
|
||||||
<Button Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" ToolTip="Bring Selected Folder To View" Padding="4"
|
|
||||||
Command="{Binding MenuCommand}" CommandParameter="{Binding SelectedItem, ElementName=AssetsFolderName}">
|
|
||||||
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource LocateMeIcon}" />
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</Button>
|
|
||||||
<!-- <Button Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" ToolTip="Expand All (not appropriate for huge amount of folders)" Padding="4" -->
|
|
||||||
<!-- Command="{Binding MenuCommand}" CommandParameter="ToolBox_Expand_All"> -->
|
|
||||||
<!-- <Viewbox Width="16" Height="16" HorizontalAlignment="Center"> -->
|
|
||||||
<!-- <Canvas Width="24" Height="24"> -->
|
|
||||||
<!-- <Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource UnfoldIcon}" /> -->
|
|
||||||
<!-- </Canvas> -->
|
|
||||||
<!-- </Viewbox> -->
|
|
||||||
<!-- </Button> -->
|
|
||||||
<Button Style="{DynamicResource {x:Static adonisUi:Styles.ToolbarButton}}" ToolTip="Collapse All" Padding="4"
|
|
||||||
Command="{Binding MenuCommand}" CommandParameter="ToolBox_Collapse_All">
|
|
||||||
<Viewbox Width="16" Height="16" HorizontalAlignment="Center">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource FoldIcon}"/>
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
<Separator Grid.Row="1" Style="{StaticResource CustomSeparator}" Margin="0" />
|
|
||||||
<TreeView Grid.Row="2" x:Name="AssetsFolderName" Style="{StaticResource AssetsFolderTreeView}" PreviewMouseDoubleClick="OnAssetsTreeMouseDoubleClick">
|
|
||||||
<TreeView.ContextMenu>
|
<TreeView.ContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<!-- <MenuItem Header="Extract Folder's Packages" Click="OnFolderExtractClick"> -->
|
<MenuItem Header="Extract Folder's Assets" Click="OnFolderExtractClick">
|
||||||
<!-- <MenuItem.Icon> -->
|
<MenuItem.Icon>
|
||||||
<!-- <Viewbox Width="16" Height="16"> -->
|
<Viewbox Width="16" Height="16">
|
||||||
<!-- <Canvas Width="24" Height="24"> -->
|
<Canvas Width="24" Height="24">
|
||||||
<!-- <Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExtractIcon}" /> -->
|
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ExtractIcon}" />
|
||||||
<!-- </Canvas> -->
|
</Canvas>
|
||||||
<!-- </Viewbox> -->
|
</Viewbox>
|
||||||
<!-- </MenuItem.Icon> -->
|
</MenuItem.Icon>
|
||||||
<!-- </MenuItem> -->
|
</MenuItem>
|
||||||
<!-- <Separator /> -->
|
<MenuItem Header="Export Folder's Assets Data" Click="OnFolderExportClick">
|
||||||
<MenuItem Header="Export Folder's Packages Raw Data (.uasset)" Click="OnFolderExportClick">
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -340,7 +340,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Save Folder's Packages Properties (.json)" Click="OnFolderSaveClick">
|
<MenuItem Header="Save Folder's Assets Properties" Click="OnFolderSaveClick">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -349,35 +349,8 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Save Folder's Packages Textures" Click="OnFolderTextureClick">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<Viewbox Width="16" Height="16">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource TextureIcon}" />
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Save Folder's Packages Models" Click="OnFolderModelClick">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<Viewbox Width="16" Height="16">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ModelIcon}" />
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Save Folder's Packages Animations" Click="OnFolderAnimationClick">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<Viewbox Width="16" Height="16">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AnimationIcon}" />
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="Favorite Directory" Click="OnFavoriteDirectoryClick">
|
<MenuItem Header="Save Directory" Click="OnSaveDirectoryClick">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -398,8 +371,8 @@
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</TreeView.ContextMenu>
|
</TreeView.ContextMenu>
|
||||||
</TreeView>
|
</TreeView>
|
||||||
<Separator Grid.Row="3" Style="{StaticResource CustomSeparator}" Tag="INFORMATION" />
|
<Separator Grid.Row="2" Style="{StaticResource CustomSeparator}" Tag="INFORMATION" />
|
||||||
<StackPanel Grid.Row="4" Orientation="Vertical" Margin="0 0 0 5">
|
<StackPanel Grid.Row="3" Orientation="Vertical" Margin="0 0 0 5">
|
||||||
<Grid HorizontalAlignment="Stretch">
|
<Grid HorizontalAlignment="Stretch">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
|
@ -414,22 +387,23 @@
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding SelectedItem.AssetsList.Assets.Count, ElementName=AssetsFolderName, FallbackValue=0}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding SelectedItem.AssetsList.Assets.Count, ElementName=AssetsFolderName, FallbackValue=0}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="Packages Count" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="0" Grid.Column="1" Text="Assets Count" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding SelectedItem.FoldersView.Count, ElementName=AssetsFolderName, FallbackValue=0}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding SelectedItem.FoldersView.Count, ElementName=AssetsFolderName, FallbackValue=0}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="Folders Count" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="1" Grid.Column="1" Text="Folders Count" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding SelectedItem.Archive, ElementName=AssetsFolderName, FallbackValue='None'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
<TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding SelectedItem.Package, ElementName=AssetsFolderName, FallbackValue='None'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
<TextBlock Grid.Row="2" Grid.Column="1" Text="Included In Archive" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="2" Grid.Column="1" Text="Included In Package" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding SelectedItem.MountPoint, ElementName=AssetsFolderName, FallbackValue='/', Converter={x:Static converters:TrimRightToLeftConverter.Instance}, ConverterParameter=275}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding SelectedItem.MountPoint, ElementName=AssetsFolderName, FallbackValue='/', Converter={x:Static converters:TrimRightToLeftConverter.Instance}, ConverterParameter=275}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
<TextBlock Grid.Row="3" Grid.Column="1" Text="Archive Mount Point" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="3" Grid.Column="1" Text="Package Mount Point" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="{Binding SelectedItem.Version, ElementName=AssetsFolderName, FallbackValue='VER_UE4_LATEST', Converter={x:Static converters:TrimRightToLeftConverter.Instance}, ConverterParameter=275}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
<TextBlock Grid.Row="4" Grid.Column="0" Text="{Binding SelectedItem.Version, ElementName=AssetsFolderName, FallbackValue='VER_UE4_LATEST', Converter={x:Static converters:TrimRightToLeftConverter.Instance}, ConverterParameter=275}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
<TextBlock Grid.Row="4" Grid.Column="1" Text="Archive Version" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="4" Grid.Column="1" Text="Package Version" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Style="{StaticResource TabItemFillSpace}"
|
<TabItem Style="{StaticResource TabItemFillSpace}"
|
||||||
Header="{Binding SelectedItem.AssetsList.Assets.Count, FallbackValue=0, ElementName=AssetsFolderName}"
|
Header="{Binding SelectedItem.AssetsList.Assets.Count, FallbackValue=0, ElementName=AssetsFolderName}"
|
||||||
HeaderStringFormat="{}{0} Packages">
|
HeaderStringFormat="{}{0} Assets">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Grid DockPanel.Dock="Top" ZIndex="0">
|
<Grid DockPanel.Dock="Top" ZIndex="0">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
|
@ -465,19 +439,12 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<controls:Breadcrumb Grid.Row="0" MaxWidth="{Binding ActualWidth, ElementName=AssetsSearchName}" HorizontalAlignment="Left" Margin="0 5 0 5"
|
<Separator Grid.Row="0" Style="{StaticResource CustomSeparator}"
|
||||||
DataContext="{Binding SelectedItem.PathAtThisPoint, ElementName=AssetsFolderName, FallbackValue='No/Directory/Detected/In/Folder'}"/>
|
Tag="{Binding SelectedItem.Header, ElementName=AssetsFolderName, FallbackValue='ASSETS LIST', Converter={x:Static converters:FolderToSeparatorTagConverter.Instance}}" />
|
||||||
|
<ListBox Grid.Row="1" x:Name="AssetsListName" Style="{StaticResource AssetsListBox}" PreviewMouseDoubleClick="OnAssetsListMouseDoubleClick">
|
||||||
<ListBox Grid.Row="1" x:Name="AssetsListName" Style="{StaticResource AssetsListBox}" PreviewMouseDoubleClick="OnAssetsListMouseDoubleClick" PreviewKeyDown="OnPreviewKeyDown">
|
|
||||||
<ListBox.ContextMenu>
|
<ListBox.ContextMenu>
|
||||||
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
|
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
|
||||||
<MenuItem Header="Extract in New Tab" Command="{Binding DataContext.RightClickMenuCommand}">
|
<MenuItem Header="Extract in New Tab" Command="{Binding DataContext.ExtractNewTabCommand}" CommandParameter="{Binding SelectedItems}">
|
||||||
<MenuItem.CommandParameter>
|
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
|
||||||
<Binding Source="Assets_Extract_New_Tab" />
|
|
||||||
<Binding Path="SelectedItems" />
|
|
||||||
</MultiBinding>
|
|
||||||
</MenuItem.CommandParameter>
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -486,14 +453,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<MenuItem Header="Export Data" Command="{Binding DataContext.ExportDataCommand}" CommandParameter="{Binding SelectedItems}">
|
||||||
<MenuItem Header="Export Raw Data (.uasset)" Command="{Binding DataContext.RightClickMenuCommand}">
|
|
||||||
<MenuItem.CommandParameter>
|
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
|
||||||
<Binding Source="Assets_Export_Data" />
|
|
||||||
<Binding Path="SelectedItems" />
|
|
||||||
</MultiBinding>
|
|
||||||
</MenuItem.CommandParameter>
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -502,13 +462,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Save Properties (.json)" Command="{Binding DataContext.RightClickMenuCommand}">
|
<MenuItem Header="Save Properties" Command="{Binding DataContext.SavePropertyCommand}" CommandParameter="{Binding SelectedItems}">
|
||||||
<MenuItem.CommandParameter>
|
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
|
||||||
<Binding Source="Assets_Save_Properties" />
|
|
||||||
<Binding Path="SelectedItems" />
|
|
||||||
</MultiBinding>
|
|
||||||
</MenuItem.CommandParameter>
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -517,13 +471,7 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Save Texture" Command="{Binding DataContext.RightClickMenuCommand}">
|
<MenuItem Header="Save Texture" Command="{Binding DataContext.SaveTextureCommand}" CommandParameter="{Binding SelectedItems}">
|
||||||
<MenuItem.CommandParameter>
|
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
|
||||||
<Binding Source="Assets_Save_Textures" />
|
|
||||||
<Binding Path="SelectedItems" />
|
|
||||||
</MultiBinding>
|
|
||||||
</MenuItem.CommandParameter>
|
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<Viewbox Width="16" Height="16">
|
<Viewbox Width="16" Height="16">
|
||||||
<Canvas Width="24" Height="24">
|
<Canvas Width="24" Height="24">
|
||||||
|
|
@ -532,36 +480,6 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Save Model" Command="{Binding DataContext.RightClickMenuCommand}">
|
|
||||||
<MenuItem.CommandParameter>
|
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
|
||||||
<Binding Source="Assets_Save_Models" />
|
|
||||||
<Binding Path="SelectedItems" />
|
|
||||||
</MultiBinding>
|
|
||||||
</MenuItem.CommandParameter>
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<Viewbox Width="16" Height="16">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource ModelIcon}" />
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Save Animation" Command="{Binding DataContext.RightClickMenuCommand}">
|
|
||||||
<MenuItem.CommandParameter>
|
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
|
||||||
<Binding Source="Assets_Save_Animations" />
|
|
||||||
<Binding Path="SelectedItems" />
|
|
||||||
</MultiBinding>
|
|
||||||
</MenuItem.CommandParameter>
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<Viewbox Width="16" Height="16">
|
|
||||||
<Canvas Width="24" Height="24">
|
|
||||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Data="{StaticResource AnimationIcon}" />
|
|
||||||
</Canvas>
|
|
||||||
</Viewbox>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem Header="Copy">
|
<MenuItem Header="Copy">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
|
|
@ -571,7 +489,7 @@
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
<MenuItem Header="Package Path" Command="{Binding DataContext.CopyCommand}">
|
<MenuItem Header="File Path" Command="{Binding DataContext.CopyCommand}">
|
||||||
<MenuItem.CommandParameter>
|
<MenuItem.CommandParameter>
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
||||||
<Binding Source="File_Path" />
|
<Binding Source="File_Path" />
|
||||||
|
|
@ -579,7 +497,7 @@
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</MenuItem.CommandParameter>
|
</MenuItem.CommandParameter>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Package Name" Command="{Binding DataContext.CopyCommand}">
|
<MenuItem Header="File Name" Command="{Binding DataContext.CopyCommand}">
|
||||||
<MenuItem.CommandParameter>
|
<MenuItem.CommandParameter>
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
||||||
<Binding Source="File_Name" />
|
<Binding Source="File_Name" />
|
||||||
|
|
@ -595,7 +513,7 @@
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</MenuItem.CommandParameter>
|
</MenuItem.CommandParameter>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Package Path w/o Extension" Command="{Binding DataContext.CopyCommand}">
|
<MenuItem Header="File Path w/o Extension" Command="{Binding DataContext.CopyCommand}">
|
||||||
<MenuItem.CommandParameter>
|
<MenuItem.CommandParameter>
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
||||||
<Binding Source="File_Path_No_Extension" />
|
<Binding Source="File_Path_No_Extension" />
|
||||||
|
|
@ -603,7 +521,7 @@
|
||||||
</MultiBinding>
|
</MultiBinding>
|
||||||
</MenuItem.CommandParameter>
|
</MenuItem.CommandParameter>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Package Name w/o Extension" Command="{Binding DataContext.CopyCommand}">
|
<MenuItem Header="File Name w/o Extension" Command="{Binding DataContext.CopyCommand}">
|
||||||
<MenuItem.CommandParameter>
|
<MenuItem.CommandParameter>
|
||||||
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
<MultiBinding Converter="{x:Static converters:MultiParameterConverter.Instance}">
|
||||||
<Binding Source="File_Name_No_Extension" />
|
<Binding Source="File_Name_No_Extension" />
|
||||||
|
|
@ -638,8 +556,8 @@
|
||||||
<TextBlock Grid.Row="2" Grid.Column="1" Text="Compression Method" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="2" Grid.Column="1" Text="Compression Method" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding SelectedItem.IsEncrypted, ElementName=AssetsListName, FallbackValue='False'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
<TextBlock Grid.Row="3" Grid.Column="0" Text="{Binding SelectedItem.IsEncrypted, ElementName=AssetsListName, FallbackValue='False'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
<TextBlock Grid.Row="3" Grid.Column="1" Text="Is Encrypted" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="3" Grid.Column="1" Text="Is Encrypted" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="{Binding SelectedItem.Archive, ElementName=AssetsListName, FallbackValue='None'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
<TextBlock Grid.Row="4" Grid.Column="0" Text="{Binding SelectedItem.Package, ElementName=AssetsListName, FallbackValue='None'}" VerticalAlignment="Center" HorizontalAlignment="Left" />
|
||||||
<TextBlock Grid.Row="4" Grid.Column="1" Text="Included In Archive" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
<TextBlock Grid.Row="4" Grid.Column="1" Text="Included In Package" VerticalAlignment="Center" HorizontalAlignment="Right" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -661,8 +579,7 @@
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TabControl Grid.Row="0" x:Name="TabControlName" Style="{StaticResource GameFilesTabControl}" />
|
<TabControl Grid.Row="0" x:Name="TabControlName" Style="{StaticResource GameFilesTabControl}" />
|
||||||
<Expander Grid.Row="1" Margin="0 5 0 5" ExpandDirection="Down"
|
<Expander Grid.Row="1" Margin="0 5 0 5" ExpandDirection="Down">
|
||||||
IsExpanded="{Binding IsLoggerExpanded, Source={x:Static settings:UserSettings.Default}}">
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
|
|
@ -701,31 +618,31 @@
|
||||||
<Style TargetType="{x:Type StatusBar}" BasedOn="{StaticResource {x:Type StatusBar}}">
|
<Style TargetType="{x:Type StatusBar}" BasedOn="{StaticResource {x:Type StatusBar}}">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<!--don't mind me, MultiDataTrigger just sucks-->
|
<!--don't mind me, MultiDataTrigger just sucks-->
|
||||||
<DataTrigger Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Ready}">
|
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Ready}">
|
||||||
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AccentBrush}}" />
|
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AccentBrush}}" />
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Completed}">
|
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Completed}">
|
||||||
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AccentBrush}}" />
|
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AccentBrush}}" />
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Loading}">
|
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Loading}">
|
||||||
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AlertBrush}}" />
|
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AlertBrush}}" />
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Stopping}">
|
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Stopping}">
|
||||||
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AlertBrush}}" />
|
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.AlertBrush}}" />
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Stopped}">
|
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Stopped}">
|
||||||
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
|
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Failed}">
|
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Failed}">
|
||||||
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
|
<Setter Property="Background" Value="{DynamicResource {x:Static adonisUi:Brushes.ErrorBrush}}" />
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding StatusChangeAttempted, Source={x:Static services:ApplicationService.ThreadWorkerView}}" Value="True">
|
<DataTrigger Binding="{Binding StatusChangeAttempted, Source={x:Static local:Services.ApplicationService.ThreadWorkerView}}" Value="True">
|
||||||
<DataTrigger.EnterActions>
|
<DataTrigger.EnterActions>
|
||||||
<BeginStoryboard>
|
<BeginStoryboard>
|
||||||
<Storyboard Duration="0:0:0.8">
|
<Storyboard Duration="0:0:0.8">
|
||||||
|
|
@ -742,7 +659,7 @@
|
||||||
</BeginStoryboard>
|
</BeginStoryboard>
|
||||||
</DataTrigger.EnterActions>
|
</DataTrigger.EnterActions>
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding OperationCancelled, Source={x:Static services:ApplicationService.ThreadWorkerView}}" Value="True">
|
<DataTrigger Binding="{Binding OperationCancelled, Source={x:Static local:Services.ApplicationService.ThreadWorkerView}}" Value="True">
|
||||||
<DataTrigger.EnterActions>
|
<DataTrigger.EnterActions>
|
||||||
<BeginStoryboard>
|
<BeginStoryboard>
|
||||||
<Storyboard Duration="0:0:1">
|
<Storyboard Duration="0:0:1">
|
||||||
|
|
@ -764,17 +681,17 @@
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
<TextBlock.Style>
|
<TextBlock.Style>
|
||||||
<Style TargetType="{x:Type TextBlock}">
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Text" Value="{Binding Status.Label}" />
|
<Setter Property="Text" Value="{Binding Status}" />
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Loading}">
|
<DataTrigger Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Loading}">
|
||||||
<Setter Property="Text" Value="{Binding Status.Label, StringFormat='{}{0} …'}" />
|
<Setter Property="Text" Value="{Binding Status, StringFormat='{}{0} …'}" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<MultiDataTrigger>
|
<MultiDataTrigger>
|
||||||
<MultiDataTrigger.Conditions>
|
<MultiDataTrigger.Conditions>
|
||||||
<Condition Binding="{Binding CanBeCanceled, Source={x:Static services:ApplicationService.ThreadWorkerView}}" Value="True" />
|
<Condition Binding="{Binding CanBeCanceled, Source={x:Static local:Services.ApplicationService.ThreadWorkerView}}" Value="True" />
|
||||||
<Condition Binding="{Binding Status.Kind}" Value="{x:Static local:EStatusKind.Loading}" />
|
<Condition Binding="{Binding Status}" Value="{x:Static local:EStatusKind.Loading}" />
|
||||||
</MultiDataTrigger.Conditions>
|
</MultiDataTrigger.Conditions>
|
||||||
<Setter Property="Text" Value="{Binding Status.Label, StringFormat='{}{0} … ESC to Cancel'}" />
|
<Setter Property="Text" Value="{Binding Status, StringFormat='{}{0} … ESC to Cancel'}" />
|
||||||
</MultiDataTrigger>
|
</MultiDataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
@ -792,22 +709,83 @@
|
||||||
</Viewbox>
|
</Viewbox>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
|
|
||||||
|
<StatusBarItem Width="30" HorizontalContentAlignment="Stretch" ToolTip="Auto Export Data Enabled">
|
||||||
|
<StatusBarItem.Style>
|
||||||
|
<Style TargetType="StatusBarItem">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsAutoExportData, Source={x:Static local:Settings.UserSettings.Default}}" Value="False">
|
||||||
|
<Setter Property="Visibility" Value="Hidden" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</StatusBarItem.Style>
|
||||||
|
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="DTA" />
|
||||||
|
</StatusBarItem>
|
||||||
|
|
||||||
|
<StatusBarItem Width="30" HorizontalContentAlignment="Stretch" ToolTip="Auto Save Properties Enabled">
|
||||||
|
<StatusBarItem.Style>
|
||||||
|
<Style TargetType="StatusBarItem">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsAutoSaveProps, Source={x:Static local:Settings.UserSettings.Default}}" Value="False">
|
||||||
|
<Setter Property="Visibility" Value="Hidden" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</StatusBarItem.Style>
|
||||||
|
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="PRP" />
|
||||||
|
</StatusBarItem>
|
||||||
|
|
||||||
|
<StatusBarItem Width="30" HorizontalContentAlignment="Stretch" ToolTip="Auto Save Textures Enabled">
|
||||||
|
<StatusBarItem.Style>
|
||||||
|
<Style TargetType="StatusBarItem">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsAutoSaveTextures, Source={x:Static local:Settings.UserSettings.Default}}" Value="False">
|
||||||
|
<Setter Property="Visibility" Value="Hidden" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</StatusBarItem.Style>
|
||||||
|
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="TEX" />
|
||||||
|
</StatusBarItem>
|
||||||
|
|
||||||
|
<StatusBarItem Width="30" HorizontalContentAlignment="Stretch" ToolTip="Auto Save Materials Enabled">
|
||||||
|
<StatusBarItem.Style>
|
||||||
|
<Style TargetType="StatusBarItem">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsAutoSaveMaterials, Source={x:Static local:Settings.UserSettings.Default}}" Value="False">
|
||||||
|
<Setter Property="Visibility" Value="Hidden" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</StatusBarItem.Style>
|
||||||
|
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="MAT" />
|
||||||
|
</StatusBarItem>
|
||||||
|
|
||||||
|
<StatusBarItem Width="30" HorizontalContentAlignment="Stretch" ToolTip="Auto Save Meshes Enabled">
|
||||||
|
<StatusBarItem.Style>
|
||||||
|
<Style TargetType="StatusBarItem">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsAutoSaveMeshes, Source={x:Static local:Settings.UserSettings.Default}}" Value="False">
|
||||||
|
<Setter Property="Visibility" Value="Hidden" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</StatusBarItem.Style>
|
||||||
|
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="MSH" />
|
||||||
|
</StatusBarItem>
|
||||||
|
|
||||||
<StatusBarItem Width="30" HorizontalContentAlignment="Stretch" ToolTip="Auto Open Sounds Enabled">
|
<StatusBarItem Width="30" HorizontalContentAlignment="Stretch" ToolTip="Auto Open Sounds Enabled">
|
||||||
<StatusBarItem.Style>
|
<StatusBarItem.Style>
|
||||||
<Style TargetType="StatusBarItem">
|
<Style TargetType="StatusBarItem">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding IsAutoOpenSounds, Source={x:Static settings:UserSettings.Default}}" Value="False">
|
<DataTrigger Binding="{Binding IsAutoOpenSounds, Source={x:Static local:Settings.UserSettings.Default}}" Value="False">
|
||||||
<Setter Property="Visibility" Value="Collapsed" />
|
<Setter Property="Visibility" Value="Hidden" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</StatusBarItem.Style>
|
</StatusBarItem.Style>
|
||||||
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="SND" />
|
<TextBlock HorizontalAlignment="Center" FontWeight="SemiBold" Text="SND" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
|
|
||||||
<StatusBarItem Margin="10 0 0 0">
|
|
||||||
<TextBlock Text="{Binding LastUpdateCheck, Source={x:Static local:Settings.UserSettings.Default}, Converter={x:Static converters:RelativeDateTimeConverter.Instance}, StringFormat=Last Refresh: {0}}" />
|
|
||||||
</StatusBarItem>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
</StatusBar>
|
</StatusBar>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
@ -14,8 +13,8 @@ using FModel.Views;
|
||||||
using FModel.Views.Resources.Controls;
|
using FModel.Views.Resources.Controls;
|
||||||
using ICSharpCode.AvalonEdit.Editing;
|
using ICSharpCode.AvalonEdit.Editing;
|
||||||
|
|
||||||
namespace FModel;
|
namespace FModel
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for MainWindow.xaml
|
/// Interaction logic for MainWindow.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -28,8 +27,20 @@ public partial class MainWindow
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
|
CommandBindings.Add(new CommandBinding(new RoutedCommand("AutoExportData", typeof(MainWindow), new InputGestureCollection
|
||||||
|
{new KeyGesture(UserSettings.Default.AutoExportData.Key, UserSettings.Default.AutoExportData.Modifiers)}), OnAutoTriggerExecuted));
|
||||||
|
CommandBindings.Add(new CommandBinding(new RoutedCommand("AutoSaveProps", typeof(MainWindow), new InputGestureCollection
|
||||||
|
{new KeyGesture(UserSettings.Default.AutoSaveProps.Key, UserSettings.Default.AutoSaveProps.Modifiers)}), OnAutoTriggerExecuted));
|
||||||
|
CommandBindings.Add(new CommandBinding(new RoutedCommand("AutoSaveTextures", typeof(MainWindow), new InputGestureCollection
|
||||||
|
{new KeyGesture(UserSettings.Default.AutoSaveTextures.Key, UserSettings.Default.AutoSaveTextures.Modifiers)}), OnAutoTriggerExecuted));
|
||||||
|
CommandBindings.Add(new CommandBinding(new RoutedCommand("AutoSaveMaterials", typeof(MainWindow), new InputGestureCollection
|
||||||
|
{new KeyGesture(UserSettings.Default.AutoSaveMaterials.Key, UserSettings.Default.AutoSaveMaterials.Modifiers)}), OnAutoTriggerExecuted));
|
||||||
|
CommandBindings.Add(new CommandBinding(new RoutedCommand("AutoSaveMeshes", typeof(MainWindow), new InputGestureCollection
|
||||||
|
{new KeyGesture(UserSettings.Default.AutoSaveMeshes.Key, UserSettings.Default.AutoSaveMeshes.Modifiers)}), OnAutoTriggerExecuted));
|
||||||
|
CommandBindings.Add(new CommandBinding(new RoutedCommand("AutoOpenSounds", typeof(MainWindow), new InputGestureCollection
|
||||||
|
{new KeyGesture(UserSettings.Default.AutoOpenSounds.Key, UserSettings.Default.AutoOpenSounds.Modifiers)}), OnAutoTriggerExecuted));
|
||||||
CommandBindings.Add(new CommandBinding(new RoutedCommand("ReloadMappings", typeof(MainWindow), new InputGestureCollection {new KeyGesture(Key.F12)}), OnMappingsReload));
|
CommandBindings.Add(new CommandBinding(new RoutedCommand("ReloadMappings", typeof(MainWindow), new InputGestureCollection {new KeyGesture(Key.F12)}), OnMappingsReload));
|
||||||
CommandBindings.Add(new CommandBinding(ApplicationCommands.Find, (_, _) => OnOpenAvalonFinder()));
|
CommandBindings.Add(new CommandBinding(ApplicationCommands.Find, (s, e) => OnOpenAvalonFinder()));
|
||||||
|
|
||||||
DataContext = _applicationView;
|
DataContext = _applicationView;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
@ -40,56 +51,34 @@ public partial class MainWindow
|
||||||
|
|
||||||
private void OnClosing(object sender, CancelEventArgs e)
|
private void OnClosing(object sender, CancelEventArgs e)
|
||||||
{
|
{
|
||||||
|
_applicationView.CustomDirectories.Save();
|
||||||
_discordHandler.Dispose();
|
_discordHandler.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnLoaded(object sender, RoutedEventArgs e)
|
private async void OnLoaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var newOrUpdated = UserSettings.Default.ShowChangelog;
|
ApplicationService.ApiEndpointView.FModelApi.CheckForUpdates(UserSettings.Default.UpdateMode);
|
||||||
#if !DEBUG
|
|
||||||
ApplicationService.ApiEndpointView.FModelApi.CheckForUpdates(true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (UserSettings.Default.AesReload)
|
switch (UserSettings.Default.AesReload)
|
||||||
{
|
{
|
||||||
case EAesReload.Always:
|
case EAesReload.Always:
|
||||||
await _applicationView.CUE4Parse.RefreshAes();
|
await _applicationView.CUE4Parse.RefreshAes();
|
||||||
break;
|
break;
|
||||||
case EAesReload.OncePerDay when UserSettings.Default.CurrentDir.LastAesReload != DateTime.Today:
|
case EAesReload.OncePerDay when UserSettings.Default.LastAesReload != DateTime.Today:
|
||||||
UserSettings.Default.CurrentDir.LastAesReload = DateTime.Today;
|
UserSettings.Default.LastAesReload = DateTime.Today;
|
||||||
await _applicationView.CUE4Parse.RefreshAes();
|
await _applicationView.CUE4Parse.RefreshAes();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ApplicationViewModel.InitOodle();
|
await _applicationView.CUE4Parse.InitInformation();
|
||||||
await ApplicationViewModel.InitZlib();
|
|
||||||
await _applicationView.CUE4Parse.Initialize();
|
await _applicationView.CUE4Parse.Initialize();
|
||||||
await _applicationView.AesManager.InitAes();
|
await _applicationView.AesManager.InitAes();
|
||||||
await _applicationView.UpdateProvider(true);
|
await _applicationView.AesManager.UpdateProvider(true);
|
||||||
#if !DEBUG
|
await _applicationView.CUE4Parse.InitBenMappings();
|
||||||
await _applicationView.CUE4Parse.InitInformation();
|
await _applicationView.InitVgmStream();
|
||||||
#endif
|
|
||||||
await Task.WhenAll(
|
|
||||||
_applicationView.CUE4Parse.VerifyConsoleVariables(),
|
|
||||||
_applicationView.CUE4Parse.VerifyOnDemandArchives(),
|
|
||||||
_applicationView.CUE4Parse.InitMappings(),
|
|
||||||
ApplicationViewModel.InitVgmStream(),
|
|
||||||
ApplicationViewModel.InitImGuiSettings(newOrUpdated),
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
if (UserSettings.Default.DiscordRpc == EDiscordRpc.Always)
|
|
||||||
_discordHandler.Initialize(_applicationView.GameDisplayName);
|
|
||||||
})
|
|
||||||
).ConfigureAwait(false);
|
|
||||||
|
|
||||||
#if DEBUG
|
if (UserSettings.Default.DiscordRpc == EDiscordRpc.Always)
|
||||||
// await _threadWorkerView.Begin(cancellationToken =>
|
_discordHandler.Initialize(_applicationView.CUE4Parse.Game);
|
||||||
// _applicationView.CUE4Parse.Extract(cancellationToken,
|
|
||||||
// "FortniteGame/Content/Athena/Apollo/Maps/UI/Apollo_Terrain_Minimap.uasset"));
|
|
||||||
// await _threadWorkerView.Begin(cancellationToken =>
|
|
||||||
// _applicationView.CUE4Parse.Extract(cancellationToken,
|
|
||||||
// "FortniteGame/Content/Environments/Helios/Props/GlacierHotel/GlacierHotel_Globe_A/Meshes/SM_GlacierHotel_Globe_A.uasset"));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGridSplitterDoubleClick(object sender, MouseButtonEventArgs e)
|
private void OnGridSplitterDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
|
@ -99,20 +88,16 @@ public partial class MainWindow
|
||||||
|
|
||||||
private void OnWindowKeyDown(object sender, KeyEventArgs e)
|
private void OnWindowKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.OriginalSource is TextBox || e.OriginalSource is TextArea && Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
|
if (e.OriginalSource is TextArea or TextBox)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_threadWorkerView.CanBeCanceled && e.Key == Key.Escape)
|
if (_threadWorkerView.CanBeCanceled && e.Key == Key.Escape)
|
||||||
{
|
{
|
||||||
_applicationView.Status.SetStatus(EStatusKind.Stopping);
|
_applicationView.Status = EStatusKind.Stopping;
|
||||||
_threadWorkerView.Cancel();
|
_threadWorkerView.Cancel();
|
||||||
}
|
}
|
||||||
else if (_applicationView.Status.IsReady && e.Key == Key.F && Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
|
else if (_applicationView.IsReady && e.Key == Key.F && Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
|
||||||
OnSearchViewClick(null, null);
|
OnSearchViewClick(null, null);
|
||||||
else if (e.Key == Key.Left && _applicationView.CUE4Parse.TabControl.SelectedTab.HasImage)
|
|
||||||
_applicationView.CUE4Parse.TabControl.SelectedTab.GoPreviousImage();
|
|
||||||
else if (e.Key == Key.Right && _applicationView.CUE4Parse.TabControl.SelectedTab.HasImage)
|
|
||||||
_applicationView.CUE4Parse.TabControl.SelectedTab.GoNextImage();
|
|
||||||
else if (UserSettings.Default.AssetAddTab.IsTriggered(e.Key))
|
else if (UserSettings.Default.AssetAddTab.IsTriggered(e.Key))
|
||||||
_applicationView.CUE4Parse.TabControl.AddTab();
|
_applicationView.CUE4Parse.TabControl.AddTab();
|
||||||
else if (UserSettings.Default.AssetRemoveTab.IsTriggered(e.Key))
|
else if (UserSettings.Default.AssetRemoveTab.IsTriggered(e.Key))
|
||||||
|
|
@ -142,7 +127,32 @@ public partial class MainWindow
|
||||||
|
|
||||||
private async void OnMappingsReload(object sender, ExecutedRoutedEventArgs e)
|
private async void OnMappingsReload(object sender, ExecutedRoutedEventArgs e)
|
||||||
{
|
{
|
||||||
await _applicationView.CUE4Parse.InitMappings(true);
|
await _applicationView.CUE4Parse.InitBenMappings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAutoTriggerExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
switch ((e.Command as RoutedCommand)?.Name)
|
||||||
|
{
|
||||||
|
case "AutoExportData":
|
||||||
|
UserSettings.Default.IsAutoExportData = !UserSettings.Default.IsAutoExportData;
|
||||||
|
break;
|
||||||
|
case "AutoSaveProps":
|
||||||
|
UserSettings.Default.IsAutoSaveProps = !UserSettings.Default.IsAutoSaveProps;
|
||||||
|
break;
|
||||||
|
case "AutoSaveTextures":
|
||||||
|
UserSettings.Default.IsAutoSaveTextures = !UserSettings.Default.IsAutoSaveTextures;
|
||||||
|
break;
|
||||||
|
case "AutoSaveMaterials":
|
||||||
|
UserSettings.Default.IsAutoSaveMaterials = !UserSettings.Default.IsAutoSaveMaterials;
|
||||||
|
break;
|
||||||
|
case "AutoSaveMeshes":
|
||||||
|
UserSettings.Default.IsAutoSaveMeshes = !UserSettings.Default.IsAutoSaveMeshes;
|
||||||
|
break;
|
||||||
|
case "AutoOpenSounds":
|
||||||
|
UserSettings.Default.IsAutoOpenSounds = !UserSettings.Default.IsAutoOpenSounds;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOpenAvalonFinder()
|
private void OnOpenAvalonFinder()
|
||||||
|
|
@ -180,11 +190,6 @@ public partial class MainWindow
|
||||||
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
||||||
{
|
{
|
||||||
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExportFolder(cancellationToken, folder); });
|
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExportFolder(cancellationToken, folder); });
|
||||||
FLogger.Append(ELog.Information, () =>
|
|
||||||
{
|
|
||||||
FLogger.Text("Successfully exported ", Constants.WHITE);
|
|
||||||
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.RawDataDirectory, true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,50 +198,16 @@ public partial class MainWindow
|
||||||
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
||||||
{
|
{
|
||||||
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.SaveFolder(cancellationToken, folder); });
|
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.SaveFolder(cancellationToken, folder); });
|
||||||
FLogger.Append(ELog.Information, () =>
|
|
||||||
{
|
|
||||||
FLogger.Text("Successfully saved ", Constants.WHITE);
|
|
||||||
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.PropertiesDirectory, true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnFolderTextureClick(object sender, RoutedEventArgs e)
|
private void OnSaveDirectoryClick(object sender, RoutedEventArgs e)
|
||||||
{
|
|
||||||
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
|
||||||
{
|
|
||||||
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.TextureFolder(cancellationToken, folder); });
|
|
||||||
FLogger.Append(ELog.Information, () =>
|
|
||||||
{
|
|
||||||
FLogger.Text("Successfully saved ", Constants.WHITE);
|
|
||||||
FLogger.Link(folder.PathAtThisPoint, UserSettings.Default.TextureDirectory, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnFolderModelClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
|
||||||
{
|
|
||||||
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ModelFolder(cancellationToken, folder); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnFolderAnimationClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (AssetsFolderName.SelectedItem is TreeItem folder)
|
|
||||||
{
|
|
||||||
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.AnimationFolder(cancellationToken, folder); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFavoriteDirectoryClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
{
|
||||||
if (AssetsFolderName.SelectedItem is not TreeItem folder) return;
|
if (AssetsFolderName.SelectedItem is not TreeItem folder) return;
|
||||||
|
|
||||||
_applicationView.CustomDirectories.Add(new CustomDirectory(folder.Header, folder.PathAtThisPoint));
|
_applicationView.CustomDirectories.Add(new CustomDirectory(folder.Header, folder.PathAtThisPoint));
|
||||||
FLogger.Append(ELog.Information, () =>
|
FLogger.AppendInformation();
|
||||||
FLogger.Text($"Successfully saved '{folder.PathAtThisPoint}' as a new favorite directory", Constants.WHITE, true));
|
FLogger.AppendText($"Successfully saved '{folder.PathAtThisPoint}' as a new custom directory", Constants.WHITE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCopyDirectoryPathClick(object sender, RoutedEventArgs e)
|
private void OnCopyDirectoryPathClick(object sender, RoutedEventArgs e)
|
||||||
|
|
@ -257,26 +228,10 @@ public partial class MainWindow
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var filters = textBox.Text.Trim().Split(' ');
|
var filters = textBox.Text.Trim().Split(' ');
|
||||||
folder.AssetsList.AssetsView.Filter = o => { return o is AssetItem assetItem && filters.All(x => assetItem.FullPath.SubstringAfterLast('/').Contains(x, StringComparison.OrdinalIgnoreCase)); };
|
folder.AssetsList.AssetsView.Filter = o =>
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
{
|
||||||
if (!_applicationView.Status.IsReady || sender is not ListBox listBox) return;
|
return o is AssetItem assetItem && filters.All(x => assetItem.FullPath.SubstringAfterLast('/').Contains(x, StringComparison.OrdinalIgnoreCase));
|
||||||
UserSettings.Default.LoadingMode = ELoadingMode.Multiple;
|
};
|
||||||
_applicationView.LoadingModes.LoadCommand.Execute(listBox.SelectedItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnPreviewKeyDown(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (!_applicationView.Status.IsReady || sender is not ListBox listBox) return;
|
|
||||||
|
|
||||||
switch (e.Key)
|
|
||||||
{
|
|
||||||
case Key.Enter:
|
|
||||||
var selectedItems = listBox.SelectedItems.Cast<AssetItem>().ToList();
|
|
||||||
await _threadWorkerView.Begin(cancellationToken => { _applicationView.CUE4Parse.ExtractSelected(cancellationToken, selectedItems); });
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
<SyntaxDefinition name="Changelog" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
|
||||||
|
|
||||||
<RuleSet name="diff">
|
|
||||||
<Span multiline="false" foreground="#98C379">
|
|
||||||
<Begin>^\+</Begin>
|
|
||||||
<End>.*(?:\t|\s{2,})+</End>
|
|
||||||
</Span>
|
|
||||||
<Span multiline="false" foreground="#E06C75">
|
|
||||||
<Begin>^\-</Begin>
|
|
||||||
<End>.*(?:\t|\s{2,})+</End>
|
|
||||||
</Span>
|
|
||||||
<Span multiline="false" foreground="#61AFEF">
|
|
||||||
<Begin>^\~</Begin>
|
|
||||||
<End>.*(?:\t|\s{2,})+</End>
|
|
||||||
</Span>
|
|
||||||
</RuleSet>
|
|
||||||
|
|
||||||
<RuleSet name="doc" ignoreCase="false">
|
|
||||||
<Span multiline="false" foreground="#7F848E">
|
|
||||||
<Begin>.*(?:\t|\#{1}|\s{2,})+</Begin>
|
|
||||||
<End>\r\n</End>
|
|
||||||
</Span>
|
|
||||||
<Span multiline="false" underline="true">
|
|
||||||
<Begin>^[0-9]\..*</Begin>
|
|
||||||
</Span>
|
|
||||||
<Keywords underline="true">
|
|
||||||
<Word>ADDED</Word>
|
|
||||||
<Word>FIXED</Word>
|
|
||||||
<Word>REMOVED</Word>
|
|
||||||
<Word>IMPROVED</Word>
|
|
||||||
</Keywords>
|
|
||||||
</RuleSet>
|
|
||||||
|
|
||||||
<RuleSet>
|
|
||||||
<Import ruleSet="diff" />
|
|
||||||
<Import ruleSet="doc" />
|
|
||||||
</RuleSet>
|
|
||||||
|
|
||||||
</SyntaxDefinition>
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<SyntaxDefinition name="Verse Visual Process Language" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"
|
|
||||||
extensions=".verse">
|
|
||||||
|
|
||||||
<Color name="Constant" foreground="#C792DD" />
|
|
||||||
<Color name="Method" foreground="#FFCB6B" />
|
|
||||||
<Color name="Variable" foreground="#529EFF" />
|
|
||||||
<Color name="Tag1" foreground="#F07178" />
|
|
||||||
<Color name="Tag2" foreground="#7F848E" />
|
|
||||||
<Color name="Parameter" foreground="#89DDFF" />
|
|
||||||
<Color name="Class" foreground="#FF9D5E" />
|
|
||||||
<Color name="Type" foreground="#C3E88D" />
|
|
||||||
<Color name="Punctuation" foreground="#E5C07B" />
|
|
||||||
|
|
||||||
<RuleSet>
|
|
||||||
<Rule color="Constant">\b(?:module|class|attribute|interface|struct|external|enum|where|comparable|component|void|type|subtype)|\@\w+</Rule>
|
|
||||||
<Rule color="Method">\w+(?:\'.*\')?(?=(?:<\w+>)+\()</Rule>
|
|
||||||
<Rule color="Variable">\w+(?:\'.*\')?(?=(?:<\w+>)+\^?:)</Rule>
|
|
||||||
<Rule color="Tag1"><\w+></Rule>
|
|
||||||
<Rule color="Tag2">(?:^using|\# ).*</Rule>
|
|
||||||
<Rule color="Parameter">(?!\()\w+(?=:)</Rule>
|
|
||||||
<Rule color="Class">\w+(?=(?:<\w+>)+\s:=)</Rule>
|
|
||||||
<Rule color="Type">(?<=:)[\w\[\]\?]+</Rule>
|
|
||||||
<Rule color="Punctuation">[()*+,\-.\/:;<=>?[\]^`{|}~]</Rule>
|
|
||||||
</RuleSet>
|
|
||||||
</SyntaxDefinition>
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
in vec3 fPos;
|
|
||||||
in vec3 fColor;
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
FragColor = vec4(fColor, 1.0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 0) in vec3 vPos;
|
|
||||||
layout (location = 1) in vec3 vColor;
|
|
||||||
|
|
||||||
uniform mat4 uView;
|
|
||||||
uniform mat4 uProjection;
|
|
||||||
uniform mat4 uInstanceMatrix;
|
|
||||||
|
|
||||||
out vec3 fPos;
|
|
||||||
out vec3 fColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_PointSize = 7.5f;
|
|
||||||
gl_Position = uProjection * uView * uInstanceMatrix * vec4(vPos, 1.0);
|
|
||||||
fPos = vec3(uInstanceMatrix * vec4(vPos, 1.0));
|
|
||||||
fColor = vColor;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 125 KiB |
BIN
FModel/Resources/city_pin.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
|
|
@ -1,20 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 0) in vec3 vPos;
|
|
||||||
|
|
||||||
uniform mat4 uView;
|
|
||||||
uniform mat4 uProjection;
|
|
||||||
uniform mat4 uInstanceMatrix;
|
|
||||||
uniform mat4 uCollisionMatrix;
|
|
||||||
uniform float uScaleDown;
|
|
||||||
|
|
||||||
out vec3 fPos;
|
|
||||||
out vec3 fColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_PointSize = 7.5f;
|
|
||||||
gl_Position = uProjection * uView * uInstanceMatrix * uCollisionMatrix * vec4(vPos.xzy * uScaleDown, 1.0);
|
|
||||||
fPos = vec3(uInstanceMatrix * uCollisionMatrix * vec4(vPos.xzy * uScaleDown, 1.0));
|
|
||||||
fColor = vec3(1.0);
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 831 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
|
@ -1,294 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
#define PI 3.1415926535897932384626433832795
|
|
||||||
#define MAX_UV_COUNT 8
|
|
||||||
#define MAX_LIGHT_COUNT 100
|
|
||||||
|
|
||||||
in vec3 fPos;
|
|
||||||
in vec3 fNormal;
|
|
||||||
in vec3 fTangent;
|
|
||||||
in vec2 fTexCoords;
|
|
||||||
flat in int fTexLayer;
|
|
||||||
in vec4 fColor;
|
|
||||||
|
|
||||||
struct Texture
|
|
||||||
{
|
|
||||||
sampler2D Sampler;
|
|
||||||
vec4 Color;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Boost
|
|
||||||
{
|
|
||||||
vec3 Color;
|
|
||||||
float Exponent;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AoParams
|
|
||||||
{
|
|
||||||
sampler2D Sampler;
|
|
||||||
float AmbientOcclusion;
|
|
||||||
|
|
||||||
Boost ColorBoost;
|
|
||||||
bool HasColorBoost;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Parameters
|
|
||||||
{
|
|
||||||
Texture Diffuse[MAX_UV_COUNT];
|
|
||||||
Texture Normals[MAX_UV_COUNT];
|
|
||||||
Texture SpecularMasks[MAX_UV_COUNT];
|
|
||||||
Texture Emissive[MAX_UV_COUNT];
|
|
||||||
|
|
||||||
AoParams Ao;
|
|
||||||
bool HasAo;
|
|
||||||
|
|
||||||
vec4 EmissiveRegion;
|
|
||||||
float RoughnessMin;
|
|
||||||
float RoughnessMax;
|
|
||||||
float EmissiveMult;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BaseLight
|
|
||||||
{
|
|
||||||
vec4 Color;
|
|
||||||
vec3 Position;
|
|
||||||
float Intensity;
|
|
||||||
};
|
|
||||||
|
|
||||||
//struct PointLight
|
|
||||||
//{
|
|
||||||
// BaseLight Light;
|
|
||||||
//
|
|
||||||
// float Linear;
|
|
||||||
// float Quadratic;
|
|
||||||
//};
|
|
||||||
//
|
|
||||||
//struct SpotLight
|
|
||||||
//{
|
|
||||||
// BaseLight Light;
|
|
||||||
//
|
|
||||||
// float InnerConeAngle;
|
|
||||||
// float OuterConeAngle;
|
|
||||||
// float Attenuation;
|
|
||||||
//};
|
|
||||||
|
|
||||||
struct Light {
|
|
||||||
BaseLight Base;
|
|
||||||
|
|
||||||
float InnerConeAngle;
|
|
||||||
float OuterConeAngle;
|
|
||||||
float Attenuation;
|
|
||||||
|
|
||||||
float Linear;
|
|
||||||
float Quadratic;
|
|
||||||
|
|
||||||
int Type; // 0 Point, 1 Spot
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform Parameters uParameters;
|
|
||||||
uniform Light uLights[MAX_LIGHT_COUNT];
|
|
||||||
uniform int uNumLights;
|
|
||||||
uniform int uUvCount;
|
|
||||||
uniform float uOpacity;
|
|
||||||
uniform bool uHasVertexColors;
|
|
||||||
uniform vec3 uSectionColor;
|
|
||||||
uniform bool bVertexColors[6];
|
|
||||||
uniform vec3 uViewPos;
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
int LayerToIndex()
|
|
||||||
{
|
|
||||||
return clamp(fTexLayer, 0, uUvCount - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 SamplerToVector(sampler2D s, vec2 coords)
|
|
||||||
{
|
|
||||||
return texture(s, coords);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 SamplerToVector(sampler2D s)
|
|
||||||
{
|
|
||||||
return SamplerToVector(s, fTexCoords);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 ComputeNormals(int layer)
|
|
||||||
{
|
|
||||||
vec3 normal = SamplerToVector(uParameters.Normals[layer].Sampler).rgb * 2.0 - 1.0;
|
|
||||||
|
|
||||||
vec3 t = normalize(fTangent);
|
|
||||||
vec3 n = normalize(fNormal);
|
|
||||||
vec3 b = -normalize(cross(n, t));
|
|
||||||
mat3 tbn = mat3(t, b, n);
|
|
||||||
|
|
||||||
return normalize(tbn * normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 schlickFresnel(vec3 fLambert, float metallic, float hDotv)
|
|
||||||
{
|
|
||||||
vec3 f0 = vec3(0.04);
|
|
||||||
f0 = mix(f0, fLambert, metallic);
|
|
||||||
return f0 + (1.0 - f0) * pow(clamp(1.0 - hDotv, 0.0, 1.0), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
float ggxDistribution(float roughness, float nDoth)
|
|
||||||
{
|
|
||||||
float alpha2 = roughness * roughness * roughness * roughness;
|
|
||||||
float d = nDoth * nDoth * (alpha2- 1.0) + 1.0;
|
|
||||||
return alpha2 / (PI * d * d);
|
|
||||||
}
|
|
||||||
|
|
||||||
float geomSmith(float roughness, float dp)
|
|
||||||
{
|
|
||||||
float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;
|
|
||||||
float denom = dp * (1.0 - k) + k;
|
|
||||||
return dp / denom;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 CalcLight(int layer, vec3 normals, vec3 position, vec3 color, float attenuation, bool global)
|
|
||||||
{
|
|
||||||
vec3 fLambert = SamplerToVector(uParameters.Diffuse[layer].Sampler).rgb * uParameters.Diffuse[layer].Color.rgb;
|
|
||||||
vec3 specular_masks = SamplerToVector(uParameters.SpecularMasks[layer].Sampler).rgb;
|
|
||||||
float cavity = specular_masks.g;
|
|
||||||
if (uParameters.HasAo)
|
|
||||||
{
|
|
||||||
cavity = SamplerToVector(uParameters.Ao.Sampler).g;
|
|
||||||
}
|
|
||||||
float roughness = mix(uParameters.RoughnessMin, uParameters.RoughnessMax, specular_masks.b);
|
|
||||||
|
|
||||||
vec3 l = normalize(uViewPos - fPos);
|
|
||||||
|
|
||||||
vec3 n = normals;
|
|
||||||
vec3 v = normalize(position - fPos);
|
|
||||||
vec3 h = normalize(v + l);
|
|
||||||
|
|
||||||
float nDotH = max(dot(n, h), 0.0);
|
|
||||||
float hDotv = max(dot(h, v), 0.0);
|
|
||||||
float nDotL = max(dot(n, l), 0.0);
|
|
||||||
float nDotV = max(dot(n, v), 0.0);
|
|
||||||
|
|
||||||
vec3 f = schlickFresnel(fLambert, specular_masks.g, hDotv);
|
|
||||||
|
|
||||||
vec3 kS = f;
|
|
||||||
vec3 kD = 1.0 - kS;
|
|
||||||
kD *= 1.0 - cavity;
|
|
||||||
|
|
||||||
vec3 specBrdfNom = ggxDistribution(roughness, nDotH) * geomSmith(roughness, nDotL) * geomSmith(roughness, nDotV) * f;
|
|
||||||
float specBrdfDenom = 4.0 * nDotV * nDotL + 0.0001;
|
|
||||||
vec3 specBrdf = specBrdfNom / specBrdfDenom;
|
|
||||||
|
|
||||||
vec3 diffuseBrdf = fLambert;
|
|
||||||
if (!global) diffuseBrdf = kD * fLambert / PI;
|
|
||||||
return (diffuseBrdf + specBrdf) * color * attenuation * nDotL;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 CalcBaseLight(int layer, vec3 normals, BaseLight base, float attenuation, bool global)
|
|
||||||
{
|
|
||||||
return CalcLight(layer, normals, base.Position, base.Color.rgb * base.Intensity, attenuation, global);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 CalcPointLight(int layer, vec3 normals, Light light)
|
|
||||||
{
|
|
||||||
float distanceToLight = length(light.Base.Position - fPos);
|
|
||||||
float attenuation = 1.0 / (1.0 + light.Linear * distanceToLight + light.Quadratic * pow(distanceToLight, 2));
|
|
||||||
return CalcBaseLight(layer, normals, light.Base, attenuation, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 CalcSpotLight(int layer, vec3 normals, Light light)
|
|
||||||
{
|
|
||||||
vec3 v = normalize(light.Base.Position - fPos);
|
|
||||||
float inner = cos(radians(light.InnerConeAngle));
|
|
||||||
float outer = cos(radians(light.OuterConeAngle));
|
|
||||||
|
|
||||||
float distanceToLight = length(light.Base.Position - fPos);
|
|
||||||
float theta = dot(v, normalize(-vec3(0, -1, 0)));
|
|
||||||
float epsilon = inner - outer;
|
|
||||||
float attenuation = 1.0 / (1.0 + light.Attenuation * pow(distanceToLight, 2));
|
|
||||||
light.Base.Intensity *= smoothstep(0.0, 1.0, (theta - outer) / epsilon);
|
|
||||||
|
|
||||||
if(theta > outer)
|
|
||||||
{
|
|
||||||
return CalcBaseLight(layer, normals, light.Base, attenuation, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return vec3(0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
int layer = LayerToIndex();
|
|
||||||
vec3 normals = ComputeNormals(layer);
|
|
||||||
vec3 lightDir = normalize(uViewPos - fPos);
|
|
||||||
float diffuseFactor = max(dot(normals, lightDir), 0.4);
|
|
||||||
|
|
||||||
if (bVertexColors[1])
|
|
||||||
{
|
|
||||||
FragColor = vec4(diffuseFactor * uSectionColor, uOpacity);
|
|
||||||
}
|
|
||||||
else if (bVertexColors[2] && uHasVertexColors)
|
|
||||||
{
|
|
||||||
FragColor = vec4(diffuseFactor * fColor.rgb, fColor.a);
|
|
||||||
}
|
|
||||||
else if (bVertexColors[3])
|
|
||||||
{
|
|
||||||
FragColor = vec4(normals, uOpacity);
|
|
||||||
}
|
|
||||||
else if (bVertexColors[4])
|
|
||||||
{
|
|
||||||
vec4 diffuse = SamplerToVector(uParameters.Diffuse[0].Sampler);
|
|
||||||
FragColor = vec4(diffuseFactor * diffuse.rgb, diffuse.a);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vec4 diffuse = SamplerToVector(uParameters.Diffuse[layer].Sampler);
|
|
||||||
vec3 result = diffuseFactor * diffuse.rgb * uParameters.Diffuse[layer].Color.rgb;
|
|
||||||
|
|
||||||
if (uParameters.HasAo)
|
|
||||||
{
|
|
||||||
vec3 m = SamplerToVector(uParameters.Ao.Sampler).rgb;
|
|
||||||
if (uParameters.Ao.HasColorBoost)
|
|
||||||
{
|
|
||||||
vec3 color = uParameters.Ao.ColorBoost.Color * uParameters.Ao.ColorBoost.Exponent;
|
|
||||||
result = mix(result, result * color, m.b);
|
|
||||||
}
|
|
||||||
result *= m.r;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 coords = fTexCoords;
|
|
||||||
if (coords.x > uParameters.EmissiveRegion.x &&
|
|
||||||
coords.y > uParameters.EmissiveRegion.y &&
|
|
||||||
coords.x < uParameters.EmissiveRegion.z &&
|
|
||||||
coords.y < uParameters.EmissiveRegion.w)
|
|
||||||
{
|
|
||||||
coords.x -= uParameters.EmissiveRegion.x;
|
|
||||||
coords.y -= uParameters.EmissiveRegion.y;
|
|
||||||
coords.x *= 1.0 / (uParameters.EmissiveRegion.z - uParameters.EmissiveRegion.x);
|
|
||||||
coords.y *= 1.0 / (uParameters.EmissiveRegion.w - uParameters.EmissiveRegion.y);
|
|
||||||
vec4 emissive = SamplerToVector(uParameters.Emissive[layer].Sampler, coords);
|
|
||||||
result += uParameters.Emissive[layer].Color.rgb * emissive.rgb * uParameters.EmissiveMult;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
result += CalcLight(layer, normals, uViewPos, vec3(1.0), 1.0, false);
|
|
||||||
|
|
||||||
vec3 lights = vec3(uNumLights > 0 ? 0 : 1);
|
|
||||||
for (int i = 0; i < uNumLights; i++)
|
|
||||||
{
|
|
||||||
if (uLights[i].Type == 0)
|
|
||||||
{
|
|
||||||
lights += CalcPointLight(layer, normals, uLights[i]);
|
|
||||||
}
|
|
||||||
else if (uLights[i].Type == 1)
|
|
||||||
{
|
|
||||||
lights += CalcSpotLight(layer, normals, uLights[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result *= lights; // use * to darken the scene, + to lighten it
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result / (result + vec3(1.0));
|
|
||||||
FragColor = vec4(pow(result, vec3(1.0 / 2.2)), uOpacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 1) in vec3 vPos;
|
|
||||||
layout (location = 2) in vec3 vNormal;
|
|
||||||
layout (location = 3) in vec3 vTangent;
|
|
||||||
layout (location = 4) in vec2 vTexCoords;
|
|
||||||
layout (location = 5) in int vTexLayer;
|
|
||||||
layout (location = 6) in float vColor;
|
|
||||||
layout (location = 7) in vec4 vBoneInfluence;
|
|
||||||
layout (location = 8) in vec4 vBoneInfluenceExtra;
|
|
||||||
layout (location = 9) in mat4 vInstanceMatrix;
|
|
||||||
layout (location = 13) in vec3 vMorphTargetPos;
|
|
||||||
layout (location = 14) in vec3 vMorphTargetTangent;
|
|
||||||
|
|
||||||
layout(std430, binding = 1) buffer BoneMatrices
|
|
||||||
{
|
|
||||||
mat4 uFinalBonesMatrix[];
|
|
||||||
};
|
|
||||||
layout(std430, binding = 2) buffer RestBoneMatrices
|
|
||||||
{
|
|
||||||
mat4 uRestBonesMatrix[];
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform mat4 uView;
|
|
||||||
uniform mat4 uProjection;
|
|
||||||
uniform float uMorphTime;
|
|
||||||
uniform bool uIsAnimated;
|
|
||||||
|
|
||||||
out vec3 fPos;
|
|
||||||
out vec3 fNormal;
|
|
||||||
out vec3 fTangent;
|
|
||||||
out vec2 fTexCoords;
|
|
||||||
flat out int fTexLayer;
|
|
||||||
out vec4 fColor;
|
|
||||||
|
|
||||||
vec4 unpackARGB(int color)
|
|
||||||
{
|
|
||||||
float a = float((color >> 24) & 0xFF);
|
|
||||||
float r = float((color >> 16) & 0xFF);
|
|
||||||
float g = float((color >> 8) & 0xFF);
|
|
||||||
float b = float((color >> 0) & 0xFF);
|
|
||||||
return vec4(r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 unpackBoneIDsAndWeights(int packedData)
|
|
||||||
{
|
|
||||||
return vec2(float((packedData >> 16) & 0xFFFF), float(packedData & 0xFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 bindPos = vec4(mix(vPos, vMorphTargetPos, uMorphTime), 1.0);
|
|
||||||
vec4 bindNormal = vec4(vNormal, 1.0);
|
|
||||||
vec4 bindTangent = vec4(mix(vTangent, vMorphTargetTangent, uMorphTime), 1.0);
|
|
||||||
|
|
||||||
vec4 finalPos = vec4(0.0);
|
|
||||||
vec4 finalNormal = vec4(0.0);
|
|
||||||
vec4 finalTangent = vec4(0.0);
|
|
||||||
if (uIsAnimated)
|
|
||||||
{
|
|
||||||
vec4 boneInfluences[2];
|
|
||||||
boneInfluences[0] = vBoneInfluence;
|
|
||||||
boneInfluences[1] = vBoneInfluenceExtra;
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
for(int j = 0 ; j < 4; j++)
|
|
||||||
{
|
|
||||||
vec2 boneInfluence = unpackBoneIDsAndWeights(int(boneInfluences[i][j]));
|
|
||||||
int boneIndex = int(boneInfluence.x);
|
|
||||||
float weight = boneInfluence.y;
|
|
||||||
|
|
||||||
mat4 boneMatrix = uFinalBonesMatrix[boneIndex] * inverse(uRestBonesMatrix[boneIndex]);
|
|
||||||
mat4 inverseBoneMatrix = transpose(inverse(boneMatrix));
|
|
||||||
|
|
||||||
finalPos += boneMatrix * bindPos * weight;
|
|
||||||
finalNormal += inverseBoneMatrix * bindNormal * weight;
|
|
||||||
finalTangent += inverseBoneMatrix * bindTangent * weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finalPos = normalize(finalPos);
|
|
||||||
finalNormal = normalize(finalNormal);
|
|
||||||
finalTangent = normalize(finalTangent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
finalPos = bindPos;
|
|
||||||
finalNormal = bindNormal;
|
|
||||||
finalTangent = bindTangent;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_Position = uProjection * uView * vInstanceMatrix * finalPos;
|
|
||||||
|
|
||||||
fPos = vec3(vInstanceMatrix * finalPos);
|
|
||||||
fNormal = vec3(transpose(inverse(vInstanceMatrix)) * finalNormal);
|
|
||||||
fTangent = vec3(transpose(inverse(vInstanceMatrix)) * finalTangent);
|
|
||||||
fTexCoords = vTexCoords;
|
|
||||||
fTexLayer = vTexLayer;
|
|
||||||
fColor = unpackARGB(int(vColor)) / 255.0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
in vec2 fTexCoords;
|
|
||||||
|
|
||||||
uniform sampler2D screenTexture;
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
FragColor = texture(screenTexture, fTexCoords);
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 0) in vec2 vPos;
|
|
||||||
layout (location = 1) in vec2 vTexCoords;
|
|
||||||
|
|
||||||
out vec2 fTexCoords;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = vec4(vPos.x, vPos.y, 0.0, 1.0);
|
|
||||||
fTexCoords = vTexCoords;
|
|
||||||
}
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
// --------------------- IN ---------------------
|
|
||||||
in OUT_IN_VARIABLES {
|
|
||||||
vec3 nearPoint;
|
|
||||||
vec3 farPoint;
|
|
||||||
mat4 proj;
|
|
||||||
mat4 view;
|
|
||||||
float near;
|
|
||||||
float far;
|
|
||||||
} inVar;
|
|
||||||
|
|
||||||
// --------------------- OUT --------------------
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
// ------------------- UNIFORM ------------------
|
|
||||||
uniform vec3 uCamDir;
|
|
||||||
|
|
||||||
vec4 grid(vec3 fragPos, float scale) {
|
|
||||||
vec2 coord = fragPos.xz * scale;
|
|
||||||
vec2 derivative = fwidth(coord);
|
|
||||||
vec2 grid = abs(fract(coord - 0.5) - 0.5) / derivative;
|
|
||||||
float line = min(grid.x, grid.y);
|
|
||||||
float minimumz = min(derivative.y, 1) * 0.1;
|
|
||||||
float minimumx = min(derivative.x, 1) * 0.1;
|
|
||||||
vec4 color = vec4(0.102, 0.102, 0.129, 1.0 - min(line, 1.0));
|
|
||||||
if(abs(fragPos.x) < minimumx)
|
|
||||||
color.z = 1.0;
|
|
||||||
if(abs(fragPos.z) < minimumz)
|
|
||||||
color.x = 1.0;
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
float computeDepth(vec3 pos) {
|
|
||||||
vec4 clip_space_pos = inVar.proj * inVar.view * vec4(pos.xyz, 1.0);
|
|
||||||
float clip_space_depth = clip_space_pos.z / clip_space_pos.w;
|
|
||||||
|
|
||||||
float far = gl_DepthRange.far;
|
|
||||||
float near = gl_DepthRange.near;
|
|
||||||
|
|
||||||
float depth = (((far-near) * clip_space_depth) + near + far) / 2.0;
|
|
||||||
|
|
||||||
return depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
float computeLinearDepth(vec3 pos) {
|
|
||||||
vec4 clip_space_pos = inVar.proj * inVar.view * vec4(pos.xyz, 1.0);
|
|
||||||
float clip_space_depth = (clip_space_pos.z / clip_space_pos.w) * 2.0 - 1.0;
|
|
||||||
float linearDepth = (2.0 * inVar.near * inVar.far) / (inVar.far + inVar.near - clip_space_depth * (inVar.far - inVar.near));
|
|
||||||
return linearDepth / inVar.far;
|
|
||||||
}
|
|
||||||
void main() {
|
|
||||||
float t = -inVar.nearPoint.y / (inVar.farPoint.y - inVar.nearPoint.y);
|
|
||||||
vec3 fragPos3D = inVar.nearPoint + t * (inVar.farPoint - inVar.nearPoint);
|
|
||||||
|
|
||||||
gl_FragDepth = computeDepth(fragPos3D);
|
|
||||||
|
|
||||||
float linearDepth = computeLinearDepth(fragPos3D);
|
|
||||||
float fading = max(0, (0.5 - linearDepth));
|
|
||||||
|
|
||||||
FragColor = (grid(fragPos3D, 10) + grid(fragPos3D, 1)) * float(t > 0);
|
|
||||||
FragColor.a *= fading;
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 0) in vec3 vPos;
|
|
||||||
|
|
||||||
// --------------------- OUT ---------------------
|
|
||||||
out OUT_IN_VARIABLES {
|
|
||||||
vec3 nearPoint;
|
|
||||||
vec3 farPoint;
|
|
||||||
mat4 proj;
|
|
||||||
mat4 view;
|
|
||||||
float near;
|
|
||||||
float far;
|
|
||||||
} outVar;
|
|
||||||
|
|
||||||
uniform mat4 proj;
|
|
||||||
uniform mat4 view;
|
|
||||||
uniform float uNear;
|
|
||||||
uniform float uFar;
|
|
||||||
|
|
||||||
vec3 UnprojectPoint(vec2 xy, float z) {
|
|
||||||
mat4 viewInv = inverse(view);
|
|
||||||
mat4 projInv = inverse(proj);
|
|
||||||
vec4 unprojectedPoint = viewInv * projInv * vec4(xy, z, 1.0);
|
|
||||||
return unprojectedPoint.xyz / unprojectedPoint.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
outVar.near = uNear;
|
|
||||||
outVar.far = uFar;
|
|
||||||
outVar.proj = proj;
|
|
||||||
outVar.view = view;
|
|
||||||
outVar.nearPoint = UnprojectPoint(vPos.xy, -1.0).xyz;
|
|
||||||
outVar.farPoint = UnprojectPoint(vPos.xy, 1.0).xyz;
|
|
||||||
gl_Position = vec4(vPos, 1.0f);
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 517 B |
|
|
@ -1,16 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
uniform sampler2D uIcon;
|
|
||||||
uniform vec4 uColor;
|
|
||||||
|
|
||||||
in vec2 fTexCoords;
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 color = uColor * texture(uIcon, fTexCoords);
|
|
||||||
if (color.a < 0.1) discard;
|
|
||||||
|
|
||||||
FragColor = uColor;
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
|
@ -1,22 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 0) in vec3 vPos;
|
|
||||||
layout (location = 9) in mat4 vInstanceMatrix;
|
|
||||||
|
|
||||||
uniform mat4 uView;
|
|
||||||
uniform mat4 uProjection;
|
|
||||||
|
|
||||||
out vec2 fTexCoords;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
float scale = 0.075;
|
|
||||||
mat4 result;
|
|
||||||
result[0] = vec4(scale, 0.0, 0.0, 0.0);
|
|
||||||
result[1] = vec4(0.0, scale, 0.0, 0.0);
|
|
||||||
result[2] = vec4(0.0, 0.0, scale, 0.0);
|
|
||||||
result[3] = vInstanceMatrix[3];
|
|
||||||
|
|
||||||
gl_Position = uProjection * uView * result * vec4(inverse(mat3(uView)) * vPos, 1.0);
|
|
||||||
fTexCoords = -vPos.xy * 0.5 + 0.5; // fits the whole rectangle
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 311 B |
|
Before Width: | Height: | Size: 235 B |
|
Before Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
|
@ -1,8 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
FragColor = vec4(0.929, 0.588, 0.196, 1.0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 1) in vec3 vPos;
|
|
||||||
layout (location = 2) in vec3 vNormal;
|
|
||||||
layout (location = 7) in vec4 vBoneInfluence;
|
|
||||||
layout (location = 8) in vec4 vBoneInfluenceExtra;
|
|
||||||
layout (location = 9) in mat4 vInstanceMatrix;
|
|
||||||
layout (location = 13) in vec3 vMorphTargetPos;
|
|
||||||
|
|
||||||
layout(std430, binding = 1) buffer BoneMatrices
|
|
||||||
{
|
|
||||||
mat4 uFinalBonesMatrix[];
|
|
||||||
};
|
|
||||||
layout(std430, binding = 2) buffer RestBoneMatrices
|
|
||||||
{
|
|
||||||
mat4 uRestBonesMatrix[];
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform mat4 uView;
|
|
||||||
uniform vec3 uViewPos;
|
|
||||||
uniform mat4 uProjection;
|
|
||||||
uniform float uMorphTime;
|
|
||||||
uniform bool uIsAnimated;
|
|
||||||
|
|
||||||
vec2 unpackBoneIDsAndWeights(int packedData)
|
|
||||||
{
|
|
||||||
return vec2(float((packedData >> 16) & 0xFFFF), float(packedData & 0xFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 calculateScale(vec4 bindPos, vec4 bindNormal)
|
|
||||||
{
|
|
||||||
vec4 worldPos = vInstanceMatrix * bindPos;
|
|
||||||
float scaleFactor = length(uViewPos - worldPos.xyz) * 0.0035;
|
|
||||||
return transpose(inverse(vInstanceMatrix)) * bindNormal * scaleFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 bindPos = vec4(mix(vPos, vMorphTargetPos, uMorphTime), 1.0);
|
|
||||||
vec4 bindNormal = vec4(vNormal, 1.0);
|
|
||||||
bindPos.xyz += calculateScale(bindPos, bindNormal).xyz;
|
|
||||||
|
|
||||||
vec4 finalPos = vec4(0.0);
|
|
||||||
vec4 finalNormal = vec4(0.0);
|
|
||||||
if (uIsAnimated)
|
|
||||||
{
|
|
||||||
vec4 boneInfluences[2];
|
|
||||||
boneInfluences[0] = vBoneInfluence;
|
|
||||||
boneInfluences[1] = vBoneInfluenceExtra;
|
|
||||||
for(int i = 0 ; i < 2; i++)
|
|
||||||
{
|
|
||||||
for(int j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
vec2 boneInfluence = unpackBoneIDsAndWeights(int(boneInfluences[i][j]));
|
|
||||||
int boneIndex = int(boneInfluence.x);
|
|
||||||
float weight = boneInfluence.y;
|
|
||||||
|
|
||||||
mat4 boneMatrix = uFinalBonesMatrix[boneIndex] * inverse(uRestBonesMatrix[boneIndex]);
|
|
||||||
|
|
||||||
finalPos += boneMatrix * bindPos * weight;
|
|
||||||
finalNormal += transpose(inverse(boneMatrix)) * bindNormal * weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
finalPos = bindPos;
|
|
||||||
finalNormal = bindNormal;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_Position = uProjection * uView * vInstanceMatrix * finalPos;
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
uniform uint uA;
|
|
||||||
uniform uint uB;
|
|
||||||
uniform uint uC;
|
|
||||||
uniform uint uD;
|
|
||||||
|
|
||||||
out uvec4 FragColor;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
FragColor = uvec4(uA, uB, uC, uD);
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
#version 460 core
|
|
||||||
|
|
||||||
layout (location = 1) in vec3 vPos;
|
|
||||||
layout (location = 7) in vec4 vBoneInfluence;
|
|
||||||
layout (location = 8) in vec4 vBoneInfluenceExtra;
|
|
||||||
layout (location = 9) in mat4 vInstanceMatrix;
|
|
||||||
layout (location = 13) in vec3 vMorphTargetPos;
|
|
||||||
|
|
||||||
layout(std430, binding = 1) buffer BoneMatrices
|
|
||||||
{
|
|
||||||
mat4 uFinalBonesMatrix[];
|
|
||||||
};
|
|
||||||
layout(std430, binding = 2) buffer RestBoneMatrices
|
|
||||||
{
|
|
||||||
mat4 uRestBonesMatrix[];
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform mat4 uView;
|
|
||||||
uniform mat4 uProjection;
|
|
||||||
uniform float uMorphTime;
|
|
||||||
uniform bool uIsAnimated;
|
|
||||||
|
|
||||||
vec2 unpackBoneIDsAndWeights(int packedData)
|
|
||||||
{
|
|
||||||
return vec2(float((packedData >> 16) & 0xFFFF), float(packedData & 0xFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 bindPos = vec4(mix(vPos, vMorphTargetPos, uMorphTime), 1.0);
|
|
||||||
|
|
||||||
vec4 finalPos = vec4(0.0);
|
|
||||||
if (uIsAnimated)
|
|
||||||
{
|
|
||||||
vec4 boneInfluences[2];
|
|
||||||
boneInfluences[0] = vBoneInfluence;
|
|
||||||
boneInfluences[1] = vBoneInfluenceExtra;
|
|
||||||
for(int i = 0 ; i < 2; i++)
|
|
||||||
{
|
|
||||||
for(int j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
vec2 boneInfluence = unpackBoneIDsAndWeights(int(boneInfluences[i][j]));
|
|
||||||
int boneIndex = int(boneInfluence.x);
|
|
||||||
float weight = boneInfluence.y;
|
|
||||||
|
|
||||||
finalPos += uFinalBonesMatrix[boneIndex] * inverse(uRestBonesMatrix[boneIndex]) * bindPos * weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else finalPos = bindPos;
|
|
||||||
|
|
||||||
gl_Position = uProjection * uView * vInstanceMatrix * finalPos;
|
|
||||||
}
|
|
||||||
BIN
FModel/Resources/pin.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |