mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 09:44:37 -05:00
mb
This commit is contained in:
parent
b0625bbd6f
commit
656d3b59ca
|
|
@ -65,7 +65,7 @@ using CUE4Parse.UE4.Assets.Objects;
|
|||
using CUE4Parse.UE4.Kismet;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse.UE4.Objects.GameplayTags;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace FModel.ViewModels;
|
||||
|
|
@ -620,7 +620,6 @@ public class CUE4ParseViewModel : ViewModel
|
|||
case "js":
|
||||
case "po":
|
||||
case "md":
|
||||
case "po":
|
||||
case "h":
|
||||
{
|
||||
var data = Provider.SaveAsset(entry);
|
||||
|
|
@ -956,493 +955,493 @@ public class CUE4ParseViewModel : ViewModel
|
|||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("");
|
||||
|
||||
TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(package, Formatting.Indented), false, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Decompile(GameFile entry)
|
||||
{
|
||||
var package = Provider.LoadPackage(entry);
|
||||
|
||||
if (TabControl.CanAddTabs)
|
||||
if (TabControl.CanAddTabs)
|
||||
TabControl.AddTab(entry);
|
||||
else
|
||||
else
|
||||
TabControl.SelectedTab.SoftReset(entry);
|
||||
|
||||
TabControl.SelectedTab.TitleExtra = "Decompiled";
|
||||
TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("txt");
|
||||
|
||||
var pkg = Provider.LoadPackage(entry);
|
||||
|
||||
var outputBuilder = new StringBuilder();
|
||||
for (var i = 0; i < pkg.ExportMapLength; i++)
|
||||
{
|
||||
var pointer = new FPackageIndex(pkg, i + 1).ResolvedObject;
|
||||
if (pointer?.Object is null)
|
||||
continue;
|
||||
|
||||
var dummy = ((AbstractUePackage) pkg).ConstructObject(
|
||||
pointer.Class?.Object?.Value as UStruct, pkg);
|
||||
switch (dummy)
|
||||
{
|
||||
case UBlueprintGeneratedClass _:
|
||||
case UVerseClass _:
|
||||
{
|
||||
var blueprintGeneratedClass = pkg.ExportsLazy.FirstOrDefault(e => e.Value is UBlueprintGeneratedClass)?.Value as UBlueprintGeneratedClass;
|
||||
var verseClass = pkg.ExportsLazy.Where(export => export.Value is UVerseClass).Select(export => (UVerseClass) export.Value).FirstOrDefault();
|
||||
|
||||
var stringsarray = new List<string>();
|
||||
if (blueprintGeneratedClass != null)
|
||||
{
|
||||
{
|
||||
var mainClass = blueprintGeneratedClass?.Name ?? verseClass?.Name;
|
||||
var superStructName = blueprintGeneratedClass?.SuperStruct?.Name ?? verseClass?.SuperStruct?.Name ?? string.Empty;
|
||||
outputBuilder.AppendLine(
|
||||
$"class {KismetExtensions.GetPrefix(blueprintGeneratedClass?.GetType().Name ?? verseClass?.GetType().Name)}{mainClass} : public {KismetExtensions.GetPrefix(blueprintGeneratedClass?.GetType().Name ?? verseClass?.GetType().Name)}{superStructName}\n{{\npublic:");
|
||||
|
||||
foreach (var export in pkg.ExportsLazy)
|
||||
{
|
||||
if (export.Value is not UBlueprintGeneratedClass)
|
||||
|
||||
if (export.Value.Name.StartsWith("Default__") &&
|
||||
export.Value.Name.EndsWith(mainClass ?? string.Empty))
|
||||
{
|
||||
var exportObject = export.Value;
|
||||
foreach (var key in exportObject.Properties)
|
||||
{
|
||||
stringsarray.Add(key.Name.PlainText);
|
||||
string placeholder = $"{key.Name}placenolder";
|
||||
string result = key.Tag.GenericValue.ToString();
|
||||
string keyName = key.Name.PlainText.Replace(" ", "");
|
||||
|
||||
var propertyTag = key.Tag.GetValue(typeof(object));
|
||||
|
||||
void ShouldAppend(string? value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
if (outputBuilder.ToString().Contains(placeholder))
|
||||
{
|
||||
outputBuilder.Replace(placeholder, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputBuilder.AppendLine(
|
||||
$"\t{KismetExtensions.GetPropertyType(propertyTag)} {keyName} = {value};");
|
||||
}
|
||||
}
|
||||
|
||||
if (key.Tag.GenericValue is FScriptStruct structTag)
|
||||
{
|
||||
if (structTag.StructType is FVector vector)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector({vector.X}, {vector.Y}, {vector.Z})");
|
||||
}
|
||||
else if (structTag.StructType is FGuid guid)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FGuid({guid.A}, {guid.B}, {guid.C}, {guid.D})");
|
||||
}
|
||||
else if (structTag.StructType is TIntVector3<int> vector3)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector({vector3.X}, {vector3.Y}, {vector3.Z})");
|
||||
}
|
||||
else if (structTag.StructType is TIntVector3<float>
|
||||
floatVector3)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector({floatVector3.X}, {floatVector3.Y}, {floatVector3.Z})");
|
||||
}
|
||||
else if (structTag.StructType is TIntVector2<float>
|
||||
floatVector2)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector2D({floatVector2.X}, {floatVector2.Y})");
|
||||
}
|
||||
else if (structTag.StructType is FVector2D vector2d)
|
||||
{
|
||||
ShouldAppend($"FVector2D({vector2d.X}, {vector2d.Y})");
|
||||
}
|
||||
else if (structTag.StructType is FRotator rotator)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FRotator({rotator.Pitch}, {rotator.Yaw}, {rotator.Roll})");
|
||||
}
|
||||
else if (structTag.StructType is FStructFallback fallback)
|
||||
{
|
||||
string formattedTags;
|
||||
if (fallback.Properties.Count > 0)
|
||||
{
|
||||
formattedTags = "[\n" + string.Join(",\n",
|
||||
fallback.Properties.Select(tag =>
|
||||
{
|
||||
string tagDataFormatted;
|
||||
if (tag.Tag is TextProperty text)
|
||||
{
|
||||
tagDataFormatted = $"\"{text.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is NameProperty name)
|
||||
{
|
||||
tagDataFormatted = $"\"{name.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is ObjectProperty
|
||||
objectproperty)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{objectproperty.Value}\"";
|
||||
}
|
||||
else if (tag.Tag.GenericValue is FScriptStruct innerStruct && innerStruct.StructType is FStructFallback nestedFallback)
|
||||
{
|
||||
if (nestedFallback.Properties.Count > 0)
|
||||
{
|
||||
tagDataFormatted = "{ " + string.Join(", ",
|
||||
nestedFallback.Properties.Select(nested =>
|
||||
{
|
||||
string nestedVal;
|
||||
if (nested.Tag is TextProperty textProp)
|
||||
nestedVal = $"\"{textProp.Value.Text}\"";
|
||||
else if (nested.Tag is NameProperty nameProp)
|
||||
nestedVal = $"\"{nameProp.Value.Text}\"";
|
||||
else
|
||||
nestedVal = $"\"{nested.Tag.GenericValue}\"";
|
||||
|
||||
return $"\"{nested.Name}\": {nestedVal}";
|
||||
})) + " }";
|
||||
}
|
||||
else
|
||||
{
|
||||
tagDataFormatted = "{}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tagDataFormatted = tag.Tag.GenericValue != null ? tag.Tag.GenericValue.ToString() : "{}";
|
||||
}
|
||||
;
|
||||
|
||||
return $"\t\t{{ \"{tag.Name}\": {tagDataFormatted} }}";
|
||||
})) + "\n\t]";
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedTags = "[]";
|
||||
}
|
||||
|
||||
ShouldAppend(formattedTags);
|
||||
}
|
||||
else if (structTag.StructType is FGameplayTagContainer
|
||||
gameplayTag)
|
||||
{
|
||||
var tags = gameplayTag.GameplayTags.ToList();
|
||||
if (tags.Count > 1)
|
||||
{
|
||||
var formattedTags = "[\n" + string.Join(",\n",
|
||||
tags.Select(tag =>
|
||||
$"\t\t\"{tag.TagName}\"")) +
|
||||
"\n\t]";
|
||||
ShouldAppend(formattedTags);
|
||||
}
|
||||
else if (tags.Any())
|
||||
{
|
||||
ShouldAppend($"\"{tags.First().TagName}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShouldAppend("[]");
|
||||
}
|
||||
}
|
||||
else if (structTag.StructType is FLinearColor color)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FLinearColor({color.R}, {color.G}, {color.B}, {color.A})");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShouldAppend($"\"{result}\"");
|
||||
}
|
||||
}
|
||||
else if (key.Tag.GetType().Name == "ObjectProperty" ||
|
||||
key.Tag.GetType().Name == "TextProperty" ||
|
||||
key.PropertyType == "StrProperty" ||
|
||||
key.PropertyType == "NameProperty" ||
|
||||
key.PropertyType == "ClassProperty")
|
||||
{
|
||||
ShouldAppend($"\"{result}\"");
|
||||
}
|
||||
else if (key.Tag.GenericValue is UScriptSet set)
|
||||
{
|
||||
var formattedSet = "[\n" + string.Join(",\n",
|
||||
set.Properties.Select(p =>
|
||||
$"\t\"{p.GenericValue}\"")) +
|
||||
"\n\t]";
|
||||
ShouldAppend(formattedSet);
|
||||
}
|
||||
else if (key.Tag.GenericValue is UScriptMap map)
|
||||
{
|
||||
var formattedMap = "[\n" + string.Join(",\n",
|
||||
map.Properties.Select(kvp =>
|
||||
$"\t{{\n\t\t\"{kvp.Key}\": \"{kvp.Value}\"\n\t}}")) +
|
||||
"\n\t]";
|
||||
ShouldAppend(formattedMap);
|
||||
}
|
||||
else if (key.Tag.GenericValue is UScriptArray array)
|
||||
{
|
||||
var formattedArray = "[\n" + string.Join(",\n",
|
||||
array.Properties.Select(p =>
|
||||
{
|
||||
if (p.GenericValue is FScriptStruct vectorInArray &&
|
||||
vectorInArray.StructType is FVector vector)
|
||||
{
|
||||
return
|
||||
$"FVector({vector.X}, {vector.Y}, {vector.Z})";
|
||||
}
|
||||
|
||||
if (p.GenericValue is FScriptStruct
|
||||
vector2dInArray &&
|
||||
vector2dInArray
|
||||
.StructType is FVector2D vector2d)
|
||||
{
|
||||
return $"FVector2D({vector2d.X}, {vector2d.Y})";
|
||||
}
|
||||
|
||||
if (p.GenericValue is FScriptStruct structInArray &&
|
||||
structInArray.StructType is FRotator rotator)
|
||||
{
|
||||
return
|
||||
$"FRotator({rotator.Pitch}, {rotator.Yaw}, {rotator.Roll})";
|
||||
}
|
||||
else if
|
||||
(p.GenericValue is FScriptStruct
|
||||
fallbacksInArray &&
|
||||
fallbacksInArray.StructType is FStructFallback
|
||||
fallback)
|
||||
{
|
||||
string formattedTags;
|
||||
if (fallback.Properties.Count > 0)
|
||||
{
|
||||
formattedTags = "\t[\n" + string.Join(",\n",
|
||||
fallback.Properties.Select(tag =>
|
||||
{
|
||||
string tagDataFormatted;
|
||||
if (tag.Tag is TextProperty text)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{text.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is NameProperty
|
||||
name)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{name.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is ObjectProperty
|
||||
objectproperty)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{objectproperty.Value}\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{tag.Tag.GenericValue}\"";
|
||||
}
|
||||
|
||||
return
|
||||
$"\t\t\"{tag.Name}\": {tagDataFormatted}";
|
||||
})) + "\n\t]";
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedTags = "{}";
|
||||
}
|
||||
|
||||
return formattedTags;
|
||||
}
|
||||
else if
|
||||
(p.GenericValue is FScriptStruct
|
||||
gameplayTagsInArray &&
|
||||
gameplayTagsInArray.StructType is
|
||||
FGameplayTagContainer gameplayTag)
|
||||
{
|
||||
var tags = gameplayTag.GameplayTags.ToList();
|
||||
if (tags.Count > 1)
|
||||
{
|
||||
var formattedTags =
|
||||
"[\n" + string.Join(",\n",
|
||||
tags.Select(tag =>
|
||||
$"\t\t\"{tag.TagName}\"")) +
|
||||
"\n\t]";
|
||||
return formattedTags;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"\"{tags.First().TagName}\"";
|
||||
}
|
||||
}
|
||||
|
||||
return $"\t\t\"{p.GenericValue}\"";
|
||||
})) + "\n\t]";
|
||||
ShouldAppend(formattedArray);
|
||||
}
|
||||
else if (key.Tag.GenericValue is FMulticastScriptDelegate multicast)
|
||||
{
|
||||
var list = multicast.InvocationList;
|
||||
ShouldAppend(list.Length == 0 ? "[]" : $"[{string.Join(", ", list.Select(x => $"\"{x.FunctionName}\""))}]");
|
||||
}
|
||||
|
||||
else if (key.Tag.GenericValue is bool boolResult)
|
||||
{
|
||||
ShouldAppend(boolResult.ToString().ToLower());
|
||||
}
|
||||
else
|
||||
{
|
||||
ShouldAppend(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//outputBuilder.Append($"\nType: {export.Value.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var childProperties = blueprintGeneratedClass?.ChildProperties ??
|
||||
verseClass?.ChildProperties;
|
||||
if (childProperties != null)
|
||||
{
|
||||
foreach (FProperty property in childProperties)
|
||||
{
|
||||
if (!stringsarray.Contains(property.Name.PlainText))
|
||||
outputBuilder.AppendLine(
|
||||
$"\t{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || KismetExtensions.GetPropertyProperty(property) ? "*" : string.Empty)} {property.Name.PlainText.Replace(" ", "")} = {property.Name.PlainText.Replace(" ", "")}placenolder;");
|
||||
}
|
||||
}
|
||||
var funcMapOrder =
|
||||
blueprintGeneratedClass?.FuncMap?.Keys.Select(fname => fname.ToString())
|
||||
.ToList() ?? verseClass?.FuncMap.Keys.Select(fname => fname.ToString())
|
||||
.ToList();
|
||||
var functions = pkg.ExportsLazy
|
||||
.Where(e => e.Value is UFunction)
|
||||
.Select(e => (UFunction) e.Value)
|
||||
.OrderBy(f =>
|
||||
{
|
||||
if (funcMapOrder != null)
|
||||
{
|
||||
var functionName = f.Name.ToString();
|
||||
int indexx = funcMapOrder.IndexOf(functionName);
|
||||
return indexx >= 0 ? indexx : int.MaxValue;
|
||||
}
|
||||
|
||||
return int.MaxValue;
|
||||
})
|
||||
.ThenBy(f => f.Name.ToString())
|
||||
.ToList();
|
||||
|
||||
var jumpCodeOffsetsMap = new Dictionary<string, List<int>>();
|
||||
|
||||
foreach (var function in functions.AsEnumerable().Reverse())
|
||||
{
|
||||
if (function?.ScriptBytecode == null)
|
||||
continue;
|
||||
|
||||
foreach (var property in function.ScriptBytecode)
|
||||
{
|
||||
string? label = null;
|
||||
int? offset = null;
|
||||
|
||||
switch (property.Token)
|
||||
{
|
||||
case EExprToken.EX_JumpIfNot:
|
||||
label = ((EX_JumpIfNot) property).ObjectPath?.ToString()?.Split('.').Last().Split('[')[0];
|
||||
offset = (int) ((EX_JumpIfNot) property).CodeOffset;
|
||||
break;
|
||||
|
||||
case EExprToken.EX_Jump:
|
||||
label = ((EX_Jump) property).ObjectPath?.ToString()?.Split('.').Last().Split('[')[0];
|
||||
offset = (int) ((EX_Jump) property).CodeOffset;
|
||||
break;
|
||||
|
||||
case EExprToken.EX_LocalFinalFunction:
|
||||
{
|
||||
EX_FinalFunction op = (EX_FinalFunction) property;
|
||||
label = op.StackNode?.Name?.ToString()?.Split('.').Last().Split('[')[0];
|
||||
|
||||
if (op.Parameters.Length == 1 && op.Parameters[0] is EX_IntConst intConst)
|
||||
offset = intConst.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(label) && offset.HasValue)
|
||||
{
|
||||
if (!jumpCodeOffsetsMap.TryGetValue(label, out var list))
|
||||
jumpCodeOffsetsMap[label] = list = new List<int>();
|
||||
|
||||
list.Add(offset.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
foreach (var function in functions)
|
||||
{
|
||||
string argsList = "";
|
||||
string returnFunc = "void";
|
||||
if (function?.ChildProperties != null)
|
||||
{
|
||||
foreach (FProperty property in function.ChildProperties)
|
||||
{
|
||||
if (property.Name.PlainText == "ReturnValue")
|
||||
{
|
||||
returnFunc =
|
||||
$"{(property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm) ? "const " : string.Empty)}{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || KismetExtensions.GetPrefix(property.GetType().Name) == "U" ? "*" : string.Empty)}";
|
||||
}
|
||||
else if (!(property.Name.ToString().EndsWith("_ReturnValue") ||
|
||||
property.Name.ToString().StartsWith("CallFunc_") ||
|
||||
property.Name.ToString().StartsWith("K2Node_") ||
|
||||
property.Name.ToString()
|
||||
.StartsWith("Temp_")) || // removes useless args
|
||||
property.PropertyFlags.HasFlag(EPropertyFlags.Edit))
|
||||
{
|
||||
argsList +=
|
||||
$"{(property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm) ? "const " : string.Empty)}{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || KismetExtensions.GetPrefix(property.GetType().Name) == "U" ? "*" : string.Empty)}{(property.PropertyFlags.HasFlag(EPropertyFlags.OutParm) ? "&" : string.Empty)} {Regex.Replace(property.Name.ToString(), @"^__verse_0x[0-9A-Fa-f]+_", "")}, ";
|
||||
}
|
||||
}
|
||||
}
|
||||
argsList = argsList.TrimEnd(',', ' ');
|
||||
|
||||
outputBuilder.AppendLine($"\n\t{returnFunc} {function.Name.Replace(" ", "")}({argsList})\n\t{{");
|
||||
if (function?.ScriptBytecode != null)
|
||||
{
|
||||
var jumpCodeOffsets = jumpCodeOffsetsMap.TryGetValue(function.Name, out var list) ? list : new List<int>();
|
||||
foreach (KismetExpression property in function.ScriptBytecode)
|
||||
{
|
||||
KismetExtensions.ProcessExpression(property.Token, property, outputBuilder, jumpCodeOffsets);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outputBuilder.Append(
|
||||
"\n\t // This function does not have Bytecode \n\n");
|
||||
outputBuilder.Append("\t}\n");
|
||||
}
|
||||
}
|
||||
|
||||
outputBuilder.Append("\n\n}");
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
string pattern = $@"\w+placenolder";
|
||||
string updatedOutput = Regex.Replace(outputBuilder.ToString(), pattern, "nullptr");
|
||||
|
||||
|
||||
var pkg = Provider.LoadPackage(entry);
|
||||
|
||||
var outputBuilder = new StringBuilder();
|
||||
for (var i = 0; i < pkg.ExportMapLength; i++)
|
||||
{
|
||||
var pointer = new FPackageIndex(pkg, i + 1).ResolvedObject;
|
||||
if (pointer?.Object is null)
|
||||
continue;
|
||||
|
||||
var dummy = ((AbstractUePackage) pkg).ConstructObject(
|
||||
pointer.Class?.Object?.Value as UStruct, pkg);
|
||||
switch (dummy)
|
||||
{
|
||||
case UBlueprintGeneratedClass _:
|
||||
case UVerseClass _:
|
||||
{
|
||||
var blueprintGeneratedClass = pkg.ExportsLazy.FirstOrDefault(e => e.Value is UBlueprintGeneratedClass)?.Value as UBlueprintGeneratedClass;
|
||||
var verseClass = pkg.ExportsLazy.Where(export => export.Value is UVerseClass).Select(export => (UVerseClass) export.Value).FirstOrDefault();
|
||||
|
||||
var stringsarray = new List<string>();
|
||||
if (blueprintGeneratedClass != null)
|
||||
{
|
||||
{
|
||||
var mainClass = blueprintGeneratedClass?.Name ?? verseClass?.Name;
|
||||
var superStructName = blueprintGeneratedClass?.SuperStruct?.Name ?? verseClass?.SuperStruct?.Name ?? string.Empty;
|
||||
outputBuilder.AppendLine(
|
||||
$"class {KismetExtensions.GetPrefix(blueprintGeneratedClass?.GetType().Name ?? verseClass?.GetType().Name)}{mainClass} : public {KismetExtensions.GetPrefix(blueprintGeneratedClass?.GetType().Name ?? verseClass?.GetType().Name)}{superStructName}\n{{\npublic:");
|
||||
|
||||
foreach (var export in pkg.ExportsLazy)
|
||||
{
|
||||
if (export.Value is not UBlueprintGeneratedClass)
|
||||
|
||||
if (export.Value.Name.StartsWith("Default__") &&
|
||||
export.Value.Name.EndsWith(mainClass ?? string.Empty))
|
||||
{
|
||||
var exportObject = export.Value;
|
||||
foreach (var key in exportObject.Properties)
|
||||
{
|
||||
stringsarray.Add(key.Name.PlainText);
|
||||
string placeholder = $"{key.Name}placenolder";
|
||||
string result = key.Tag.GenericValue.ToString();
|
||||
string keyName = key.Name.PlainText.Replace(" ", "");
|
||||
|
||||
var propertyTag = key.Tag.GetValue(typeof(object));
|
||||
|
||||
void ShouldAppend(string? value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
if (outputBuilder.ToString().Contains(placeholder))
|
||||
{
|
||||
outputBuilder.Replace(placeholder, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputBuilder.AppendLine(
|
||||
$"\t{KismetExtensions.GetPropertyType(propertyTag)} {keyName} = {value};");
|
||||
}
|
||||
}
|
||||
|
||||
if (key.Tag.GenericValue is FScriptStruct structTag)
|
||||
{
|
||||
if (structTag.StructType is FVector vector)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector({vector.X}, {vector.Y}, {vector.Z})");
|
||||
}
|
||||
else if (structTag.StructType is FGuid guid)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FGuid({guid.A}, {guid.B}, {guid.C}, {guid.D})");
|
||||
}
|
||||
else if (structTag.StructType is TIntVector3<int> vector3)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector({vector3.X}, {vector3.Y}, {vector3.Z})");
|
||||
}
|
||||
else if (structTag.StructType is TIntVector3<float>
|
||||
floatVector3)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector({floatVector3.X}, {floatVector3.Y}, {floatVector3.Z})");
|
||||
}
|
||||
else if (structTag.StructType is TIntVector2<float>
|
||||
floatVector2)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FVector2D({floatVector2.X}, {floatVector2.Y})");
|
||||
}
|
||||
else if (structTag.StructType is FVector2D vector2d)
|
||||
{
|
||||
ShouldAppend($"FVector2D({vector2d.X}, {vector2d.Y})");
|
||||
}
|
||||
else if (structTag.StructType is FRotator rotator)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FRotator({rotator.Pitch}, {rotator.Yaw}, {rotator.Roll})");
|
||||
}
|
||||
else if (structTag.StructType is FStructFallback fallback)
|
||||
{
|
||||
string formattedTags;
|
||||
if (fallback.Properties.Count > 0)
|
||||
{
|
||||
formattedTags = "[\n" + string.Join(",\n",
|
||||
fallback.Properties.Select(tag =>
|
||||
{
|
||||
string tagDataFormatted;
|
||||
if (tag.Tag is TextProperty text)
|
||||
{
|
||||
tagDataFormatted = $"\"{text.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is NameProperty name)
|
||||
{
|
||||
tagDataFormatted = $"\"{name.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is ObjectProperty
|
||||
objectproperty)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{objectproperty.Value}\"";
|
||||
}
|
||||
else if (tag.Tag.GenericValue is FScriptStruct innerStruct && innerStruct.StructType is FStructFallback nestedFallback)
|
||||
{
|
||||
if (nestedFallback.Properties.Count > 0)
|
||||
{
|
||||
tagDataFormatted = "{ " + string.Join(", ",
|
||||
nestedFallback.Properties.Select(nested =>
|
||||
{
|
||||
string nestedVal;
|
||||
if (nested.Tag is TextProperty textProp)
|
||||
nestedVal = $"\"{textProp.Value.Text}\"";
|
||||
else if (nested.Tag is NameProperty nameProp)
|
||||
nestedVal = $"\"{nameProp.Value.Text}\"";
|
||||
else
|
||||
nestedVal = $"\"{nested.Tag.GenericValue}\"";
|
||||
|
||||
return $"\"{nested.Name}\": {nestedVal}";
|
||||
})) + " }";
|
||||
}
|
||||
else
|
||||
{
|
||||
tagDataFormatted = "{}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tagDataFormatted = tag.Tag.GenericValue != null ? tag.Tag.GenericValue.ToString() : "{}";
|
||||
}
|
||||
;
|
||||
|
||||
return $"\t\t{{ \"{tag.Name}\": {tagDataFormatted} }}";
|
||||
})) + "\n\t]";
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedTags = "[]";
|
||||
}
|
||||
|
||||
ShouldAppend(formattedTags);
|
||||
}
|
||||
else if (structTag.StructType is FGameplayTagContainer
|
||||
gameplayTag)
|
||||
{
|
||||
var tags = gameplayTag.GameplayTags.ToList();
|
||||
if (tags.Count > 1)
|
||||
{
|
||||
var formattedTags = "[\n" + string.Join(",\n",
|
||||
tags.Select(tag =>
|
||||
$"\t\t\"{tag.TagName}\"")) +
|
||||
"\n\t]";
|
||||
ShouldAppend(formattedTags);
|
||||
}
|
||||
else if (tags.Any())
|
||||
{
|
||||
ShouldAppend($"\"{tags.First().TagName}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShouldAppend("[]");
|
||||
}
|
||||
}
|
||||
else if (structTag.StructType is FLinearColor color)
|
||||
{
|
||||
ShouldAppend(
|
||||
$"FLinearColor({color.R}, {color.G}, {color.B}, {color.A})");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShouldAppend($"\"{result}\"");
|
||||
}
|
||||
}
|
||||
else if (key.Tag.GetType().Name == "ObjectProperty" ||
|
||||
key.Tag.GetType().Name == "TextProperty" ||
|
||||
key.PropertyType == "StrProperty" ||
|
||||
key.PropertyType == "NameProperty" ||
|
||||
key.PropertyType == "ClassProperty")
|
||||
{
|
||||
ShouldAppend($"\"{result}\"");
|
||||
}
|
||||
else if (key.Tag.GenericValue is UScriptSet set)
|
||||
{
|
||||
var formattedSet = "[\n" + string.Join(",\n",
|
||||
set.Properties.Select(p =>
|
||||
$"\t\"{p.GenericValue}\"")) +
|
||||
"\n\t]";
|
||||
ShouldAppend(formattedSet);
|
||||
}
|
||||
else if (key.Tag.GenericValue is UScriptMap map)
|
||||
{
|
||||
var formattedMap = "[\n" + string.Join(",\n",
|
||||
map.Properties.Select(kvp =>
|
||||
$"\t{{\n\t\t\"{kvp.Key}\": \"{kvp.Value}\"\n\t}}")) +
|
||||
"\n\t]";
|
||||
ShouldAppend(formattedMap);
|
||||
}
|
||||
else if (key.Tag.GenericValue is UScriptArray array)
|
||||
{
|
||||
var formattedArray = "[\n" + string.Join(",\n",
|
||||
array.Properties.Select(p =>
|
||||
{
|
||||
if (p.GenericValue is FScriptStruct vectorInArray &&
|
||||
vectorInArray.StructType is FVector vector)
|
||||
{
|
||||
return
|
||||
$"FVector({vector.X}, {vector.Y}, {vector.Z})";
|
||||
}
|
||||
|
||||
if (p.GenericValue is FScriptStruct
|
||||
vector2dInArray &&
|
||||
vector2dInArray
|
||||
.StructType is FVector2D vector2d)
|
||||
{
|
||||
return $"FVector2D({vector2d.X}, {vector2d.Y})";
|
||||
}
|
||||
|
||||
if (p.GenericValue is FScriptStruct structInArray &&
|
||||
structInArray.StructType is FRotator rotator)
|
||||
{
|
||||
return
|
||||
$"FRotator({rotator.Pitch}, {rotator.Yaw}, {rotator.Roll})";
|
||||
}
|
||||
else if
|
||||
(p.GenericValue is FScriptStruct
|
||||
fallbacksInArray &&
|
||||
fallbacksInArray.StructType is FStructFallback
|
||||
fallback)
|
||||
{
|
||||
string formattedTags;
|
||||
if (fallback.Properties.Count > 0)
|
||||
{
|
||||
formattedTags = "\t[\n" + string.Join(",\n",
|
||||
fallback.Properties.Select(tag =>
|
||||
{
|
||||
string tagDataFormatted;
|
||||
if (tag.Tag is TextProperty text)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{text.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is NameProperty
|
||||
name)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{name.Value.Text}\"";
|
||||
}
|
||||
else if (tag.Tag is ObjectProperty
|
||||
objectproperty)
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{objectproperty.Value}\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
tagDataFormatted =
|
||||
$"\"{tag.Tag.GenericValue}\"";
|
||||
}
|
||||
|
||||
return
|
||||
$"\t\t\"{tag.Name}\": {tagDataFormatted}";
|
||||
})) + "\n\t]";
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedTags = "{}";
|
||||
}
|
||||
|
||||
return formattedTags;
|
||||
}
|
||||
else if
|
||||
(p.GenericValue is FScriptStruct
|
||||
gameplayTagsInArray &&
|
||||
gameplayTagsInArray.StructType is
|
||||
FGameplayTagContainer gameplayTag)
|
||||
{
|
||||
var tags = gameplayTag.GameplayTags.ToList();
|
||||
if (tags.Count > 1)
|
||||
{
|
||||
var formattedTags =
|
||||
"[\n" + string.Join(",\n",
|
||||
tags.Select(tag =>
|
||||
$"\t\t\"{tag.TagName}\"")) +
|
||||
"\n\t]";
|
||||
return formattedTags;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"\"{tags.First().TagName}\"";
|
||||
}
|
||||
}
|
||||
|
||||
return $"\t\t\"{p.GenericValue}\"";
|
||||
})) + "\n\t]";
|
||||
ShouldAppend(formattedArray);
|
||||
}
|
||||
else if (key.Tag.GenericValue is FMulticastScriptDelegate multicast)
|
||||
{
|
||||
var list = multicast.InvocationList;
|
||||
ShouldAppend(list.Length == 0 ? "[]" : $"[{string.Join(", ", list.Select(x => $"\"{x.FunctionName}\""))}]");
|
||||
}
|
||||
|
||||
else if (key.Tag.GenericValue is bool boolResult)
|
||||
{
|
||||
ShouldAppend(boolResult.ToString().ToLower());
|
||||
}
|
||||
else
|
||||
{
|
||||
ShouldAppend(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//outputBuilder.Append($"\nType: {export.Value.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var childProperties = blueprintGeneratedClass?.ChildProperties ??
|
||||
verseClass?.ChildProperties;
|
||||
if (childProperties != null)
|
||||
{
|
||||
foreach (FProperty property in childProperties)
|
||||
{
|
||||
if (!stringsarray.Contains(property.Name.PlainText))
|
||||
outputBuilder.AppendLine(
|
||||
$"\t{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || property.PropertyFlags.HasFlag(EPropertyFlags.ReferenceParm) || KismetExtensions.GetPropertyProperty(property) ? "*" : string.Empty)} {property.Name.PlainText.Replace(" ", "")} = {property.Name.PlainText.Replace(" ", "")}placenolder;");
|
||||
}
|
||||
}
|
||||
var funcMapOrder =
|
||||
blueprintGeneratedClass?.FuncMap?.Keys.Select(fname => fname.ToString())
|
||||
.ToList() ?? verseClass?.FuncMap.Keys.Select(fname => fname.ToString())
|
||||
.ToList();
|
||||
var functions = pkg.ExportsLazy
|
||||
.Where(e => e.Value is UFunction)
|
||||
.Select(e => (UFunction) e.Value)
|
||||
.OrderBy(f =>
|
||||
{
|
||||
if (funcMapOrder != null)
|
||||
{
|
||||
var functionName = f.Name.ToString();
|
||||
int indexx = funcMapOrder.IndexOf(functionName);
|
||||
return indexx >= 0 ? indexx : int.MaxValue;
|
||||
}
|
||||
|
||||
return int.MaxValue;
|
||||
})
|
||||
.ThenBy(f => f.Name.ToString())
|
||||
.ToList();
|
||||
|
||||
var jumpCodeOffsetsMap = new Dictionary<string, List<int>>();
|
||||
|
||||
foreach (var function in functions.AsEnumerable().Reverse())
|
||||
{
|
||||
if (function?.ScriptBytecode == null)
|
||||
continue;
|
||||
|
||||
foreach (var property in function.ScriptBytecode)
|
||||
{
|
||||
string? label = null;
|
||||
int? offset = null;
|
||||
|
||||
switch (property.Token)
|
||||
{
|
||||
case EExprToken.EX_JumpIfNot:
|
||||
label = ((EX_JumpIfNot) property).ObjectPath?.ToString()?.Split('.').Last().Split('[')[0];
|
||||
offset = (int) ((EX_JumpIfNot) property).CodeOffset;
|
||||
break;
|
||||
|
||||
case EExprToken.EX_Jump:
|
||||
label = ((EX_Jump) property).ObjectPath?.ToString()?.Split('.').Last().Split('[')[0];
|
||||
offset = (int) ((EX_Jump) property).CodeOffset;
|
||||
break;
|
||||
|
||||
case EExprToken.EX_LocalFinalFunction:
|
||||
{
|
||||
EX_FinalFunction op = (EX_FinalFunction) property;
|
||||
label = op.StackNode?.Name?.ToString()?.Split('.').Last().Split('[')[0];
|
||||
|
||||
if (op.Parameters.Length == 1 && op.Parameters[0] is EX_IntConst intConst)
|
||||
offset = intConst.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(label) && offset.HasValue)
|
||||
{
|
||||
if (!jumpCodeOffsetsMap.TryGetValue(label, out var list))
|
||||
jumpCodeOffsetsMap[label] = list = new List<int>();
|
||||
|
||||
list.Add(offset.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
foreach (var function in functions)
|
||||
{
|
||||
string argsList = "";
|
||||
string returnFunc = "void";
|
||||
if (function?.ChildProperties != null)
|
||||
{
|
||||
foreach (FProperty property in function.ChildProperties)
|
||||
{
|
||||
if (property.Name.PlainText == "ReturnValue")
|
||||
{
|
||||
returnFunc =
|
||||
$"{(property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm) ? "const " : string.Empty)}{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || KismetExtensions.GetPrefix(property.GetType().Name) == "U" ? "*" : string.Empty)}";
|
||||
}
|
||||
else if (!(property.Name.ToString().EndsWith("_ReturnValue") ||
|
||||
property.Name.ToString().StartsWith("CallFunc_") ||
|
||||
property.Name.ToString().StartsWith("K2Node_") ||
|
||||
property.Name.ToString()
|
||||
.StartsWith("Temp_")) || // removes useless args
|
||||
property.PropertyFlags.HasFlag(EPropertyFlags.Edit))
|
||||
{
|
||||
argsList +=
|
||||
$"{(property.PropertyFlags.HasFlag(EPropertyFlags.ConstParm) ? "const " : string.Empty)}{KismetExtensions.GetPrefix(property.GetType().Name)}{KismetExtensions.GetPropertyType(property)}{(property.PropertyFlags.HasFlag(EPropertyFlags.InstancedReference) || KismetExtensions.GetPrefix(property.GetType().Name) == "U" ? "*" : string.Empty)}{(property.PropertyFlags.HasFlag(EPropertyFlags.OutParm) ? "&" : string.Empty)} {Regex.Replace(property.Name.ToString(), @"^__verse_0x[0-9A-Fa-f]+_", "")}, ";
|
||||
}
|
||||
}
|
||||
}
|
||||
argsList = argsList.TrimEnd(',', ' ');
|
||||
|
||||
outputBuilder.AppendLine($"\n\t{returnFunc} {function.Name.Replace(" ", "")}({argsList})\n\t{{");
|
||||
if (function?.ScriptBytecode != null)
|
||||
{
|
||||
var jumpCodeOffsets = jumpCodeOffsetsMap.TryGetValue(function.Name, out var list) ? list : new List<int>();
|
||||
foreach (KismetExpression property in function.ScriptBytecode)
|
||||
{
|
||||
KismetExtensions.ProcessExpression(property.Token, property, outputBuilder, jumpCodeOffsets);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outputBuilder.Append(
|
||||
"\n\t // This function does not have Bytecode \n\n");
|
||||
outputBuilder.Append("\t}\n");
|
||||
}
|
||||
}
|
||||
|
||||
outputBuilder.Append("\n\n}");
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
string pattern = $@"\w+placenolder";
|
||||
string updatedOutput = Regex.Replace(outputBuilder.ToString(), pattern, "nullptr");
|
||||
|
||||
TabControl.SelectedTab.SetDocumentText(updatedOutput, false, false);
|
||||
}
|
||||
private void SaveAndPlaySound(string fullPath, string ext, byte[] data)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user