Improvements

This commit is contained in:
Krowe Moh
2025-07-08 20:42:58 +10:00
parent 0f3d80bafb
commit 046677b875
2 changed files with 87 additions and 64 deletions

View File

@@ -17,16 +17,43 @@ namespace FModel.Extensions;
public static class KismetExtensions
{
public static string GetPrefix(string type, string extra = "") // todo: implement better handling
public static string GetPrefix(this UStruct val)
{
return type switch
var ret = string.Empty;
var super = val;
while (super is not null)
{
"FNameProperty" or "FPackageIndex" or "FTextProperty" or "FStructProperty" => "F",
"UBlueprintGeneratedClass" or "FActorProperty" => "A",
"FObjectProperty" when extra.Contains("Actor") => "A",
"ResolvedScriptObject" or "ResolvedLoadedObject" or "FSoftObjectProperty" or "FObjectProperty" => "U",
_ => ""
};
if (super.Name == "Actor")
{
ret += 'A';
break;
}
if (super.Name == "Interface")
{
ret += 'I';
break;
}
if (super.Name == "Object")
{
ret += 'U';
break;
}
super = super?.SuperStruct?.Load<UStruct>();
}
if (string.IsNullOrEmpty(ret))
ret += 'U';
return ret;
}
public static string GetPrefix(this string val) // todo: val.Contains("Struct") ? "F" findout
{
return val.Contains(".Actor") ? "A" : val.Contains("Interface") ? "I" : "U";
}
// GetUnknownFieldType and GetPropertyType from
@@ -77,36 +104,25 @@ public static class KismetExtensions
_ => GetUnknownFieldType(property)
};
}
public static string GetPropertyType(FProperty? property)
public static bool isPointer(FProperty p) =>
p.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) ||
p.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) ||
p.PropertyFlags.HasFlag(EPropertyFlags.ContainsInstancedReference) ||
p.GetType() == typeof(FObjectProperty);
public static string GetPropertyType(FProperty property)
{
if (property is null) return "None";
bool isPointer(FProperty p) =>
p.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) ||
property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) ||
p.PropertyFlags.HasFlag(EPropertyFlags.ContainsInstancedReference);
return property switch
{
FSetProperty s => $"TSet<{GetPrefix(s.ElementProp.GetType().Name)}{GetPropertyType(s.ElementProp)}{(isPointer(s) ? "*" : "")}>",
FMapProperty m => $"TMap<{GetPrefix(m.KeyProp.GetType().Name)}{GetPropertyType(m.KeyProp)}, {GetPrefix(m.ValueProp.GetType().Name)}{GetPropertyType(m.ValueProp)}{(isPointer(m) ? "*" : "")}>",
FArrayProperty a => $"TArray<{GetPrefix(a.Inner.GetType().Name)}{GetPropertyType(a.Inner)}{(isPointer(a) || GetPropertyProperty(a.Inner.GetType().Name) ? "*" : "")}>",
FSetProperty s => $"TSet<{s?.ElementProp.GetType().Name.GetPrefix()}{GetPropertyType(s.ElementProp)}{(isPointer(s) ? "*" : "")}>",
FMapProperty m => $"TMap<{m?.KeyProp.GetType().Name.GetPrefix()}{GetPropertyType(m.KeyProp)}, {m.ValueProp.GetType().Name.GetPrefix()}{GetPropertyType(m.ValueProp)}{(isPointer(m) ? "*" : "")}>",
FArrayProperty a => $"TArray<{a?.Inner.GetType().Name.GetPrefix()}{GetPropertyType(a.Inner)}{(isPointer(a) || a.Inner.GetType().Name == nameof(FObjectProperty) ? "*" : "")}>",
_ => GetPropertyType((object)property)
};
}
public static bool GetPropertyProperty(object? property)
{
if (property is null)
return false;
return property switch
{
FObjectProperty => true,
_ => false
};
}
public static string FormatStructFallback(FStructFallback fallback)
{
if (fallback.Properties.Count == 0)
@@ -245,7 +261,7 @@ public static class KismetExtensions
}
else
{
outputBuilder.Append($"\t\t{GetPrefix(op?.StackNode?.ResolvedObject?.Outer?.GetType()?.Name ?? string.Empty)}{op?.StackNode?.Name.Replace(" ", "")}(");
outputBuilder.Append($"\t\t{op?.StackNode?.ResolvedObject?.Outer?.GetType()?.Name.GetPrefix()}{op?.StackNode?.Name.Replace(" ", "")}(");
}
for (int i = 0; i < opp.Length; i++)
@@ -275,7 +291,7 @@ public static class KismetExtensions
}
else
{
outputBuilder.Append($"\t\t{op?.StackNode?.Name.Replace(" ", "")}(");//{GetPrefix(op?.StackNode?.ResolvedObject?.Outer?.GetType()?.Name)}
outputBuilder.Append($"\t\t{op?.StackNode?.Name.Replace(" ", "")}(");// maybe use GetPrefix(op?.StackNode?.ResolvedObject?.Outer?.GetType()?.Name)}
}
for (int i = 0; i < opp.Length; i++)
@@ -296,7 +312,7 @@ public static class KismetExtensions
EX_FinalFunction op = (EX_FinalFunction) expression;
KismetExpression[] opp = op.Parameters;
outputBuilder.Append(isParameter ? string.Empty : "\t\t");
outputBuilder.Append($"{GetPrefix(op.StackNode.ResolvedObject.Outer.GetType().Name)}{op.StackNode.ResolvedObject.Outer.Name.ToString().Replace(" ", "")}::{op.StackNode.Name}(");
outputBuilder.Append($"{op.StackNode.ResolvedObject.Outer.GetType().Name.GetPrefix()}{op.StackNode.ResolvedObject.Outer.Name.ToString().Replace(" ", "")}::{op.StackNode.Name}(");
for (int i = 0; i < opp.Length; i++)
{
@@ -606,7 +622,7 @@ public static class KismetExtensions
case EExprToken.EX_StructConst:
{
EX_StructConst op = (EX_StructConst) expression;
outputBuilder.Append($"{GetPrefix(op.Struct.GetType().Name)}{op.Struct.Name}");
outputBuilder.Append($"{op.Struct.GetType().Name.GetPrefix()}{op.Struct.Name}");
outputBuilder.Append('(');
for (int i = 0; i < op.Properties.Length; i++)
{
@@ -627,11 +643,11 @@ public static class KismetExtensions
if (classString?.Contains('.') == true)
{
outputBuilder.Append(GetPrefix(op?.Value?.ResolvedObject?.Class?.GetType().Name) + classString.Split('.')[1]);
outputBuilder.Append(op?.Value?.ResolvedObject?.Class?.GetType().Name.GetPrefix() + classString.Split('.')[1]);
}
else
{
outputBuilder.Append(GetPrefix(op?.Value?.ResolvedObject?.Class?.GetType().Name) + classString);
outputBuilder.Append(op?.Value?.ResolvedObject?.Class?.GetType().Name.GetPrefix() + classString);
}
outputBuilder.Append(">(\"");
var resolvedObject = op?.Value?.ResolvedObject;
@@ -883,7 +899,7 @@ public static class KismetExtensions
if (!check)
outputBuilder.Append(' ');
ProcessExpression(op.ReturnExpression.Token, op.ReturnExpression, outputBuilder, jumpCodeOffsets, true);
outputBuilder.AppendLine(";\n\n");
outputBuilder.AppendLine(";");
break;
}
case EExprToken.EX_RotationConst:

View File

@@ -60,12 +60,12 @@ using SkiaSharp;
using UE4Config.Parsing;
using Application = System.Windows.Application;
using FGuid = CUE4Parse.UE4.Objects.Core.Misc.FGuid;
using CUE4Parse.UE4.Assets.Objects.Properties;
using CUE4Parse.UE4.Assets.Objects;
using CUE4Parse.UE4.Kismet;
using CUE4Parse.UE4.Objects.Core.Math;
using CUE4Parse.UE4.Objects.GameplayTags;
using System.Text;
using AssetRipper.TextureDecoder.Rgb;
namespace FModel.ViewModels;
@@ -353,7 +353,7 @@ public class CUE4ParseViewModel : ViewModel
{
var mappingsFolder = Path.Combine(UserSettings.Default.OutputDirectory, ".data");
if (endpoint.Path == "$.[?(@.meta.compressionMethod=='Oodle')].['url','fileName']") endpoint.Path = "$.[0].['url','fileName']";
var mappings = _apiEndpointView.DynamicApi.GetMappings(default, endpoint.Url, endpoint.Path);
var mappings = _apiEndpointView.DynamicApi.GetMappings(CancellationToken.None, endpoint.Url, endpoint.Path);
if (mappings is { Length: > 0 })
{
foreach (var mapping in mappings)
@@ -428,7 +428,7 @@ public class CUE4ParseViewModel : ViewModel
var ioStoreOnDemandPath = Path.Combine(UserSettings.Default.GameDirectory, "..\\..\\..\\Cloud", inst[0].Value.SubstringAfterLast("/").SubstringBefore("\""));
if (!File.Exists(ioStoreOnDemandPath)) return;
await _apiEndpointView.EpicApi.VerifyAuth(default);
await _apiEndpointView.EpicApi.VerifyAuth(CancellationToken.None);
await Provider.RegisterVfs(new IoChunkToc(ioStoreOnDemandPath), new IoStoreOnDemandOptions
{
ChunkBaseUri = new Uri("https://download.epicgames.com/ias/fortnite/", UriKind.Absolute),
@@ -471,7 +471,7 @@ public class CUE4ParseViewModel : ViewModel
if (!Provider.ProjectName.Equals("fortnitegame", StringComparison.OrdinalIgnoreCase) || HotfixedResourcesDone) return Task.CompletedTask;
return Task.Run(() =>
{
var hotfixes = ApplicationService.ApiEndpointView.CentralApi.GetHotfixes(default, Provider.GetLanguageCode(UserSettings.Default.AssetLanguage));
var hotfixes = ApplicationService.ApiEndpointView.CentralApi.GetHotfixes(CancellationToken.None, Provider.GetLanguageCode(UserSettings.Default.AssetLanguage));
if (hotfixes == null) return;
Provider.Internationalization.Override(hotfixes);
@@ -796,7 +796,7 @@ public class CUE4ParseViewModel : ViewModel
}
}
private bool CheckExport(CancellationToken cancellationToken, IPackage pkg, int index, EBulkType bulk = EBulkType.None) // return true once you wanna stop searching for exports
private bool CheckExport(CancellationToken cancellationToken, IPackage pkg, int index, EBulkType bulk = EBulkType.None) // return true once you want to stop searching for exports
{
var isNone = bulk == EBulkType.None;
var updateUi = !HasFlag(bulk, EBulkType.Auto);
@@ -999,8 +999,9 @@ public class CUE4ParseViewModel : ViewModel
if (dummy is not UClass || pointer.Object.Value is not UClass blueprint)
continue;
var typePrefix = KismetExtensions.GetPrefix(blueprint.GetType().Name);
outputBuilder.AppendLine($"class {typePrefix}{blueprint.Name} : public {typePrefix}{blueprint?.SuperStruct?.Name ?? string.Empty}\n{{\npublic:");
var typePrefix = blueprint?.SuperStruct.Load<UStruct>().GetPrefix();
var modifierStr = blueprint.Flags.HasAnyFlags(EObjectFlags.RF_Public) ? "public" : "private";
outputBuilder.AppendLine($"class {typePrefix}{blueprint.Name} : {modifierStr} {typePrefix}{blueprint?.SuperStruct?.Name ?? string.Empty}\n{{\n{modifierStr}:");
if (!blueprint.ClassDefaultObject.TryLoad(out var bpObject))
continue;
@@ -1110,21 +1111,19 @@ public class CUE4ParseViewModel : ViewModel
var propertyName = property.Name.ToString().Replace(" ", "");
var type = KismetExtensions.GetPropertyType(property);
var prefix = KismetExtensions.GetPrefix(property.GetType().Name);
string pointerIdentifier;
if (property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) ||
property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) ||
KismetExtensions.GetPropertyProperty(property))
var prefix = "";
switch (property)
{
pointerIdentifier = "*";
}
else
{
pointerIdentifier = string.Empty;
case FFieldPathProperty pathProp:
prefix = pathProp.PropertyClass.ToString().GetPrefix();
break;
case FObjectProperty objectProp:
prefix = objectProp.PropertyClass.ToString().GetPrefix();
break;
}
outputBuilder.AppendLine($"\t{prefix}{type}{pointerIdentifier} {propertyName} = {propertyName}fmodelholder;");
outputBuilder.AppendLine($"\t{prefix}{type}{(KismetExtensions.isPointer(property) ? '*' : "")} {propertyName} = {propertyName}fmodelholder;");
}
{
@@ -1155,8 +1154,8 @@ public class CUE4ParseViewModel : ViewModel
foreach (var property in function.ScriptBytecode)
{
string? label = null;
int? offset = null;
string label = string.Empty;
int offset = 0;
switch (property.Token)
{
@@ -1173,20 +1172,20 @@ public class CUE4ParseViewModel : ViewModel
case EExprToken.EX_LocalFinalFunction:
{
EX_FinalFunction op = (EX_FinalFunction) property;
label = op.StackNode?.Name?.ToString()?.Split('.').Last().Split('[')[0];
label = op.StackNode?.Name?.Split('.').Last().Split('[')[0];
if (op.Parameters.Length == 1 && op.Parameters[0] is EX_IntConst intConst)
if (op is { Parameters: [EX_IntConst intConst] })
offset = intConst.Value;
break;
}
}
if (!string.IsNullOrEmpty(label) && offset.HasValue)
if (!string.IsNullOrEmpty(label))
{
if (!jumpCodeOffsetsMap.TryGetValue(label, out var list))
jumpCodeOffsetsMap[label] = list = new List<int>();
list.Add(offset.Value);
list.Add(offset);
}
}
}
@@ -1201,16 +1200,24 @@ public class CUE4ParseViewModel : ViewModel
{
var name = property.Name.ToString();
var plainName = property.Name.PlainText;
var prefix = KismetExtensions.GetPrefix(property.GetType().Name);
var prefix = "";
switch (property)
{
case FFieldPathProperty pathProp:
prefix = pathProp.PropertyClass.ToString().GetPrefix();
break;
case FObjectProperty objectProp:
prefix = objectProp.PropertyClass.ToString().GetPrefix();
break;
}
var type = KismetExtensions.GetPropertyType(property);
var isConst = property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm);
var isOut = property.PropertyFlags.HasFlag(EPropertyFlags.OutParm);
var isInstanced = property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference);
var isEdit = property.PropertyFlags.HasFlag(EPropertyFlags.Edit);
if (plainName == "ReturnValue")
{
returnFunc = $"{(isConst ? "const " : "")}{prefix}{type}{(isInstanced || prefix == "U" ? "*" : "")}";
returnFunc = $"{(isConst ? "const " : "")}{prefix}{type}{(KismetExtensions.isPointer(property) ? '*' : "")}";
continue;
}
@@ -1220,7 +1227,7 @@ public class CUE4ParseViewModel : ViewModel
continue;
var strippedVerseName = Regex.Replace(name, @"^__verse_0x[0-9A-Fa-f]+_", "");
argsList += $"{(isConst ? "const " : "")}{prefix}{type}{(isInstanced || prefix == "U" ? "*" : "")}{(isOut ? "&" : "")} {strippedVerseName}, ";
argsList += $"{(isConst ? "const " : "")}{prefix}{type}{(KismetExtensions.isPointer(property) ? '*' : "")}{(isOut ? '&' : "")} {strippedVerseName}, ";
}
}
argsList = argsList.TrimEnd(',', ' ');