mirror of
https://github.com/4sval/FModel.git
synced 2026-06-23 16:30:35 -05:00
SoftObjectPath notify animation support
Marvel Rivals emotes will display notified models
This commit is contained in:
parent
a97d773c64
commit
b5c1fdccc6
|
|
@ -1 +1 @@
|
|||
Subproject commit 2aed4da1ee440cd421222526bdc501031f685be6
|
||||
Subproject commit 7c76fdc0d3053170121bd5b6f0bb3b5fa28afbf6
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,111 +122,89 @@ 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 || !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 when animSequence.Skeleton.TryLoad(out USkeleton skeleton) => skeleton.ConvertAnims(animSequence),
|
||||
UAnimMontage animMontage when animMontage.Skeleton.TryLoad(out USkeleton skeleton) => skeleton.ConvertAnims(animMontage),
|
||||
UAnimComposite animComposite when animComposite.Skeleton.TryLoad(out USkeleton skeleton) => 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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user