Merge pull request #550 from 4sval/on-hold
Some checks failed
FModel QA Builder / build (push) Has been cancelled

On hold
This commit is contained in:
Valentin 2025-02-16 00:23:44 +01:00 committed by GitHub
commit 34116d62b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 100 additions and 110 deletions

@ -1 +1 @@
Subproject commit 9a63be6718300901eebe6af9c65908c2c69c67b0
Subproject commit c36748f206d19eea45a6f2ea4cc82e56617d87c9

View File

@ -1,13 +1,19 @@
using RestSharp;
using RestSharp.Interceptors;
namespace FModel.ViewModels.ApiEndpoints;
public abstract class AbstractApiProvider
{
protected readonly RestClient _client;
protected readonly Interceptor _interceptor;
protected AbstractApiProvider(RestClient client)
{
_client = client;
_interceptor = new CompatibilityInterceptor
{
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
};
}
}

View File

@ -66,7 +66,7 @@ public class DynamicApiEndpoint : AbstractApiProvider
{
var request = new FRestRequest(url)
{
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
Interceptors = [_interceptor]
};
var response = await _client.ExecuteAsync(request, token).ConfigureAwait(false);
Log.Information("[{Method}] [{Status}({StatusCode})] '{Resource}'", request.Method, response.StatusDescription, (int) response.StatusCode, response.ResponseUri?.OriginalString);

View File

@ -15,7 +15,7 @@ public class FortniteCentralApiEndpoint : AbstractApiProvider
{
var request = new FRestRequest("https://fortnitecentral.genxgames.gg/api/v1/hotfixes")
{
OnBeforeDeserialization = resp => { resp.ContentType = "application/json; charset=utf-8"; }
Interceptors = [_interceptor]
};
request.AddParameter("lang", language);
var response = await _client.ExecuteAsync<Dictionary<string, Dictionary<string, string>>>(request, token).ConfigureAwait(false);

View File

@ -66,7 +66,7 @@ public class BackupManagerViewModel : ViewModel
var backupFolder = Path.Combine(UserSettings.Default.OutputDirectory, "Backups");
var fileName = $"{_gameName}_{DateTime.Now:MM'_'dd'_'yyyy}.fbkp";
var fullPath = Path.Combine(backupFolder, fileName);
var func = new Func<GameFile, bool>(x => !x.Path.EndsWith(".uexp") && !x.Path.EndsWith(".ubulk") && !x.Path.EndsWith(".uptnl"));
var func = new Func<GameFile, bool>(x => !x.IsUePackagePayload);
using var fileStream = new FileStream(fullPath, FileMode.Create);
using var compressedStream = LZ4Stream.Encode(fileStream, LZ4Level.L00_FAST);
@ -80,7 +80,7 @@ public class BackupManagerViewModel : ViewModel
if (!func(asset)) continue;
writer.Write(asset.Size);
writer.Write(asset.IsEncrypted);
writer.Write($"/{asset.Path.ToLower()}");
writer.Write(asset.Path);
}
SaveCheck(fullPath, fileName, "created", "create");
@ -121,6 +121,7 @@ public enum EBackupVersion : byte
{
BeforeVersionWasAdded = 0,
Initial,
PerfectPath, // no more leading slash and ToLower
LatestPlusOne,
Latest = LatestPlusOne - 1

View File

@ -182,7 +182,7 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
{
case ELoadingMode.AllButNew:
{
var paths = new HashSet<string>();
var paths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var magic = archive.Read<uint>();
if (magic != BackupManagerViewModel.FBKP_MAGIC)
{
@ -192,7 +192,7 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
cancellationToken.ThrowIfCancellationRequested();
archive.Position += 29;
paths.Add(archive.ReadString().ToLower()[1..]);
paths.Add(archive.ReadString()[1..]);
archive.Position += 4;
}
}
@ -205,7 +205,10 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
cancellationToken.ThrowIfCancellationRequested();
archive.Position += sizeof(long) + sizeof(byte);
paths.Add(archive.ReadString().ToLower()[1..]);
var fullPath = archive.ReadString();
if (version < EBackupVersion.PerfectPath) fullPath = fullPath[1..];
paths.Add(fullPath);
}
}
@ -233,7 +236,7 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
var uncompressedSize = archive.Read<long>();
var isEncrypted = archive.ReadFlag();
archive.Position += 4;
var fullPath = archive.ReadString().ToLower()[1..];
var fullPath = archive.ReadString()[1..];
archive.Position += 4;
AddEntry(fullPath, uncompressedSize, isEncrypted, entries);
@ -249,7 +252,8 @@ public class LoadCommand : ViewModelCommand<LoadingModesViewModel>
var uncompressedSize = archive.Read<long>();
var isEncrypted = archive.ReadFlag();
var fullPath = archive.ReadString().ToLower()[1..];
var fullPath = archive.ReadString();
if (version < EBackupVersion.PerfectPath) fullPath = fullPath[1..];
AddEntry(fullPath, uncompressedSize, isEncrypted, entries);
}

View File

@ -35,9 +35,9 @@ public class Animation : IDisposable
_export = export;
Path = _export.GetPathName();
Name = _export.Name;
Sequences = Array.Empty<Sequence>();
Sequences = [];
Framing = new Dictionary<int, float>();
AttachedModels = new List<FGuid>();
AttachedModels = [];
}
public Animation(UObject export, CAnimSet animSet) : this(export)

View File

@ -20,7 +20,7 @@ public class TimeTracker : IDisposable
public bool IsActive;
public float ElapsedTime;
public float MaxElapsedTime;
public int TimeMultiplier;
public float TimeMultiplier;
public TimeTracker()
{
@ -51,7 +51,7 @@ public class TimeTracker : IDisposable
if (doMet)
{
MaxElapsedTime = 0.01f;
TimeMultiplier = 1;
TimeMultiplier = 1f;
}
}

View File

@ -153,7 +153,7 @@ public class SkeletalModel : UModel
GL.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.CullFace);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Line);
foreach (var collision in Collisions)
{
var boneMatrix = Matrix4x4.Identity;
@ -162,7 +162,7 @@ public class SkeletalModel : UModel
collision.Render(shader, boneMatrix);
}
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Fill);
GL.Enable(EnableCap.CullFace);
GL.Enable(EnableCap.DepthTest);
}

View File

@ -148,12 +148,12 @@ public class StaticModel : UModel
base.RenderCollision(shader);
GL.Disable(EnableCap.CullFace);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Line);
foreach (var collision in Collisions)
{
collision.Render(shader, Matrix4x4.Identity);
}
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Fill);
GL.Enable(EnableCap.CullFace);
}
}

View File

@ -255,7 +255,7 @@ public abstract class UModel : IRenderableModel
}
Vao.Bind();
GL.PolygonMode(MaterialFace.FrontAndBack, ShowWireframe ? PolygonMode.Line : PolygonMode.Fill);
GL.PolygonMode(TriangleFace.FrontAndBack, ShowWireframe ? PolygonMode.Line : PolygonMode.Fill);
foreach (var section in Sections)
{
if (!section.Show) continue;
@ -275,7 +275,7 @@ public abstract class UModel : IRenderableModel
GL.DrawElementsInstanced(PrimitiveType.Triangles, section.FacesCount, DrawElementsType.UnsignedInt, section.FirstFaceIndexPtr, TransformsCount);
}
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.PolygonMode(TriangleFace.FrontAndBack, PolygonMode.Fill);
Vao.Unbind();
if (IsSelected)

View File

@ -122,111 +122,90 @@ public class Renderer : IDisposable
public void Animate(Lazy<UObject> anim) => Animate(anim.Value, Options.SelectedModel);
private void Animate(UObject anim, FGuid guid)
{
if (!Options.TryGetModel(guid, out var m) || m is not SkeletalModel model)
if (anim is not UAnimSequenceBase animBase || !animBase.Skeleton.TryLoad(out USkeleton skeleton) ||
!Options.TryGetModel(guid, out var m) || m is not SkeletalModel model)
return;
float maxElapsedTime;
switch (anim)
var animSet = animBase switch
{
case UAnimSequence animSequence when animSequence.Skeleton.TryLoad(out USkeleton skeleton):
{
var animSet = skeleton.ConvertAnims(animSequence);
var animation = new Animation(animSequence, animSet, guid);
maxElapsedTime = animation.TotalElapsedTime;
model.Skeleton.Animate(animSet);
Options.AddAnimation(animation);
break;
}
case UAnimMontage animMontage when animMontage.Skeleton.TryLoad(out USkeleton skeleton):
{
var animSet = skeleton.ConvertAnims(animMontage);
var animation = new Animation(animMontage, animSet, guid);
maxElapsedTime = animation.TotalElapsedTime;
model.Skeleton.Animate(animSet);
Options.AddAnimation(animation);
UAnimSequence animSequence => skeleton.ConvertAnims(animSequence),
UAnimMontage animMontage => skeleton.ConvertAnims(animMontage),
UAnimComposite animComposite => skeleton.ConvertAnims(animComposite),
_ => throw new ArgumentException("Unknown animation type")
};
foreach (var notifyEvent in animMontage.Notifies)
var animation = new Animation(anim, animSet, guid);
model.Skeleton.Animate(animSet);
Options.AddAnimation(animation);
foreach (var notifyEvent in animBase.Notifies)
{
if (!notifyEvent.NotifyStateClass.TryLoad(out UObject notifyClass) ||
!notifyClass.TryGetValue(out UObject export, "SkeletalMeshProp", "StaticMeshProp", "Mesh", "SkeletalMeshTemplate"))
continue;
var t = Transform.Identity;
if (notifyClass.TryGetValue(out FTransform offset, "Offset"))
{
t.Rotation = offset.Rotation;
t.Position = offset.Translation * Constants.SCALE_DOWN_RATIO;
t.Scale = offset.Scale3D;
}
UModel addedModel = null;
switch (export)
{
case UStaticMesh st:
{
if (!notifyEvent.NotifyStateClass.TryLoad(out UObject notifyClass) ||
!notifyClass.TryGetValue(out FPackageIndex meshProp, "SkeletalMeshProp", "StaticMeshProp", "Mesh") ||
!meshProp.TryLoad(out UObject export)) continue;
var t = Transform.Identity;
if (notifyClass.TryGetValue(out FTransform offset, "Offset"))
guid = st.LightingGuid;
if (Options.TryGetModel(guid, out addedModel))
{
t.Rotation = offset.Rotation;
t.Position = offset.Translation * Constants.SCALE_DOWN_RATIO;
t.Scale = offset.Scale3D;
addedModel.AddInstance(t);
}
UModel addedModel = null;
switch (export)
else if (st.TryConvert(out var mesh))
{
case UStaticMesh st:
{
guid = st.LightingGuid;
if (Options.TryGetModel(guid, out addedModel))
{
addedModel.AddInstance(t);
}
else if (st.TryConvert(out var mesh))
{
addedModel = new StaticModel(st, mesh, t);
Options.Models[guid] = addedModel;
}
break;
}
case USkeletalMesh sk:
{
guid = Guid.NewGuid();
if (!Options.Models.ContainsKey(guid) && sk.TryConvert(out var mesh))
{
addedModel = new SkeletalModel(sk, mesh, t);
Options.Models[guid] = addedModel;
}
break;
}
}
if (addedModel == null)
throw new ArgumentException("Unknown model type");
addedModel.IsProp = true;
if (notifyClass.TryGetValue(out UObject skeletalMeshPropAnimation, "SkeletalMeshPropAnimation", "Animation"))
Animate(skeletalMeshPropAnimation, guid);
if (notifyClass.TryGetValue(out FName socketName, "SocketName"))
{
t = Transform.Identity;
if (notifyClass.TryGetValue(out FVector location, "LocationOffset", "Location"))
t.Position = location * Constants.SCALE_DOWN_RATIO;
if (notifyClass.TryGetValue(out FRotator rotation, "RotationOffset", "Rotation"))
t.Rotation = rotation.Quaternion();
if (notifyClass.TryGetValue(out FVector scale, "Scale"))
t.Scale = scale;
var s = new Socket($"ANIM_{addedModel.Name}", socketName, t, true);
model.Sockets.Add(s);
addedModel.Attachments.Attach(model, addedModel.GetTransform(), s,
new SocketAttachementInfo { Guid = guid, Instance = addedModel.SelectedInstance });
addedModel = new StaticModel(st, mesh, t);
Options.Models[guid] = addedModel;
}
break;
}
case USkeletalMesh sk:
{
guid = Guid.NewGuid();
if (!Options.Models.ContainsKey(guid) && sk.TryConvert(out var mesh))
{
addedModel = new SkeletalModel(sk, mesh, t);
Options.Models[guid] = addedModel;
}
break;
}
break;
}
case UAnimComposite animComposite when animComposite.Skeleton.TryLoad(out USkeleton skeleton):
if (addedModel == null)
throw new ArgumentException("Unknown model type");
addedModel.IsProp = true;
if (notifyClass.TryGetValue(out UObject skeletalMeshPropAnimation, "SkeletalMeshPropAnimation", "Animation", "AnimToPlay"))
Animate(skeletalMeshPropAnimation, guid);
if (notifyClass.TryGetValue(out FName socketName, "SocketName"))
{
var animSet = skeleton.ConvertAnims(animComposite);
var animation = new Animation(animComposite, animSet, guid);
maxElapsedTime = animation.TotalElapsedTime;
model.Skeleton.Animate(animSet);
Options.AddAnimation(animation);
break;
t = Transform.Identity;
if (notifyClass.TryGetValue(out FVector location, "LocationOffset", "Location"))
t.Position = location * Constants.SCALE_DOWN_RATIO;
if (notifyClass.TryGetValue(out FRotator rotation, "RotationOffset", "Rotation"))
t.Rotation = rotation.Quaternion();
if (notifyClass.TryGetValue(out FVector scale, "Scale"))
t.Scale = scale;
var s = new Socket($"ANIM_{addedModel.Name}", socketName, t, true);
model.Sockets.Add(s);
addedModel.Attachments.Attach(model, addedModel.GetTransform(), s,
new SocketAttachementInfo { Guid = guid, Instance = addedModel.SelectedInstance });
}
default:
throw new ArgumentException();
}
Options.Tracker.IsPaused = false;
Options.Tracker.SafeSetMaxElapsedTime(maxElapsedTime);
Options.Tracker.SafeSetMaxElapsedTime(animation.TotalElapsedTime);
}
public void Setup()

View File

@ -218,7 +218,7 @@ public class SnimGui
Layout("Animate With Rotation Only");ImGui.PushID(1);
ImGui.Checkbox("", ref s.Renderer.AnimateWithRotationOnly);
ImGui.PopID();Layout("Time Multiplier");ImGui.PushID(2);
ImGui.DragInt("", ref s.Renderer.Options.Tracker.TimeMultiplier, 0.1f, 1, 8, "x%i", ImGuiSliderFlags.NoInput);
ImGui.DragFloat("", ref s.Renderer.Options.Tracker.TimeMultiplier, 0.01f, 0.25f, 8f, "x%.2f", ImGuiSliderFlags.NoInput);
ImGui.PopID();Layout("Vertex Colors");ImGui.PushID(3);
var c = (int) s.Renderer.Color;
ImGui.Combo("vertex_colors", ref c,