Search Unity

[Released] Ultimate Replay - Complete state based replay system

Discussion in 'Assets and Asset Store' started by scottyboy805, Jun 28, 2017.

  1. UA_AV

    UA_AV

    Joined:
    Apr 18, 2017
    Posts:
    14
    Hello, and I just updated the latest version of your asset. Unfortunately, the ReplayManager still returned the same exception:
    upload_2020-1-17_9-2-11.png

    I even deleted the UltimateReplay folder and re-imported the asset, but the results are still the same.

    I need your help to look on this one.

    Thank you very much.
     
  2. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Yes you can send us your scene to info(at)trivialinteractive.co.uk but you would need to provide some instructions on how to use the scene and what you are trying to do.

    Yes the steps you mention are possible but there is nothing built in automatically to move onto a new recording. You will need to write a little script that waits for the playback to end and then changes to the next replay.

    If you want to detect when playback has ended it would be best to create a script that inherits form 'ReplayBehaviour' and override the 'OnReplayEnd' method because this will be called directly when the last frame of the recording has finished. I would have to check but I am fairly sure that the condition you use would never be true because the ReplayManager time value can never go beyond the end of the recording duration.
     
    UA_AV likes this.
  3. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Ultimate Replay 2.0 is now in development. To track development progress or suggest features/changes use the WIP thread which can be found here.
     
  4. UA_AV

    UA_AV

    Joined:
    Apr 18, 2017
    Posts:
    14
    Hi there, and it has been a while since I made a reply.

    I have found the cause of the bug I opened up to you and it is due to how I call my functions. As a result, I had to limit the number of functions I call during the recording.

    Thank you!
     
  5. UA_AV

    UA_AV

    Joined:
    Apr 18, 2017
    Posts:
    14
    Hello, and I have found an issue with regards to beginning a playback at a specified time.

    Based on your code documentation, I must call the SetPlaybackFrame(float, PlaybackOrigin) method before I call the BeginPlayback(false) method.

    With that, here is my custom function.
    Code (CSharp):
    1. public void BeginPlaybackNotFromStart(float _time)
    2. {
    3.     ReplayFileTarget replayFileTarget = FindObjectOfType<ReplayFileTarget>();
    4.     if (replayFileTarget != null)
    5.     {
    6.         replayFileTarget.FileOutputDirectory = $"{ Application.streamingAssetsPath }/{ replayFileDirectory }";
    7.         replayFileTarget.FileOutputName = replayFilename;
    8.  
    9.         ReplayManager.SetPlaybackFrame(_time);
    10.         ReplayManager.BeginPlayback(false);
    11.     }
    12. }
    However, after calling my BeginPlaybackNotFromStart(64.0f) function, the playback starts from the top (or at 0:00).

    For now, my temporary workaround for my BeginPlaybackNotFromStart(64.0f) function goes this way:
    Code (CSharp):
    1. public void BeginPlaybackNotFromStart(float _time)
    2. {
    3.     ReplayFileTarget replayFileTarget = FindObjectOfType<ReplayFileTarget>();
    4.     if (replayFileTarget != null)
    5.     {
    6.         replayFileTarget.FileOutputDirectory = $"{ Application.streamingAssetsPath }/{ replayFileDirectory }";
    7.         replayFileTarget.FileOutputName = replayFilename;
    8.  
    9.         ReplayManager.BeginPlayback(false);
    10.         ReplayManager.SetPlaybackFrame(_time);
    11.     }
    12. }
    The playback starts from the top for a number of frames before "skipping" to my specified time, which is at 64 seconds or at 1:04.

    I am using ReplayFileTarget as the ReplayManager's Target.

    May I know how I can get through this issue?

    Thank you very much in advance.
     
    Last edited: Feb 5, 2020
  6. haraldk

    haraldk

    Joined:
    Apr 25, 2013
    Posts:
    3
    Hi,

    I noticed today that a simple

    Code (CSharp):
    1. SceneManager.LoadScene("Empty", LoadSceneMode.Additive);
    will completely break the playbacks. I tested this in the CubeDemo and Unity 2019.3 too just to make sure.
    Is there some setting or setup I might be missing?
     
  7. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Hi,
    Sorry for not responding. I did not get any notification that you had posted.

    As you have discovered, Changing scenes for playback is not supported at the moment because each recording stores scene specific information to make it possible to replay the objects. A possible solution is to additivley load the record scene into another scene for playback but you would need to make sure that the recording source scene is active. We are currently woking on Ultimate Replay 2.0 which will remove this limitation entirely.
     
  8. DJ_Design

    DJ_Design

    Joined:
    Mar 14, 2013
    Posts:
    66
    Hey- Love the concept of this but I'm struggling to cache the replay to another player over a photon network.
    Would you be able to direct message me with some tips once you are free to do so?

    Thanks for your time!
     
  9. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Hi, Are you trying to send a full replay to another client or are you just trying to record networked objects? Are you using a replay memory target for storing the replay or a file target? A file target would be recommended for this sort of thing and then setup a tcp connection to send the file to the other client. If you are trying to sync replays per frame accross the network then we would not recommend this. Instead we would suggest that each client records their own replay and networked objects can be synchronized over the netowork as normal and then recorded like any other object.
     
    DJ_Design likes this.
  10. DJ_Design

    DJ_Design

    Joined:
    Mar 14, 2013
    Posts:
    66
    Hey thanks for the reply!
    I'm trying to send the recorded data to a player over the network, for temporary replay use.
    I realize a full replay might be too much, so I would imagine it would work where the client records, and when an event is called I send only a snippet of the replay (last 5 seconds or so) as to save data.. what do you think?
    I thought using a file transfer would be best but maybe not.
    Either way very open to any insight into which would be easier on the network.
     
  11. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    If you only want to send small snippets of the replay then a replay file will not be suitable due to the way it stores the data. You would have to send the whole file otherwise the data would be unreadable.
    You could use a memory target to record the data but then you would likley need to modify the source code to extract the data required and send it over the network. Essentially a memory target stores the following data:
    • A collection of ReplaySnapshots - Contains the state information for all replay objects at a given time represented by a time stamp value
    • An initial data buffer - Used to recreate prefab instances that were spawned or despawned during recording
    • The name of the scene where the recording was captured.
    You would need to serialize all of these and send them over the network after your predetermined amount of time. It is not too difficult because the ReplaySnapshot and ReplayInitialDataBuffer types both have serialize and deserialize methods that accept a binary writer/reader. You will need to modify the source code to allow access to these private types declared in the ReplayMemoryTarget class.

    If you take a look at the related source code you should get an idea of how things are stored and how they work. If you need any help with specifics then let me know and I will be happy to help.
     
    DJ_Design likes this.
  12. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    Hello, I am trying to make Ultimate Replay to work with my sports sim replay module. I have number of field players running around the field. They have rigged animated bipeds, and their animation changes according to parameter of speed. If speed is 0 then they are in idle animation, if it is 3 they walking and if it 8 they are running. I am attaching Replay Animator script to field player object, point it's animator to script, attaching Replay Object and Replay transform.
    When I play the game I can see, that field players are animated according to animator blend tree. But once I make a recording and try a replay I see, that speed parameter is not being recorder by Replay Animator , so each field player is stuck with single value for speed and they are stuck in single animation. Is it possible to store speed parameter with Replay Animator script? Or is there any way to store changes in speed and apply it on replay?
     
  13. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Hi,
    Animator parameters are not recorded at the moment so you would need to record them manually. You could do this by creating a class that inherits from 'ReplayAnimator' and override the 'OnReplaySerialize' and 'OnReplayDeserialize' methods (Making sure to call the base method). You can then serialize and deserialize animator parameters as required.

    Alternativley you could opt to not use the ReplayAnimator component and instead attach a ReplayTransform component to each joint in the hierarchy. This will allow you to record and replay bone animation and will likley be more accurate too.
     
  14. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    I tried this approach, but unfortunately performance dips when I put it on 11 players.
    I will try to do as you suggested and extend Replay Animator with custom parameter.
     
  15. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Are you using one ReplayObject component for the whole character hierarchy when trying this? We are not aware of any performance issues but we will look into it and see if we can do anything to improve it. Let me know if you need any help with recording extra parameters.
     
  16. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    I instantiate players from prefab and attach single ReplayObject to parent object and ReplayTransforms to every child objects (bones and joints).


    Can you elaborate on this? I am trying to do like this, but I am not sure that I do it correctly


    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class ExtendReplayAnimator : UltimateReplay.ReplayAnimator
    {
    // Start is called before the first frame update
    void Start()
    {
    }
    // Update is called once per frame
    void Update()
    {
    }
    public override void OnReplaySerialize(UltimateReplay.ReplayState state)
    {
    Debug.Log("Overriding animator serialization");
    base.OnReplaySerialize(state);
    int layerCount = (recordAllLayers == true) ? observedAnimator.layerCount : 1;
    for (int j = 0; j < layerCount; j++)
    {
    float speedParam = observedAnimator.GetFloat("Speed");
    state.Write(speedParam);
    }
    }
    public override void OnReplayDeserialize(UltimateReplay.ReplayState state)
    {
    Debug.Log("Overriding animator deserialization");
    base.OnReplayDeserialize(state);
    }
    }
     
  17. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Yes that looks OK to me so far. You just need to match the written values in the deserialize method by reading the float data and then you can apply the speed value to the animation using 'SetFloat'. Make sure that you add your deserialize code after calling the base deserialize method to avoid corruption.
     
  18. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    Ok, I think I got this. Now speed is recording with the transform. So, it looks like animator state is a series of data in strict order. First you write this sequence, and then you read it back an apply to animator. All I needed is to add to the end of this sequence my parameter of speed, and then read it also from the end.
    Working code looks like this.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ExtendReplayAnimator : UltimateReplay.ReplayAnimator
    6. {
    7.     // Start is called before the first frame update
    8.     void Start()
    9.     {
    10.  
    11.     }
    12.  
    13.     // Update is called once per frame
    14.     void Update()
    15.     {
    16.  
    17.     }
    18.  
    19.     public override void OnReplaySerialize(UltimateReplay.ReplayState state)
    20.     {
    21.         Debug.Log("Overriding animator serialization");
    22.         base.OnReplaySerialize(state);
    23.         float speedParam = observedAnimator.GetFloat("Speed");
    24.         state.Write(speedParam);
    25.        
    26.     }
    27.     public override void OnReplayDeserialize(UltimateReplay.ReplayState state)
    28.     {
    29.         Debug.Log("Overriding animator deserialization");
    30.         base.OnReplayDeserialize(state);
    31.         observedAnimator.SetFloat("Speed", state.ReadFloat());
    32.     }
    33.  
    34. }
     
    scottyboy805 likes this.
  19. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Yep you got it. The same applies if you want to record any other custom component data that is not supported by default.
     
  20. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    Have another question regarding bones tracking for biped. I have player character on scene, this is a biped with bones controller by VRIK plugin. I wrote script that assigns Replay Transform on all children of biped and I put one ReplayObject on parent object. I observer strange behaviour with this arrangement. Sometimes all bones tracks and replays fine, but sometimes not. Can VRIK interfere with UltimateReplay?
     
  21. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Hi,
    I am not familiar with VRIK plugin but here are a couple of things to check:
    1. Make sure that all ReplayTransform components in the hierarchy are set to record local position and rotation if they are not already.
    2. Make sure that any scripts or components from the VRIK plugin are not intefering with the playback of the object during a replay. Usually all non-ReplayBehaviour scripts will be disabled by Ultimate Replay prior to starting playback but maybe they are not in this case. Also check that scripts not attached to the object directly are not intefering such as manager scripts etc.
    Let me know if you are still having issues after trying these things.
     
  22. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    All ReplayTransform are showing local position and rotation.

    I can see that during replay all components are disabled except needed by UltimateReplay.
    Strange thing is that sometimes it all works as it should, replay of the biped animations is playing correctly, but sometimes not, the biped just freezes during replay.
     
  23. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Is there an animator component running during playback or any physics components that could be interfering? Apart from that I cannot think what else could be happening. If you are able to send the project to info(at)trivialinteractive.co.uk we would be happy to look into it further.
     
  24. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    The animator component is there, but it is disabled during the playback. Also, I narrowed down the bug to the fact that recording only works when I run the script that attaches ReplayTransforms and ReplayObject only first time. On second run playback don't work, but if I remove script, run the game, and then add the script again it works fine again. Like if something prevents recording of the biped on second run.
     
  25. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    That is strange. When you are adding the replay components via script, are you adding the ReplayObject component first? If not then Ultimate Replay will try to create a ReplayObject component at the same hierarchy level when adding the transform component. If the ReplayObject is created first then all child components should detect this automatically.
     
  26. kirkokuev

    kirkokuev

    Joined:
    Aug 9, 2014
    Posts:
    8
    I add components like this

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerReplayHelper : MonoBehaviour
    6. {
    7.     private GameObject biped;
    8.  
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.         biped = this.transform.gameObject;
    13.         PrepareForReplay();
    14.     }
    15.  
    16.     // Update is called once per frame
    17.     void Update()
    18.     {
    19.        
    20.     }
    21.  
    22.     public void PrepareForReplay()
    23.     {
    24.         biped.AddComponent<UltimateReplay.ReplayObject>();
    25.  
    26.         Component[] bipedChildComponents = biped.GetComponentsInChildren<Transform>();
    27.         foreach (Transform bipedChild in bipedChildComponents)
    28.         {
    29.             bipedChild.gameObject.AddComponent<UltimateReplay.ReplayTransform>();
    30.         }
    31.  
    32.     }
    33. }
    34.  
     
  27. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    655
    Yes that looks fine to me. I don’t know what else to suggest in that case. As I said, if you are able to send us the project we could take a look as I think we have covered most of the trivial possible causes.
     
unityunity