mirror of
https://github.com/4sval/FModel.git
synced 2026-06-24 00:40:15 -05:00
Merge branch '4sval:dev' into ExportingFix
This commit is contained in:
commit
521fe894c8
|
|
@ -1 +1 @@
|
|||
Subproject commit a3821bdc34ef75f10a2003092ad2502dc648e53a
|
||||
Subproject commit dc70cfbc92436bd8c6308a5139c1baa94bd37799
|
||||
|
|
@ -162,4 +162,11 @@ public enum EAssetCategory : uint
|
|||
Borderlands = GameSpecific + 1,
|
||||
Aion2 = GameSpecific + 2,
|
||||
RocoKingdomWorld = GameSpecific + 3,
|
||||
DeltaForce = GameSpecific + 4,
|
||||
}
|
||||
|
||||
public enum EUnluacMode
|
||||
{
|
||||
Decompile,
|
||||
Disassemble,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public static class AvalonExtensions
|
|||
private static readonly IHighlightingDefinition _cppHighlighter = LoadHighlighter("Cpp.xshd");
|
||||
private static readonly IHighlightingDefinition _changelogHighlighter = LoadHighlighter("Changelog.xshd");
|
||||
private static readonly IHighlightingDefinition _verseHighlighter = LoadHighlighter("Verse.xshd");
|
||||
private static readonly IHighlightingDefinition _luaHighlighter = LoadHighlighter("Lua.xshd");
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static IHighlightingDefinition LoadHighlighter(string resourceName)
|
||||
|
|
@ -29,6 +30,9 @@ public static class AvalonExtensions
|
|||
{
|
||||
switch (ext)
|
||||
{
|
||||
case "lua":
|
||||
case "luac":
|
||||
return _luaHighlighter;
|
||||
case "ini":
|
||||
case "csv":
|
||||
return _iniHighlighter;
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
<None Remove="Resources\Xml.xshd" />
|
||||
<None Remove="Resources\Cpp.xshd" />
|
||||
<None Remove="Resources\Changelog.xshd" />
|
||||
<None Remove="Resources\Lua.xshd" />
|
||||
<None Remove="Resources\unix.png" />
|
||||
<None Remove="Resources\linux.png" />
|
||||
<None Remove="Resources\stateofdecay2.png" />
|
||||
|
|
@ -129,6 +130,7 @@
|
|||
<EmbeddedResource Include="Resources\Verse.xshd" />
|
||||
<EmbeddedResource Include="Resources\Xml.xshd" />
|
||||
<EmbeddedResource Include="Resources\Cpp.xshd" />
|
||||
<EmbeddedResource Include="Resources\Lua.xshd" />
|
||||
<EmbeddedResource Include="Resources\Changelog.xshd" />
|
||||
<EmbeddedResource Include="Resources\default.frag" />
|
||||
<EmbeddedResource Include="Resources\default.vert" />
|
||||
|
|
|
|||
|
|
@ -124,7 +124,8 @@ public partial class MainWindow
|
|||
{
|
||||
if (UserSettings.Default.DiscordRpc == EDiscordRpc.Always)
|
||||
_discordHandler.Initialize(_applicationView.GameDisplayName);
|
||||
})
|
||||
}),
|
||||
UserSettings.Default.DecompileLua ? ApplicationViewModel.InitUnluac() : Task.CompletedTask
|
||||
).ConfigureAwait(false);
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
|||
230
FModel/Resources/Lua.xshd
Normal file
230
FModel/Resources/Lua.xshd
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
<SyntaxDefinition name="Lua" extensions=".lua;.luac" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
||||
<Color name="Keyword1" foreground="#C586C0" fontWeight="bold" />
|
||||
<Color name="Keyword2" foreground="#569CD6" fontWeight="bold" />
|
||||
<Color name="Comment" foreground="#6A9955" />
|
||||
<Color name="String" foreground="#D69D85" />
|
||||
<Color name="Number" foreground="#B5CEA8" />
|
||||
<Color name="Function" foreground="#DCDCAA" />
|
||||
<Color name="Punctuation" foreground="#89DDFF" />
|
||||
<Color name="ObjectName" foreground="#3DC9B0" />
|
||||
<Color name="Constant" foreground="#9CDCFE" />
|
||||
|
||||
<RuleSet>
|
||||
<Rule color="Comment">--.*$</Rule>
|
||||
|
||||
<Rule color="String">"([^"\\]|\\.)*"</Rule>
|
||||
<Rule color="String">'([^'\\]|\\.)*'</Rule>
|
||||
|
||||
<Rule color="Number">\b\d+\.\d+([eE][+-]?\d+)?\b</Rule>
|
||||
<Rule color="Number">\b\d+[eE][+-]?\d+\b</Rule>
|
||||
<Rule color="Number">\b\d+\b</Rule>
|
||||
|
||||
<Keywords color="Keyword1">
|
||||
<Word>return</Word>
|
||||
<Word>function</Word>
|
||||
<Word>goto</Word>
|
||||
<Word>end</Word>
|
||||
<Word>if</Word>
|
||||
<Word>else</Word>
|
||||
<Word>elseif</Word>
|
||||
<Word>then</Word>
|
||||
<Word>for</Word>
|
||||
<Word>in</Word>
|
||||
<Word>until</Word>
|
||||
<Word>while</Word>
|
||||
<Word>break</Word>
|
||||
<Word>or</Word>
|
||||
<Word>and</Word>
|
||||
<Word>repeat</Word>
|
||||
<Word>do</Word>
|
||||
</Keywords>
|
||||
|
||||
<Keywords color="Keyword2">
|
||||
<Word>local</Word>
|
||||
<Word>nil</Word>
|
||||
<Word>not</Word>
|
||||
<Word>true</Word>
|
||||
<Word>false</Word>
|
||||
</Keywords>
|
||||
|
||||
<Keywords color="Function">
|
||||
<!-- Core functions -->
|
||||
<Word>assert</Word>
|
||||
<Word>collectgarbage</Word>
|
||||
<Word>error</Word>
|
||||
<Word>ipairs</Word>
|
||||
<Word>next</Word>
|
||||
<Word>pairs</Word>
|
||||
<Word>pcall</Word>
|
||||
<Word>print</Word>
|
||||
<Word>rawequal</Word>
|
||||
<Word>rawget</Word>
|
||||
<Word>rawlen</Word>
|
||||
<Word>rawset</Word>
|
||||
<Word>select</Word>
|
||||
<Word>setmetatable</Word>
|
||||
<Word>tonumber</Word>
|
||||
<Word>tostring</Word>
|
||||
<Word>type</Word>
|
||||
<Word>xpcall</Word>
|
||||
<Word>getmetatable</Word>
|
||||
<Word>require</Word>
|
||||
<Word>module</Word>
|
||||
|
||||
<!-- Modules / tables -->
|
||||
<Word>math</Word>
|
||||
<Word>string</Word>
|
||||
<Word>table</Word>
|
||||
<Word>coroutine</Word>
|
||||
<Word>os</Word>
|
||||
<Word>io</Word>
|
||||
<Word>utf8</Word>
|
||||
<Word>bit32</Word>
|
||||
<Word>package</Word>
|
||||
<Word>debug</Word>
|
||||
|
||||
<!-- Bit32 / bitwise functions -->
|
||||
<Word>arshift</Word>
|
||||
<Word>band</Word>
|
||||
<Word>bnot</Word>
|
||||
<Word>bor</Word>
|
||||
<Word>bxor</Word>
|
||||
<Word>btest</Word>
|
||||
<Word>extract</Word>
|
||||
<Word>lrotate</Word>
|
||||
<Word>lshift</Word>
|
||||
<Word>replace</Word>
|
||||
<Word>rrotate</Word>
|
||||
<Word>rshift</Word>
|
||||
|
||||
<!-- Coroutine functions -->
|
||||
<Word>create</Word>
|
||||
<Word>resume</Word>
|
||||
<Word>running</Word>
|
||||
<Word>status</Word>
|
||||
<Word>wrap</Word>
|
||||
<Word>yield</Word>
|
||||
<Word>isyieldable</Word>
|
||||
|
||||
<!-- Debug functions -->
|
||||
<Word>getuservalue</Word>
|
||||
<Word>gethook</Word>
|
||||
<Word>getinfo</Word>
|
||||
<Word>getlocal</Word>
|
||||
<Word>getregistry</Word>
|
||||
<Word>getupvalue</Word>
|
||||
<Word>upvaluejoin</Word>
|
||||
<Word>upvalueid</Word>
|
||||
<Word>setuservalue</Word>
|
||||
<Word>sethook</Word>
|
||||
<Word>setlocal</Word>
|
||||
<Word>setupvalue</Word>
|
||||
<Word>traceback</Word>
|
||||
|
||||
<!-- IO functions -->
|
||||
<Word>close</Word>
|
||||
<Word>flush</Word>
|
||||
<Word>input</Word>
|
||||
<Word>lines</Word>
|
||||
<Word>open</Word>
|
||||
<Word>output</Word>
|
||||
<Word>popen</Word>
|
||||
<Word>read</Word>
|
||||
<Word>tmpfile</Word>
|
||||
<Word>seek</Word>
|
||||
<Word>setvbuf</Word>
|
||||
<Word>write</Word>
|
||||
|
||||
<!-- String functions -->
|
||||
<Word>byte</Word>
|
||||
<Word>char</Word>
|
||||
<Word>dump</Word>
|
||||
<Word>find</Word>
|
||||
<Word>format</Word>
|
||||
<Word>gmatch</Word>
|
||||
<Word>gsub</Word>
|
||||
<Word>len</Word>
|
||||
<Word>lower</Word>
|
||||
<Word>match</Word>
|
||||
<Word>rep</Word>
|
||||
<Word>reverse</Word>
|
||||
<Word>sub</Word>
|
||||
<Word>upper</Word>
|
||||
<Word>pack</Word>
|
||||
<Word>packsize</Word>
|
||||
<Word>unpack</Word>
|
||||
<Word>concat</Word>
|
||||
<Word>maxn</Word>
|
||||
<Word>insert</Word>
|
||||
<Word>move</Word>
|
||||
<Word>offset</Word>
|
||||
<Word>codepoint</Word>
|
||||
<Word>codes</Word>
|
||||
<Word>charpattern</Word>
|
||||
|
||||
<!-- OS / Time functions -->
|
||||
<Word>clock</Word>
|
||||
<Word>date</Word>
|
||||
<Word>difftime</Word>
|
||||
<Word>execute</Word>
|
||||
<Word>exit</Word>
|
||||
<Word>getenv</Word>
|
||||
<Word>remove</Word>
|
||||
<Word>rename</Word>
|
||||
<Word>setlocale</Word>
|
||||
<Word>time</Word>
|
||||
<Word>loadlib</Word>
|
||||
<Word>searchpath</Word>
|
||||
<Word>seeall</Word>
|
||||
<Word>preload</Word>
|
||||
<Word>cpath</Word>
|
||||
<Word>path</Word>
|
||||
<Word>searchers</Word>
|
||||
<Word>loaded</Word>
|
||||
|
||||
<!-- Math functions / constants -->
|
||||
<Word>abs</Word>
|
||||
<Word>acos</Word>
|
||||
<Word>asin</Word>
|
||||
<Word>atan</Word>
|
||||
<Word>atan2</Word>
|
||||
<Word>ceil</Word>
|
||||
<Word>cos</Word>
|
||||
<Word>cosh</Word>
|
||||
<Word>deg</Word>
|
||||
<Word>exp</Word>
|
||||
<Word>floor</Word>
|
||||
<Word>fmod</Word>
|
||||
<Word>ult</Word>
|
||||
<Word>log</Word>
|
||||
<Word>log10</Word>
|
||||
<Word>max</Word>
|
||||
<Word>min</Word>
|
||||
<Word>modf</Word>
|
||||
<Word>pi</Word>
|
||||
<Word>rad</Word>
|
||||
<Word>random</Word>
|
||||
<Word>randomseed</Word>
|
||||
<Word>sin</Word>
|
||||
<Word>sqrt</Word>
|
||||
<Word>tan</Word>
|
||||
<Word>sinh</Word>
|
||||
<Word>tanh</Word>
|
||||
<Word>pow</Word>
|
||||
<Word>frexp</Word>
|
||||
<Word>ldexp</Word>
|
||||
<Word>huge</Word>
|
||||
<Word>maxinteger</Word>
|
||||
<Word>mininteger</Word>
|
||||
</Keywords>
|
||||
|
||||
<Rule color="Punctuation">(\|)|(<<)|(>>)|(\/\/)|(==)|(~=)|(<=)|(>=)|(<)|(>)|(=)|(\()|(\))|(\{)|(\})|(\[)|(\])|(::)|(:)|(;)|(,)|(\.\.\.)|(\.\.)|(\.)|[+\-*%\^#&~]</Rule>
|
||||
|
||||
<Rule color="ObjectName">(?<=function\s)[A-Za-z0-9_]+(?=\.)</Rule>
|
||||
|
||||
<Rule color="Function">(?<=\.)[A-Za-z0-9_]+(?=\()</Rule>
|
||||
<Rule color="Function">(?<=function\s)[A-Za-z0-9_]+(?=\s*\()</Rule> <!-- Standalone function name -->
|
||||
|
||||
<Rule color="Constant">\b[A-Z_][A-Z0-9_]*\b</Rule>
|
||||
</RuleSet>
|
||||
</SyntaxDefinition>
|
||||
|
|
@ -25,7 +25,8 @@ public class DirectorySettings : ViewModel, ICloneable
|
|||
Directories = old?.Directories ?? CustomDirectory.Default(gameName),
|
||||
AesKeys = old?.AesKeys ?? new AesResponse { MainKey = aes, DynamicKeys = null },
|
||||
LastAesReload = old?.LastAesReload ?? DateTime.Today.AddDays(-1),
|
||||
CriwareDecryptionKey = old?.CriwareDecryptionKey ?? 0
|
||||
CriwareDecryptionKey = old?.CriwareDecryptionKey ?? 0,
|
||||
UnluacOpCodeMap = old?.UnluacOpCodeMap ?? ""
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +107,13 @@ public class DirectorySettings : ViewModel, ICloneable
|
|||
set => SetProperty(ref _criwareDecryptionKey, value);
|
||||
}
|
||||
|
||||
private string _unluacOpCodeMap;
|
||||
public string UnluacOpCodeMap
|
||||
{
|
||||
get => _unluacOpCodeMap;
|
||||
set => SetProperty(ref _unluacOpCodeMap, value);
|
||||
}
|
||||
|
||||
private bool Equals(DirectorySettings other)
|
||||
{
|
||||
return GameDirectory == other.GameDirectory && UeVersion == other.UeVersion;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using CUE4Parse_Conversion.Animations;
|
|||
using CUE4Parse_Conversion.Meshes;
|
||||
using CUE4Parse_Conversion.Textures;
|
||||
using CUE4Parse_Conversion.UEFormat.Enums;
|
||||
using CUE4Parse.UE4.Lua.unluac;
|
||||
using FModel.Framework;
|
||||
using FModel.ViewModels;
|
||||
using FModel.ViewModels.ApiEndpoints.Models;
|
||||
|
|
@ -280,6 +281,36 @@ namespace FModel.Settings
|
|||
set => SetProperty(ref _convertAudioOnBulkExport, value);
|
||||
}
|
||||
|
||||
private bool _decompileLua;
|
||||
public bool DecompileLua
|
||||
{
|
||||
get => _decompileLua;
|
||||
set => SetProperty(ref _decompileLua, value);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public EUnluacMode UnluacMode
|
||||
{
|
||||
get => UnluacFlags.HasFlag(EUnluacFlags.Disassemble) ? EUnluacMode.Disassemble : EUnluacMode.Decompile;
|
||||
set
|
||||
{
|
||||
var withoutMode = UnluacFlags & ~(EUnluacFlags.Decompile | EUnluacFlags.Disassemble);
|
||||
var modeFlag = value == EUnluacMode.Disassemble ? EUnluacFlags.Disassemble : EUnluacFlags.Decompile;
|
||||
UnluacFlags = withoutMode | modeFlag;
|
||||
}
|
||||
}
|
||||
|
||||
private EUnluacFlags _unluacFlags = EUnluacFlags.Decompile;
|
||||
public EUnluacFlags UnluacFlags
|
||||
{
|
||||
get => _unluacFlags;
|
||||
set
|
||||
{
|
||||
if (!SetProperty(ref _unluacFlags, value)) return;
|
||||
RaisePropertyChanged(nameof(UnluacMode));
|
||||
}
|
||||
}
|
||||
|
||||
private IDictionary<string, DirectorySettings> _perDirectory = new Dictionary<string, DirectorySettings>();
|
||||
public IDictionary<string, DirectorySettings> PerDirectory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Windows;
|
|||
using CUE4Parse_Conversion.Textures.BC;
|
||||
using CUE4Parse.Compression;
|
||||
using CUE4Parse.Encryption.Aes;
|
||||
using CUE4Parse.UE4.Lua.unluac;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using CUE4Parse.UE4.VirtualFileSystem;
|
||||
using FModel.Extensions;
|
||||
|
|
@ -340,4 +341,12 @@ public class ApplicationViewModel : ViewModel
|
|||
|
||||
DetexHelper.Initialize(detexPath);
|
||||
}
|
||||
|
||||
public static async Task InitUnluac()
|
||||
{
|
||||
var unluacPath = Path.Combine(UserSettings.Default.OutputDirectory, ".data", UnluacHelper.DllName);
|
||||
await UnluacHelper.InitializeAsync(unluacPath).ConfigureAwait(false);
|
||||
if (UnluacHelper.Instance is null)
|
||||
FLogger.Append(ELog.Error, () => FLogger.Text("Failed to download unluac", Constants.WHITE, true));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ public class AudioPlayerViewModel : ViewModel, ISource, IDisposable
|
|||
|
||||
if (Spectrum != null && PlayedFile.PlaybackState == PlaybackState.Playing)
|
||||
{
|
||||
FftData = new float[4096];
|
||||
FftData = new float[4096+4];
|
||||
Spectrum.GetFftData(FftData);
|
||||
RaiseSourcePropertyChangedEvent(ESourceProperty.FftData, FftData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ using CUE4Parse.GameTypes.AshEchoes.FileProvider;
|
|||
using CUE4Parse.GameTypes.Borderlands3.Assets.Exports;
|
||||
using CUE4Parse.GameTypes.Borderlands4.Assets.Exports;
|
||||
using CUE4Parse.GameTypes.Borderlands4.Wwise;
|
||||
using CUE4Parse.GameTypes.DFHO.Assets.Objects;
|
||||
using CUE4Parse.GameTypes.HonorOfKings.FileProvider;
|
||||
using CUE4Parse.GameTypes.KRD.Assets.Exports;
|
||||
using CUE4Parse.GameTypes.RocoKingdomWorld.Assets.Objects;
|
||||
using CUE4Parse.GameTypes.SMG.UE4.Assets.Exports.Wwise;
|
||||
|
|
@ -41,12 +43,14 @@ using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
|||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse.UE4.Assets.Exports.Verse;
|
||||
using CUE4Parse.UE4.Assets.Exports.Wwise;
|
||||
using CUE4Parse.UE4.Assets.Objects;
|
||||
using CUE4Parse.UE4.BinaryConfig;
|
||||
using CUE4Parse.UE4.CriWare;
|
||||
using CUE4Parse.UE4.CriWare.Readers;
|
||||
using CUE4Parse.UE4.FMod;
|
||||
using CUE4Parse.UE4.IO;
|
||||
using CUE4Parse.UE4.Localization;
|
||||
using CUE4Parse.UE4.Lua.unluac;
|
||||
using CUE4Parse.UE4.Objects.Core.Serialization;
|
||||
using CUE4Parse.UE4.Objects.Engine;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
|
|
@ -194,6 +198,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
], SearchOption.AllDirectories, versionContainer, pathComparer),
|
||||
_ when versionContainer.Game is EGame.GAME_AshEchoes => new AEDefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer),
|
||||
_ when versionContainer.Game is EGame.GAME_BlackStigma => new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, StringComparer.Ordinal),
|
||||
_ when versionContainer.Game is EGame.GAME_HonorofKingsWorld => new HoKWDefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer),
|
||||
_ => new DefaultFileProvider(gameDirectory, SearchOption.AllDirectories, versionContainer, pathComparer)
|
||||
};
|
||||
|
||||
|
|
@ -395,6 +400,16 @@ public class CUE4ParseViewModel : ViewModel
|
|||
});
|
||||
}
|
||||
|
||||
private ITypeMappingsProvider SelectMappingsProvider(string path)
|
||||
{
|
||||
if (path.EndsWith(".jmap.gz", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".jmap", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new JmapTypeMappingsProvider(path);
|
||||
}
|
||||
|
||||
return new FileUsmapTypeMappingsProvider(path);
|
||||
}
|
||||
|
||||
public Task InitMappings(bool force = false)
|
||||
{
|
||||
if (!UserSettings.IsEndpointValid(EEndpointType.Mapping, out var endpoint))
|
||||
|
|
@ -408,7 +423,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
var l = ELog.Information;
|
||||
if (endpoint.Overwrite && File.Exists(endpoint.FilePath))
|
||||
{
|
||||
Provider.MappingsContainer = new FileUsmapTypeMappingsProvider(endpoint.FilePath);
|
||||
Provider.MappingsContainer = SelectMappingsProvider(endpoint.FilePath);
|
||||
}
|
||||
else if (endpoint.IsValid)
|
||||
{
|
||||
|
|
@ -434,7 +449,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
_apiEndpointView.DownloadFile(mapping.Url, mappingPath);
|
||||
}
|
||||
|
||||
Provider.MappingsContainer = new FileUsmapTypeMappingsProvider(mappingPath);
|
||||
Provider.MappingsContainer = SelectMappingsProvider(mappingPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -695,6 +710,18 @@ public class CUE4ParseViewModel : ViewModel
|
|||
ProcessCacheDBFile(entry, updateUi, saveProperties);
|
||||
break;
|
||||
}
|
||||
case "luac":
|
||||
case "lua":
|
||||
{
|
||||
var data = Provider.SaveAsset(entry);
|
||||
byte[] decompiled = ProcessLuaFile(data);
|
||||
|
||||
using var stream = new MemoryStream(decompiled);
|
||||
using var reader = new StreamReader(stream);
|
||||
TabControl.SelectedTab.SetDocumentText(reader.ReadToEnd(), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "upluginmanifest":
|
||||
case "code-workspace":
|
||||
case "projectstore":
|
||||
|
|
@ -717,13 +744,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "verse":
|
||||
case "html":
|
||||
case "json5":
|
||||
case "json":
|
||||
case "uref":
|
||||
case "cube":
|
||||
case "usda":
|
||||
case "ocio":
|
||||
case "data" when Provider.ProjectName is "OakGame":
|
||||
case "scss":
|
||||
case "yaml":
|
||||
case "ini":
|
||||
case "txt":
|
||||
case "log":
|
||||
|
|
@ -746,11 +773,11 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "apx":
|
||||
case "udn":
|
||||
case "doc":
|
||||
case "lua":
|
||||
case "vdf":
|
||||
case "yml":
|
||||
case "js":
|
||||
case "po":
|
||||
case "py":
|
||||
case "md":
|
||||
case "h":
|
||||
case "non" when Provider.Versions.Game is EGame.GAME_RocoKingdomWorld:
|
||||
|
|
@ -772,6 +799,17 @@ public class CUE4ParseViewModel : ViewModel
|
|||
|
||||
break;
|
||||
}
|
||||
case "json":
|
||||
{
|
||||
var data = Provider.SaveAsset(entry);
|
||||
using var stream = new MemoryStream(data) { Position = 0 };
|
||||
using var reader = new StreamReader(stream);
|
||||
|
||||
var parsedJson = JsonConvert.DeserializeObject(reader.ReadToEnd());
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(parsedJson, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
break;
|
||||
}
|
||||
case "locmeta":
|
||||
{
|
||||
var archive = entry.CreateReader();
|
||||
|
|
@ -828,7 +866,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "pck":
|
||||
{
|
||||
var archive = entry.CreateReader();
|
||||
var wwise = new WwiseReader(archive, new WwiseGameFileSource(entry));
|
||||
var wwise = new WwiseReader(new FWwiseArchive(archive), new WwiseGameFileSource(entry));
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(wwise, Formatting.Indented), saveProperties, updateUi);
|
||||
|
||||
var medias = WwiseProvider.ExtractBankSounds(wwise);
|
||||
|
|
@ -893,6 +931,13 @@ public class CUE4ParseViewModel : ViewModel
|
|||
|
||||
break;
|
||||
}
|
||||
case "ustbin" when Provider.Versions.Game is EGame.GAME_DeltaForce:
|
||||
{
|
||||
var archive = entry.CreateReader();
|
||||
var ustbin = new FDeltaStringTable(archive);
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(ustbin, Formatting.Indented), saveProperties, updateUi);
|
||||
break;
|
||||
}
|
||||
case "png":
|
||||
case "jpg":
|
||||
case "bmp":
|
||||
|
|
@ -960,7 +1005,6 @@ public class CUE4ParseViewModel : ViewModel
|
|||
break;
|
||||
}
|
||||
case "res": // just skip
|
||||
case "luac": // compiled lua
|
||||
case "bytes": // wuthering waves
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1066,6 +1110,53 @@ public class CUE4ParseViewModel : ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
private byte[] ProcessLuaFile(byte[] data)
|
||||
{
|
||||
var result = EUnluacErrorCode.Ok;
|
||||
byte[] output = [];
|
||||
if (BitConverter.ToUInt32(data) == UnluacHelper.LuaMagic && UnluacHelper.Instance is not null)
|
||||
{
|
||||
// opcodemap patch
|
||||
byte[] opmapData = Provider.Versions.Game switch
|
||||
{
|
||||
_ => [],
|
||||
};
|
||||
|
||||
var flags = UserSettings.Default.UnluacFlags;
|
||||
var opcodemap = UserSettings.Default.CurrentDir.UnluacOpCodeMap;
|
||||
if (!string.IsNullOrWhiteSpace(opcodemap))
|
||||
{
|
||||
opmapData = Encoding.UTF8.GetBytes(opcodemap);
|
||||
flags |= EUnluacFlags.OpCodeMap;
|
||||
}
|
||||
else if (opmapData is { Length: > 12 })
|
||||
{
|
||||
flags |= EUnluacFlags.OpCodeMapPatch;
|
||||
}
|
||||
|
||||
result = UnluacHelper.Decompile(data, opmapData, (uint)flags, out output, out var log);
|
||||
if (result != EUnluacErrorCode.Ok && log.Length > 0)
|
||||
{
|
||||
Log.Error(Encoding.UTF8.GetString(log));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = EUnluacErrorCode.Error;
|
||||
}
|
||||
|
||||
var decompiled = result switch
|
||||
{
|
||||
EUnluacErrorCode.Ok => output,
|
||||
#if DEBUG
|
||||
EUnluacErrorCode.PartialDecompile => output,
|
||||
#endif
|
||||
_ => data,
|
||||
};
|
||||
|
||||
return decompiled;
|
||||
}
|
||||
|
||||
public void ExtractAndScroll(CancellationToken cancellationToken, string fullPath, string objectName, string parentExportType)
|
||||
{
|
||||
Log.Information("User CTRL-CLICKED to extract '{FullPath}'", fullPath);
|
||||
|
|
@ -1240,8 +1331,8 @@ public class CUE4ParseViewModel : ViewModel
|
|||
{
|
||||
var data = squareEnixObject switch
|
||||
{
|
||||
USQEXSEADSoundBank sqexSoundBank => sqexSoundBank.SQEXSoundBankData?.Data ?? [],
|
||||
USQEXSEADSound sqexSound => sqexSound.SQEXSoundData?.Data ?? [],
|
||||
USQEXSEADSoundBank sqexSoundBank => sqexSoundBank.SQEXSoundBankData?.ReadDataOnce() ?? [],
|
||||
USQEXSEADSound sqexSound => sqexSound.SQEXSoundData?.ReadDataOnce() ?? [],
|
||||
_ => [],
|
||||
};
|
||||
var sabPath = Path.Combine(TabControl.SelectedTab.Entry.PathWithoutExtension.Replace('\\', '/').SubstringBeforeLast('/'), squareEnixObject.Name);
|
||||
|
|
|
|||
|
|
@ -446,6 +446,9 @@ public class GameFileViewModel(GameFile asset) : ViewModel
|
|||
case "cam" when GameVersion is EGame.GAME_RocoKingdomWorld:
|
||||
AssetCategory = EAssetCategory.RocoKingdomWorld;
|
||||
break;
|
||||
case "ustbin" when GameVersion is EGame.GAME_DeltaForce:
|
||||
AssetCategory = EAssetCategory.DeltaForce;
|
||||
break;
|
||||
default:
|
||||
AssetCategory = EAssetCategory.All; // just so it sets resolved
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -172,6 +172,13 @@ public class SettingsViewModel : ViewModel
|
|||
set => SetProperty(ref _criwareDecryptionKey, value);
|
||||
}
|
||||
|
||||
private string _unluacOpcodeMap;
|
||||
public string UnluacOpcodeMap
|
||||
{
|
||||
get => _unluacOpcodeMap;
|
||||
set => SetProperty(ref _unluacOpcodeMap, value);
|
||||
}
|
||||
|
||||
public bool SocketSettingsEnabled => SelectedMeshExportFormat == EMeshFormat.ActorX;
|
||||
public bool CompressionSettingsEnabled => SelectedMeshExportFormat == EMeshFormat.UEFormat;
|
||||
|
||||
|
|
@ -237,6 +244,7 @@ public class SettingsViewModel : ViewModel
|
|||
_optionsSnapshot = UserSettings.Default.CurrentDir.Versioning.Options;
|
||||
_mapStructTypesSnapshot = UserSettings.Default.CurrentDir.Versioning.MapStructTypes;
|
||||
_criwareDecryptionKey = UserSettings.Default.CurrentDir.CriwareDecryptionKey;
|
||||
_unluacOpcodeMap = UserSettings.Default.CurrentDir.UnluacOpCodeMap;
|
||||
|
||||
AesEndpoint = UserSettings.Default.CurrentDir.Endpoints[0];
|
||||
MappingEndpoint = UserSettings.Default.CurrentDir.Endpoints[1];
|
||||
|
|
@ -273,6 +281,7 @@ public class SettingsViewModel : ViewModel
|
|||
SelectedMaterialExportFormat = _materialExportFormatSnapshot;
|
||||
SelectedTextureExportFormat = _textureExportFormatSnapshot;
|
||||
CriwareDecryptionKey = _criwareDecryptionKey;
|
||||
UnluacOpcodeMap = _unluacOpcodeMap;
|
||||
SelectedAesReload = UserSettings.Default.AesReload;
|
||||
SelectedDiscordRpc = UserSettings.Default.DiscordRpc;
|
||||
|
||||
|
|
@ -314,6 +323,7 @@ public class SettingsViewModel : ViewModel
|
|||
UserSettings.Default.CurrentDir.Versioning.Options = SelectedOptions;
|
||||
UserSettings.Default.CurrentDir.Versioning.MapStructTypes = SelectedMapStructTypes;
|
||||
UserSettings.Default.CurrentDir.CriwareDecryptionKey = CriwareDecryptionKey;
|
||||
UserSettings.Default.CurrentDir.UnluacOpCodeMap = UnluacOpcodeMap;
|
||||
|
||||
UserSettings.Default.AssetLanguage = SelectedAssetLanguage;
|
||||
UserSettings.Default.CompressedAudioMode = SelectedCompressedAudio;
|
||||
|
|
|
|||
|
|
@ -53,4 +53,5 @@
|
|||
<SolidColorBrush x:Key="BorderlandsBrush" Color="Yellow"></SolidColorBrush>
|
||||
<SolidColorBrush x:Key="AionBrush" Color="DeepSkyBlue"></SolidColorBrush>
|
||||
<SolidColorBrush x:Key="RocoKingdomWorldBrush" Color="#fecf4d"></SolidColorBrush>
|
||||
<SolidColorBrush x:Key="DeltaForceBrush" Color="LightGreen"></SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public partial class DropOverlay : UserControl
|
|||
}
|
||||
else if (_dragStatus is DragStatus.File)
|
||||
{
|
||||
TitleText.Text = "Drop .usmap to import";
|
||||
TitleText.Text = "Drop usmap/jmap to import";
|
||||
DescriptionText.Text = "Mapping file will be applied immediately";
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +125,6 @@ public partial class DropOverlay : UserControl
|
|||
if (!_applicationView.Status.IsReady || !e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetData(DataFormats.FileDrop) is not string[] files)
|
||||
return;
|
||||
|
||||
|
||||
bool directorySelectorIsVisible = _applicationView.Status.Kind is EStatusKind.Configuring;
|
||||
if (!directorySelectorIsVisible && (Helper.IsWindowOpen<DictionaryEditor>() || Helper.IsWindowOpen<EndpointEditor>()))
|
||||
{
|
||||
|
|
@ -145,7 +144,9 @@ public partial class DropOverlay : UserControl
|
|||
_dragStatus = DragStatus.Folder;
|
||||
return;
|
||||
}
|
||||
else if (File.Exists(path) && Path.GetExtension(path).Equals(".usmap", StringComparison.OrdinalIgnoreCase))
|
||||
else if (File.Exists(path) && path.EndsWith(".usmap", StringComparison.OrdinalIgnoreCase) ||
|
||||
path.EndsWith(".jmap", StringComparison.OrdinalIgnoreCase) ||
|
||||
path.EndsWith(".jmap.gz", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_path = path;
|
||||
_dragStatus = DragStatus.File;
|
||||
|
|
|
|||
32
FModel/Views/Resources/Converters/EnumFlagToBoolConverter.cs
Normal file
32
FModel/Views/Resources/Converters/EnumFlagToBoolConverter.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace FModel.Views.Resources.Converters;
|
||||
|
||||
public sealed class EnumFlagToBoolConverter : IValueConverter
|
||||
{
|
||||
public static readonly EnumFlagToBoolConverter Instance = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is null || parameter is null) return false;
|
||||
|
||||
var enumType = value.GetType();
|
||||
if (!enumType.IsEnum) return false;
|
||||
|
||||
var flag = parameter is string s
|
||||
? Enum.Parse(enumType, s, ignoreCase: true)
|
||||
: parameter;
|
||||
|
||||
var current = System.Convert.ToInt64(value);
|
||||
var wanted = System.Convert.ToInt64(flag);
|
||||
|
||||
return (current & wanted) == wanted;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
|
@ -92,6 +92,7 @@ public class FileToGeometryConverter : IMultiValueConverter
|
|||
EAssetCategory.Borderlands => ("BorderlandsIcon", "BorderlandsBrush"),
|
||||
EAssetCategory.Aion2 => ("AionIcon", "AionBrush"),
|
||||
EAssetCategory.RocoKingdomWorld => ("RocoKingdomWorldIcon", "RocoKingdomWorldBrush"),
|
||||
EAssetCategory.DeltaForce => ("DeltaForceIcon", "DeltaForceBrush"),
|
||||
|
||||
_ => ("AssetIcon", "NeutralBrush")
|
||||
};
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -44,6 +44,7 @@
|
|||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
|
|
@ -237,26 +238,32 @@
|
|||
IsChecked="{Binding ShowDecompileOption, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="19"
|
||||
<TextBlock Grid.Row="19" Grid.Column="0" Text="Decompile Lua" VerticalAlignment="Center" Margin="0 0 0 5" ToolTip="Decompile/Disassemble compiled lua files with an unluac." />
|
||||
<CheckBox Grid.Row="19" Grid.Column="2" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding DecompileLua, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}"
|
||||
Checked="OnDecompileLuaChanged" />
|
||||
|
||||
<TextBlock Grid.Row="20"
|
||||
Grid.Column="0"
|
||||
Text="Convert Audio During Export (.wav)"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 0 5" />
|
||||
<CheckBox Grid.Row="19"
|
||||
<CheckBox Grid.Row="20"
|
||||
Grid.Column="2"
|
||||
Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
IsChecked="{Binding ConvertAudioOnBulkExport, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
|
||||
Margin="0 5 0 10"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" />
|
||||
|
||||
<TextBlock Grid.Row="20"
|
||||
<TextBlock Grid.Row="21"
|
||||
Grid.Column="0"
|
||||
Text="CRIWARE Decryption Key"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0 0 0 10" />
|
||||
|
||||
<TextBox x:Name="CriwareKeyBox"
|
||||
Grid.Row="20"
|
||||
Grid.Row="21"
|
||||
Grid.Column="2"
|
||||
Grid.ColumnSpan="5"
|
||||
Margin="0 5 0 10"
|
||||
|
|
@ -608,6 +615,98 @@
|
|||
HotKey="{Binding RemoveAudio, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="unluacTemplate">
|
||||
<Grid adonisExtensions:LayerExtension.Layer="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Mode" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<ComboBox Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="10"
|
||||
SelectedValuePath="Tag"
|
||||
SelectedValue="{Binding UnluacMode, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
|
||||
Margin="0 0 0 5">
|
||||
<ComboBoxItem Content="Decompile" Tag="{x:Static local:EUnluacMode.Decompile}" />
|
||||
<ComboBoxItem Content="Disassemble" Tag="{x:Static local:EUnluacMode.Disassemble}" />
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Raw string" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Tag="RawString"
|
||||
Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="3"
|
||||
Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 5"
|
||||
IsChecked="{Binding UnluacFlags, Source={x:Static local:Settings.UserSettings.Default},
|
||||
Converter={x:Static converters:EnumFlagToBoolConverter.Instance}, ConverterParameter=RawString, Mode=OneWay}"
|
||||
Checked="OnUnluacFlagChanged"
|
||||
Unchecked="OnUnluacFlagChanged"
|
||||
ToolTip="Copy string bytes directly to output">
|
||||
</CheckBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="4" Text="No debug" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Tag="NoDebug"
|
||||
Grid.Row="1" Grid.Column="6" Grid.ColumnSpan="3"
|
||||
Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 5"
|
||||
IsChecked="{Binding UnluacFlags, Source={x:Static local:Settings.UserSettings.Default},
|
||||
Converter={x:Static converters:EnumFlagToBoolConverter.Instance}, ConverterParameter=NoDebug, Mode=OneWay}"
|
||||
Checked="OnUnluacFlagChanged"
|
||||
Unchecked="OnUnluacFlagChanged"
|
||||
ToolTip="Ignore debugging information in input file">
|
||||
</CheckBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="8" Text="Luaj" VerticalAlignment="Center" Margin="0 0 0 5" />
|
||||
<CheckBox Tag="Luaj"
|
||||
Grid.Row="1" Grid.Column="10" Grid.ColumnSpan="3"
|
||||
Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
|
||||
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 5"
|
||||
IsChecked="{Binding UnluacFlags, Source={x:Static local:Settings.UserSettings.Default},
|
||||
Converter={x:Static converters:EnumFlagToBoolConverter.Instance}, ConverterParameter=Luaj, Mode=OneWay}"
|
||||
Checked="OnUnluacFlagChanged"
|
||||
Unchecked="OnUnluacFlagChanged"
|
||||
ToolTip="Emulate Luaj's permissive parser">
|
||||
</CheckBox>
|
||||
|
||||
<Separator Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="11" Style="{StaticResource CustomSeparator}" />
|
||||
|
||||
<TextBlock Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Text="OpcodeMap"
|
||||
VerticalAlignment="Top"
|
||||
Margin="0 0 0 5"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="10"
|
||||
Margin="0 0 0 5" Height="300"
|
||||
FontSize="14" Padding="8"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top"
|
||||
VerticalContentAlignment="Top" TextAlignment="Left"
|
||||
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}"
|
||||
Text="{Binding SettingsView.UnluacOpcodeMap, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
AcceptsReturn="True"
|
||||
AcceptsTab="True"
|
||||
TextWrapping="NoWrap"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
ToolTip="Paste a custom opcode map." />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</adonisControls:AdonisWindow.Resources>
|
||||
<Grid>
|
||||
|
|
@ -685,6 +784,28 @@
|
|||
</StackPanel>
|
||||
</TreeViewItem.Header>
|
||||
</TreeViewItem>
|
||||
<TreeViewItem Tag="unluacTemplate">
|
||||
<TreeViewItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Viewbox Width="16" Height="16" HorizontalAlignment="Center" Margin="-20 4 7.5 4">
|
||||
<Canvas Width="24" Height="24">
|
||||
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource LuaIcon}" />
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
<TextBlock Text="unluac" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</TreeViewItem.Header>
|
||||
<TreeViewItem.Style>
|
||||
<Style TargetType="TreeViewItem" BasedOn="{StaticResource TreeViewItemStyle}">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding DecompileLua, Source={x:Static local:Settings.UserSettings.Default}}" Value="True">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TreeViewItem.Style>
|
||||
</TreeViewItem>
|
||||
</TreeView>
|
||||
|
||||
<Grid Grid.Row="0" Grid.Column="1" Margin="{adonisUi:Space 1, 0.5}" HorizontalAlignment="Stretch">
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using CUE4Parse.UE4.Lua.unluac;
|
||||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using FModel.ViewModels;
|
||||
|
|
@ -274,4 +275,21 @@ public partial class SettingsView
|
|||
|
||||
Process.Start(new ProcessStartInfo(hyperlink.NavigateUri.AbsoluteUri) { UseShellExecute = true });
|
||||
}
|
||||
|
||||
private async void OnDecompileLuaChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is CheckBox { IsChecked: true } && UnluacHelper.Instance is null)
|
||||
await ApplicationViewModel.InitUnluac();
|
||||
}
|
||||
|
||||
private void OnUnluacFlagChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not CheckBox cb || cb.Tag is not string name) return;
|
||||
if (!Enum.TryParse<EUnluacFlags>(name, true, out var flag)) return;
|
||||
|
||||
var current = UserSettings.Default.UnluacFlags;
|
||||
var isChecked = cb.IsChecked == true;
|
||||
|
||||
UserSettings.Default.UnluacFlags = isChecked ? (current | flag) : (current & ~flag);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user