Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[Released] Ultimate Replay 2.0 - Next generation state-based replay system

Discussion in 'Assets and Asset Store' started by scottyboy805, Sep 8, 2020.

  1. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Received thanks. I will check that out as soon as I have chance.
     
    rimunasubi likes this.
  2. rimunasubi

    rimunasubi

    Joined:
    Mar 16, 2020
    Posts:
    11
    Hi.

    The sample project we sent you previously may be corrupted, so we are sending it to you again just in case.
    Sorry, please confirm.
     
    scottyboy805 likes this.
  3. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Thanks, Sent you an email with some initial findings.
     
    rimunasubi likes this.
  4. rimunasubi

    rimunasubi

    Joined:
    Mar 16, 2020
    Posts:
    11
    I just sent you a reply.
    I am sorry, but there was a mistake in the reproduction procedure, may I ask you to check again?
     
    scottyboy805 likes this.
  5. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Sure, sent you another email
     
  6. ColinBroderick

    ColinBroderick

    Joined:
    Mar 1, 2022
    Posts:
    9
    Do you have any proper code documentation? Proper API reference? The manual is great but appears incomplete and surrounds everything with fluff with makes it difficult to find what I need.

    In particular, at the moment, I want to know if there is a method to check whether the seek bar is currently being dragged, so that my own UI controls can ignore the input.
     
  7. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi, We include a .chm scripting reference which documents main parts of the api if that will be useful to you. You can find it included with the asset at 'Assets/Ultmate Replay 2.0/ScriptingReference.chm'. Unfortunately that is all we have for api documentation at the moment other than xml comments in the code itself (Your IDE should display those if you are using the full version of Ultimate Replay).

    Other than that I will be happy to answer any questions you might have.

    For your seek bar question: I assume you are referring to the seek bar included with the default ReplayControls script? If so, that value is driven by the normalized playback time of the replay. You can use `ReplayManager.GetPlaybackTimeNormalized(...)` to fetch that value but you will need to handle the change checks yourself. Other than that you can modify the source code for the ReplayControls script where it draws the GUI Slider so that you can check via the UI feedback whether the user has dragged the slider.

    Hope that helps.
     
  8. julianr

    julianr

    Joined:
    Jun 5, 2014
    Posts:
    1,212
    Hi, just a quick question regarding audio. On the demo, I noticed that playing it back in reverse on the timeline, it played the audio forwards (normal), shouldn't it make the audio also play back in reverse? To be more specific... the word "hello" spoken normally on record, and on playback in reverse it would sound like "olleh", or an explosion on normal would be loud at first with a tail off, where as in reverse the tail off first then the large explosion sound. It should be a fairly easy fix to play audio in reverse, if playback is in reverse. I just don't know where to find it.

    Also can you go larger than 65565 objects being tracked? Apart from the Audio issue.. it's pretty solid so far. I'm just about to integrate it into a save/load menu system for replay so if you can fix the audio issue, as it may take me longer to fix than you finding and fixing the issue. I'll then be able to showcase what I've created. Thanks in advance!
     
    Last edited: Sep 22, 2022
  9. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi,
    Thanks for reporting. I wasn't aware of the reverse audio issue, although I thought it was currently setup to not support reverse audio, but I could be wrong on that. We have had some issues previously getting audio to record and replay in an acceptable way, but I will look into that to see if it can be solved.

    There are provisions in place to support more than 65565 objects such as 32-bit replay identities, however it is not a limit that we can even come close too as you will start seeing performance dropping off after 1000 objects/components or so on some lower end devices due to the amount of serialization that will be required, and even more powerful hardware will struggle to get more than a few thousand objects for the same serialization reasons. For that reason it make sense to store related data as 16-bit to reduce storage requirements, as it can add up dramatically over a few minutes of replay. Hope that helps.
     
    julianr likes this.
  10. julianr

    julianr

    Joined:
    Jun 5, 2014
    Posts:
    1,212
    Thanks for your reply, appreciate the quick response! Under normal circumstances it probably wouldn't be an issue if you are playing a recorded session forwards. When you rewind time it will become an issue. In my game I have repair bots, so rewinding time and playing back audio in reverse would make this functionality more realistic. If it can just play audio back in reverse when the playback is in reverse that would be awesome! It would also be the same length and at the same point of time I believe, so I doubt an offset would be needed.

    Thanks on the objects info, most helpful.
     
    Last edited: Sep 23, 2022
  11. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi again,
    I made some changes to the ReplayAudio component so that it can support playing sounds in reverse. Seems to be working well on my end so I have sent you a patch update via discord for you to try out, and it will also be included as part of the next udpate.

    Let me know if you have any issues or if there is anything else.
     
    julianr likes this.
  12. julianr

    julianr

    Joined:
    Jun 5, 2014
    Posts:
    1,212
    Thanks Scott. Appreciate the quick turn around on this patch - great support!
     
  13. DanielKorsahLuminous

    DanielKorsahLuminous

    Joined:
    Jan 26, 2022
    Posts:
    4
    Hello Scott,

    I'm having a couple of issues using Ultimate Replay 2. Specifically, performance tanks when replaying in reverse (either manually via scripting or using the built-in replay controls), and I can't seem to get Replay Animators to work at runtime. Can you help me out? Perhaps let me know what extra information you need. I have Replay Animators on the animator gameobjects and the observed animator is set.

    Also is it possible to exempt some components from being disabled during playback? I'm sure I read somewhere in the docs a few months ago that you could but I can't remember the wording to find it again.

    Thanks in advance for any light you can shed,
    Daniel
     
  14. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi Daniel,
    Sorry for the delay.

    For the performance issue: Which storage target are you using in this case? I would assume file storage as it has much greater performance overhead? Are you able to quanitfy the amount the performance drops if possible? For example: how many ms on avearge does a frame take when replaying in forward direction compared to reverse?
    It is to be expected that reverse playback will be somewhat slower due to the way the replay data is stored. It means that many more expensive seek operations are required for example to read the same data in reverse, and there are also a few other factors that can contribute to slower overall performance in reverse, although it should not be unwatchable.

    Also are you able estimate roughly how many replay components you might have in the scene at this time, as that can also greatly affect performance.

    You can indeed prevent certain components from being disabled while in playback mode. You can do that via the settings by going to 'Tools -> Ultimate Replay 2.0 -> Settings' and selection the State preperation tab. From there, you can add components to the ignore list so that the replay system will not affect them when switching into playback mode. let me know if you have any issues setting that up.
     
  15. DanielKorsahLuminous

    DanielKorsahLuminous

    Joined:
    Jan 26, 2022
    Posts:
    4
    Sorry for the delay, Scott. I got shifted to another project for a bit.

    To answer some questions:
    - The ReplayTarget is the ReplayFileTarget; the performance in reverse is worse when the recording is longer.
    - There were 17 ReplayTransforms and associated ReplayObject in the scene and 4 ReplayAnimations. This is effectively exploratory dev though so it will likely need to be a decent bit more than that in other scenarios.
    - If it's a few seconds long reverse is a slideshow, if it's any more than that it's effectively a crash.

    Do you have any idea why I am unable to replay animations, particle effects, etc. I'm using
    Code (CSharp):
    1. ReplayScene = new ReplayScene(FindObjectsOfType<ReplayObject>());
    to set up my replay scenes. With a few replay prefabs for dynamically spawned objects. Seems only Transforms record. I feel like I must be missing something.

    Oh and thanks for the ignore list reminder that's a big help.

    Thanks,
    Daniel
     
  16. DanielKorsahLuminous

    DanielKorsahLuminous

    Joined:
    Jan 26, 2022
    Posts:
    4
    Hi Scott,

    Sorry for not replying immediately but I would really appreciate you weighing in on my question. The reverse playback issue is not a priority since we're not using rewind as a feature now but I do need a hand with why I can't add non transform replay objects to the replay scene.

    Thanks,
    Dan
     
  17. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi again Dan,
    Sorry for the delay. I was away for a few days and am only just catching up on the backlog of support requests and updates.
    Other replay components should work just fine, but there are a few things you can check that could cause a particular replay object to not record as expected:
    • Make sure there is a ReplayObject component attached at the same level as your replay component (ReplayAnimator for example), or attached to a parent game object.
    • Once you find the managing ReplayObject component, check the 'Observed Components' list and make sure that your replay component is listed there as expected, otherwise the component will not record. In the case that your component is not listed, it can usually be solved by removing and re-adding the ReplayObject component manually to force an update.
    • Check that both the ReplayObject and replay component has valid replay identities assigned. It will usually be a 5 digit number and should not be zero.
    • If you are creating the replay scene manually using one of the 'FindObjects...' method, then make sure the game object hierarchy and replay component are enabled or they may not be found. In that case, you can perhaps check for disabled components too using one of the overloads, or add to the replay scene manually using 'AddReplayObject' method.
    • While in playback mode, check that no other scripts or components could be affecting the Animator for example. Check that any scripts that update animator properties or states do not run in playback mode as they could override the state set by the replay system giving the illusion of nothing replaying.
    If none of those points seem to be causing an issue, then let me know and I can help check for other potential reasons why your components would not replay.
     
  18. DanielKorsahLuminous

    DanielKorsahLuminous

    Joined:
    Jan 26, 2022
    Posts:
    4
    Thanks, Scott. Appreciate your time. I'll tackle this checklist tomorrow and get back to you.
     
    scottyboy805 likes this.
  19. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Ultimate Replay 2.2.2 has been released and includes the following bug fixes and changes:
    • Fix an issue where user ComponentPreparer types can have a lower priority by default that built in types causing them not to be used.
    • Fix an issue where ReplayObject.runtimeComponents list can contain null elements and lead to problems when running the game.
    • Make 'ReplayObject.isObservedComponentsExpanded' public to support asmdefs.
    • Make 'ReplayBehaviour.noManagingObject' public to support asmdefs.
    • Fixed an issue where component preparers defined outside of the Ultimate Replay assembly would not be found.
    • Fix an issue where auto changes made by replay validator would not be saved in some cases causing invalid replay objects or components in the scene.
    • Add support for reverse playback in the ReplayAudio component.
    • Fix compilation error when selecting WebGL as a built target due to missing streaming methods.
    • Minor bug fixes.
     
  20. Trigve

    Trigve

    Joined:
    Mar 17, 2013
    Posts:
    139
    Hi,
    I've question regarding the workflow for some specific use-case. I've read the whole manual and understand the concepts and API.

    I would like to use your plugin for "simulation" purposes. That is, you will plan the action for the objects, than hit the simulate button and watch the replay after the simulation ends. So the replay would be the "main concept" in the game.

    For example: In a scene is cube with planes (driven by physics). Now I order to move the cube and want to run simulation for 10 seconds (simulation isn't shown, it's done in background). I would run the physics (etc.) code in the background and record the "actions" as a replay. After the simulation, one could move back/forward replay and observe it from different angles etc.. Now the one problem I have is that during simulation, I want to show some UI which will show "simulating ..." (or some progress, etc.), which would be not affected by the replay system. What I are my options? The one option is to disable the "UI" objects to participate in the replay recording. Are there some other options like using 1 scene for "simulation" and replay recording and another one as "UI"?

    Thanks
     
  21. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi,
    Thanks for the interest in our asset.
    For the UI workflow, it depends on whether any of the UI will need to be recorded/Replayed, or whether you will just show that via a script that updates when playback beging or ends for example. If the UI does not need to be recorded and will not have any replay components attached, the the replay system will not interact with the UI objects in any way, so there should be no problem at all. If you do need to have replay components attached to the UI, then I guess your issue wil be that the replay system will disable UI components by default (I know it is not ideal, but the default replay preparer disables all 'Behaviour' components, which UI components come under as a consequence). One way to get around that issue would be to ignore certain UI components via the 'Settings / State Preparation' window which can solve that issue.
    Another possible alternative that may be suitable to you since you are talking about replaying dfferent scenes is making use of ReplayScenes. A replay scene is just a collection of replay objects that you would like to be included in a particular replay operation such as recording or playback. In this case you could indeed separate your objects into different Unity scenes, and then use the SceneManager api to change the active scene when you start recording or replaying. The replay system will only find replay objecs in the current active Unity scene by default, so that could work in your favor in this instance. Alternativley if you need even finer control of which replay objects are recorded or replayed, then you can construct a ReplayScene manually using the constructor and 'AddReplayObject' methods, and then simply pass that replay scene when calling 'BeginRecording' or 'BeginPlayback'.
    So overall there are quite a few options for you if I have understood correctly whet you need to acheive. You can have as much control over which objects are recorded and replayed at anytime as you need.

    I hope that helps you. Let me know if you have any more questions, would like some examples/expansin on any of the above points or if there is anything else.
     
    Trigve likes this.
  22. Trigve

    Trigve

    Joined:
    Mar 17, 2013
    Posts:
    139
    Thank you for your detailed reply @scottyboy805 ,
    everything is clear.
     
    scottyboy805 likes this.
  23. Trigve

    Trigve

    Joined:
    Mar 17, 2013
    Posts:
    139
    Just one question, thought.
    Does Ultimate Replay support IL2CPP? Or are there some restrictions when using IL2CPP?

    Thanks
     
  24. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    There should be no problem at all with IL2CPP, although I believe it is not something we have tested.
    If you do run into any issues then just let me know and I am sure they can be easily resolved if there are any at all, altough like I say there should be no issues in theory.
     
    Trigve likes this.
  25. harshroshan

    harshroshan

    Joined:
    Dec 12, 2022
    Posts:
    5
    I am trying to replay prefabs getting instantiated at an interval of 5 secs but it's not able to record the objects getting instantiated in the middle of the recording. I have followed all instructions provided in the user guide.

    void Start()
    {
    StartCoroutine(SpawnBall());
    }
    // Update is called once per frame
    void Update()
    {

    }
    IEnumerator SpawnBall()
    {
    while(i < _spawnCount)
    {
    posToSpawn = new Vector3(Random.Range(-2f, 2f), Random.Range(1f, 3f), 0);
    if (i > 0)
    {
    _newCapsule = Instantiate(_capsulePrefab, posToSpawn, Quaternion.identity);
    _newCapsule.name = _capsulePrefab.name;

    _newCylinder = Instantiate(_cylinderPrefab, posToSpawn, Quaternion.identity);
    _newCylinder.name = _cylinderPrefab.name;
    }

    i++;
    yield return new WaitForSeconds(_waitForSeconds);
    }
     
  26. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi,
    The code looks fine and should work without a problem. The only thing I can see that is missing is adding the instantiated object to the replay scene so that the replay system becomes aware and can start recording the new object. You can do that using a ReplayScene reference directly if you have it using 'AddReplayObject' method, or you could use one of the helper methods which is usually easier if you did not pass a custom ReplayScene object to 'BeginRecording':

    Code (CSharp):
    1. ReplayManager.AddReplayObjectToRecordScenes(_newCapsule.GetComponent<ReplayObject>());
    2. ReplayManager.AddReplayObjectToRecordScenes(_newCylinder.GetComponent<ReplayObject>());
    I checked the user guide and it looks like it has not been udpated to show this extra step, so I am sorry about that. I will be sure to add that additional information to the user guide for the next update so that there is no confusion in future.

    I hope that helps you. Let me know if you are still having any trouble, or if there is anything else.
     
  27. harshroshan

    harshroshan

    Joined:
    Dec 12, 2022
    Posts:
    5
    It works great!! Thanks for the replay.
     
    scottyboy805 likes this.
  28. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    No problem. Happy to hear that it is working out for you now :).
    Let me know if there is anything else.
     
  29. harshroshan

    harshroshan

    Joined:
    Dec 12, 2022
    Posts:
    5
    Hi, I have another question. I am storing the recorded data in a file. I have a Dispose() at the end of the game but when I switch from recording--> playback ---> recording in the middle of the game I get the error that the file is in use. How should I handle it?

    Code (CSharp):
    1.  
    2. private static ReplayFileTarget recordStorage = ReplayFileTarget.CreateReplayFile("ReplayFiles/test.replay", false);
    3.         private static ReplayFileTarget replayStorage = ReplayFileTarget.ReadReplayFile("ReplayFiles/test.replay");
    4.  
    5.  
    6. public static ReplayHandle BeginRecording(ReplayStorageTarget recordTarget = null, ReplayScene recordScene = null, bool cleanRecording = true, bool allowEmptyScene = false, ReplayRecordOptions recordOptions = null)
    7.         {
    8.             recordTarget = recordStorage;
    9.             // Check for default target
    10.             if (recordTarget == null)
    11.                 recordTarget = DefaultStorageTarget;
    12.  
    13.  
    14. private static ReplayHandle BeginPlayback(ReplayStorageTarget replaySource, ReplayScene playbackScene, ReplayPlaybackOptions playbackOptions, bool allowEmptyScene, bool restoreReplayScene, bool fixedFrame)
    15.         {
    16.             replaySource = replayStorage;
    17.             // Check for default storage device required
    18.             if (replaySource == null)
    19.                 replaySource = DefaultStorageTarget;
    20.  
     
  30. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    The problem is that the 'CreateReplayFile' call will lock the output file until you call 'Dispose', and no other IO call will be able to access it during that time.
    To solve the problem you can still use static variables for the replay and record storage, but you should make sure that only one of them is open at any time (Atleast when using the same path). To do that you could modify your code slightly so that the file is only written when recording, and only read when replaying like so (Not tested but can be used as an example):


    Code (CSharp):
    1. private static ReplayFileTarget recordStorage = null;
    2. private static ReplayFileTarget replayStorage = null;
    3.  
    4. public static ReplayHandle BeginRecording(ReplayStorageTarget recordTarget = null, ReplayScene recordScene = null, bool cleanRecording = true, bool allowEmptyScene = false, ReplayRecordOptions recordOptions = null)
    5. {  
    6.     if(replayStorage != null)
    7.     {
    8.         // Close replay storage
    9.         replayStorage.Dispose();
    10.         replayStorage = null;
    11.     }
    12.    
    13.     // Create the file for saving
    14.     recordStorage = ReplayFileTarget.CreateReplayFile("ReplayFiles/test.replay", false);
    15.    
    16.     recordTarget = recordStorage;
    17.     // Check for default target
    18.     if (recordTarget == null)
    19.         recordTarget = DefaultStorageTarget;
    20.    
    21.     // ... Rest of code...
    22. }
    23.  
    24. private static ReplayHandle BeginPlayback(ReplayStorageTarget replaySource, ReplayScene playbackScene, ReplayPlaybackOptions playbackOptions, bool allowEmptyScene, bool restoreReplayScene, bool fixedFrame)
    25. {
    26.     if(recordStorage != null)
    27.     {  
    28.         // Close record storage
    29.         recordStorage.Dispose();
    30.         recordStorage = null;
    31.     }
    32.    
    33.     // Load the file for replay
    34.     replayStorage = ReplayFileTarget.ReadReplayFile("ReplayFiles/test.replay");
    35.    
    36.     replaySource = replayStorage;
    37.     // Check for default storage device required
    38.     if (replaySource == null)
    39.         replaySource = DefaultStorageTarget;
    40.    
    41.     // ... Rest of code...
    42. }
    So in summary the best solution is to write code that only allows one IO operation to access the file at any time, like above or similar.

    Hope that helps.
     
  31. harshroshan

    harshroshan

    Joined:
    Dec 12, 2022
    Posts:
    5
    Thanks for your help. I will try to implement it tomorrow.

    Also, I see another problem. I have 2 objects instantiated in the game, one at the beginning of the game. Another in the middle of the game. Once I switch back to a recording or live after playback the object instantiated the beginning of the game freezes at one spot. I am not sure what is wrong. This happens even when it uses DefaultStorageTraget and not the file. Can you please help with this?

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UltimateReplay;
    6. using UltimateReplay.Storage;
    7. using UltimateReplay.Util;
    8. public class SpawnManager : MonoBehaviour
    9. {
    10.     /*[SerializeField]
    11.     private GameObject _objectPrefab;*/
    12.     [SerializeField]
    13.     private GameObject _capsulePrefab;
    14.     [SerializeField]
    15.     private GameObject _cylinderPrefab;
    16.     [SerializeField]
    17.     private int _spawnCount = 1;
    18.     [SerializeField]
    19.     private GameObject _ballContainer;
    20.     private int i = 0;
    21.     private Vector3 posToSpawn;
    22.     private GameObject _newCapsule;
    23.     private GameObject _newCylinder;
    24.  
    25.     [SerializeField]
    26.     private float _waitForSeconds = 5.0f;
    27.     //private ReplayStorageTarget _target = null;
    28.     // Start is called before the first frame update
    29.     void Start()
    30.     {
    31.         StartCoroutine(SpawnBall());
    32.     }
    33.     // Update is called once per frame
    34.     void Update()
    35.     {
    36.      
    37.     }
    38.     IEnumerator SpawnBall()
    39.     {
    40.         while(i < _spawnCount)
    41.         {
    42.             posToSpawn = new Vector3(Random.Range(-2f, 2f), Random.Range(1f, 3f), 0);
    43.             if (i >= 0)
    44.             {
    45.                 _newCapsule = Instantiate(_capsulePrefab, posToSpawn, Quaternion.identity);
    46.                 _newCapsule.name = _capsulePrefab.name;
    47.                 _newCapsule.transform.parent = _ballContainer.transform;
    48.                 ReplayManager.AddReplayObjectToRecordScenes(_newCapsule.GetComponent<ReplayObject>());
    49.                
    50.                 _newCylinder = Instantiate(_cylinderPrefab, posToSpawn, Quaternion.identity);
    51.                 _newCylinder.name = _cylinderPrefab.name;
    52.                 _newCylinder.transform.parent = _ballContainer.transform;
    53.                 ReplayManager.AddReplayObjectToRecordScenes(_newCylinder.GetComponent<ReplayObject>());
    54.                
    55.             }
    56.             i++;
    57.             yield return new WaitForSeconds(_waitForSeconds);
    58.         }
    59.     }
    60. }
    61.  
    62.  
     
  32. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi again,
    I am not sure what the issue could be in that case.
    When you say that the object freezes, do you mean that it snaps to a different position than expected? Can you move the object at all or by freeze do you mean that the object becomes not-movable, like something is always updating the position? When a replay ends, the replay system will try an restore all objects to their initial positions before the replay began, so that could be the source of the issue in this case. That behaviour can be disabled if required, although it certainly should not be freezing objects like you mention.
     
  33. harshroshan

    harshroshan

    Joined:
    Dec 12, 2022
    Posts:
    5
    Hi,
    The requirement is to make the objects float in the air in a given direction. The objects get instantiated at different time intervals. The first one gets instantiated immediately when the game begins while the second one after 5 secs and it goes on. When I do a playback everything goes well but when I switch back to recording the one instantiated at the beginning of the game goes to the position where it got instantiated and freezes there while the other object works fine.
     
  34. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    It is difficult to say what the issue might be based on the description. Are you able to try instantiating the object just after you call 'StartRecording', or is that not possible in this scenario? The only thing that comes to my mind based on your description is a possible issue with the replay identity changing for that object, although it also seems unlikley though.
    Are you able to send over a repro project at all, or provide some steps to replicate the issue so I can test it out on my end. No worries if you are not able to but feel free to share a repro project either on discord or via email and I will be happy to take a look and see what the issue could possible be: info(at)trivialinteractive.co.uk
     
  35. shejianshangdezhongguo

    shejianshangdezhongguo

    Joined:
    Feb 18, 2019
    Posts:
    10
    Does it support VR,I use HTC view Pro
     
  36. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi, Sorry for the delay.
    We don't have any devices to test on to confirm 100%, but I am pretty sure some other users have had success with on Android based VR devices. I don't forsee that there should be any issues since the code base is pure C# source code with no native plugins or anything like that.
    Hope that helps you somewhat but I cannot say for certain unfortunately.
    Let me know if there is anything else.
     
  37. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Ultimate Replay 2.2.3 has been released on the asset store. This version includes the following bug fixes:
    • Fix bug in replay transform when serializing individual rotation components.
    • Fix a bug where single axis rotation would not be replayed correctly in some cases.
    • Fix a buffer overflow issue when using a large number of replay prefabs.
    • Fix an issue where ReplayState could not store enough data in certain conditions.
    • Minor bug fixes.
     
    Trigve and shyamarama like this.
  38. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Ultimate Replay 2.2.4 has been released on the asset store. This version includes the following fixes:
    • Fix large allocations coming from ReplayAnimator in some cases where many parameters are used.
    • Large performance improvements to ReplayAnimator component.
    • Fix an issue where an Animator could generate a warning while replaying due to parameters modified by animation curves.
    • Minor bug fixes.
     
  39. Sibi

    Sibi

    Joined:
    Jan 1, 2016
    Posts:
    2
    I would like to have a character perform another action while watching a recording. Is it possible to play my recording using a mini-player within the scene?
    (It would be better if I could move the camera position in the mini-player as well as in the normal case.
     
  40. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi Sibi,
    Yes this will be possible with Ultimate Replay 2.0. You can play the recording in the scene and overlay a player UI if required with features like player/pause and seeking. There is already a ReplayControls script included which will do most of that ust for testing purposes, so you could either expand that or create a new UI using the same apparoach.
    Ultimate Replay will create a free fly cam by default which you can move around the scene while the replay is playing, so hopefully that can suit your needed. If not, then it is certainly possible to setup your own camera to view the replay and even switch cameras if needed.

    Hope that helps you. Let me know if you have any more questions or if there is anything else.
     
  41. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
  42. Sibi

    Sibi

    Joined:
    Jan 1, 2016
    Posts:
    2
    Thank you for your thoughtful response to my previous question. I have another question, I would like to create my own UI with Canvas and buttons to switch between Live, Rec, and Play. I have tried to create a rough one but it seems to be wrong. What would be the appropriate way to do this? Sorry for my lack of study.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using TMPro;
    4.  
    5. namespace UltimateReplay
    6. {
    7.  
    8.     public class UITest : MonoBehaviour
    9.     {
    10.         [SerializeField] private Button button1 = default;
    11.         [SerializeField] private Button button2 = default;
    12.         [SerializeField] private Button button3 = default;
    13.  
    14.         [SerializeField] private TextMeshProUGUI debugText = default;
    15.  
    16.         void Start()
    17.         {
    18.             button1.onClick.AddListener(() => IsReplayKeyPressed(KeyCode.P));//play
    19.             button2.onClick.AddListener(() => IsReplayKeyPressed(KeyCode.R));//rec
    20.             button3.onClick.AddListener(() => IsReplayKeyPressed(KeyCode.L));//live
    21.         }
    22.  
    23.         private bool IsReplayKeyPressed(KeyCode key)
    24.         {
    25.             return Input.GetKey(key);
    26.         }
    27.     }
    28. }
    Or is there any way to make the original UI operable when running in Oculus Quest?
    I cannot see the UI when running in Oculus Quest.
     
  43. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hi again, It can be possible to replicate the functionality with UGUI instead of leagcy with a bit of work. I don't know too much about VR but I guess using legacy GUI there is not supported.
    Are you using the full version of Ultimate Replay or the trail version? If you have the full version then you can take a look at the source code for `ReplayControls.cs` as it contains all of the needed functionality, and it is then just a case of replacing legacy UI with UGUI.
    The code above doesn't seem to make too much sense, but something like this should be more suitable once the methods have been filled out. I don't have too much time right now to create a full example, but if you are still having trouble let me know and I can put together a more complete example when I have chance.

    Code (CSharp):
    1. class Example : MonoBehaviour
    2. {
    3.     [SerializeField] private Button play;
    4.     [SerializeField] private Button record;
    5.  
    6.     void Start()
    7.     {
    8.         play.onClick.AddListener(OnReplayClicked);
    9.         record.onClick.AddListener(OnRecordClicked);
    10.     }
    11.  
    12.     void OnReplayClicked()
    13.     {
    14.         // Todo - start replay using ReplayManager API
    15.     }
    16.  
    17.     void OnRecordClicked()
    18.     {
    19.         // Todo - start recording using ReplayManager API
    20.     }
    21. }
     
  44. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Ultimate Replay 3.0 is now in open beta! :D

    Anyone is welcome to try it out and the latest version can be found over on github. Currently it is considered as early access since features, bugs and documentation are still being activley worked on, so it is not recommended for use in production currently. More info over on the WIP thread.

    Ultimate Replay 2.0 is still the recommended solution and will still receive feature and bug fix updates.
     
    petey likes this.
  45. petey

    petey

    Joined:
    May 20, 2009
    Posts:
    1,817
    Hey this looks really cool, I'm gonna test out some stuff soon :)
    Just wondering, could this plugin fit in any way with multiplayer or network stuff?
    It just seems they both have similar problems to solve in terms of tracking and game objects and parameters.

    Thanks!
    Pete
     
  46. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hey, thanks for the interest in our asset.
    Yes we have had users in the past implement Ultimate Replay 2.0 into a multiplayer game. It is not too complex but essentially you end up recording only the local versions of remote players for example, so there is no networking involved directly with the replay system. Instead your networking solution such as Photon will run to update the players as normal and then the replay system will record the local players after they have been udpated, and that results in a pretty convincing (although not perfect) replay suitable for most cases such as killcams or action replays.

    Hope that helps. Let me know if you have any more questions or if there is anything else.
     
    petey likes this.
  47. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,677
    Quite neat asset! After figuring out some things it does what it should!

    Have two questions though:

    - Have you foreseen that people may disable full scene reload on enter-playmode? Think many devs do that since it speeds up iteration time greatly in large scenes. Unfortunately that means static fields are not reset on start and that already breaks the demos of Ultimate Replay 2.
    As a rather dirty fix I queried all static fields, made them accesible and not read-only so that a custom script guaranteed to run Awake first, resets them all.
    A built in solution for this problem would be greatly apreciated though.

    - Does the system write values even when they don't change? So an object standing still will still keep writing data all the time?
     
    scottyboy805 likes this.
  48. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    Hey, Thanks, glad you like the asset :).
    1. Yes this is not something that was considered and in fact the asset was originally created before it was a feature in Unity, so I expect there would be some issues which it sounds like there might be. It may be too big of a task to solve currently in a nice way (I would have to check to see what issues there are), but Ultimate Replay 3.0 is nearing release and is currently in open beta, I think we should be able to add support in that version without too much trouble. More info on that here if you are interested.
    2. That one is a bit of yes and no. If a replay object has not moved since the last capture, the replay system will still go through the process of querying the componenent, serializing the data, calling replay events etc so there is still some overhead. However there is a stage just after that process where the replay system will evaluate the serialized data by hash to see if it has changed, and if not, then it uses something we call snapshot segment compression where it stores an index to a previous snapshot rather than actual data, and this does still record a small amount of data but it is much much less than storing all the data about the object. On top of that we have chunk compression when streaming to file which works on larger blocks or replay data to get the storage size as small as possible. Also worth noting that the snapshot segment compression only works for a small series of grouped snapshots (30 by default to avoid decompression performance issues) and 1/30 times the replay system will need to store the full replay object data even if the object did not move for a long time, so you will still see small amounts of data being recorded periodically.
      In Ultimate Replay 3.0 we have improved both of these algorithms for better runtime performance and storage size so that may be worth checking out if you need to store a lot of data for example.
    Hope that helps you. Let me know if you have any more questions or if there is anything else.
     
    DragonCoder likes this.
  49. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,677
    I see, thank you for the clarifications! Since I am mainly assessing whether this is suited for the usecase, wish I had noticed that there's a V3 coming out soon.
    Sounds promising in every case!

    One more thing that required a dirty fix in my usecase:
    A white-list for objects and behaviors that shall remain active when replaying. I have a fairly complex character where many things work passively and thus shall remain active when replaying. Similar with the camera object (albeit that technically would be avoidable if I were to redesign the architecture).
    Classes are not enough and it feels very inflexible to have those globally in the settings. Not to mention that the scroll menu in the settings for classes is insanely large in a large project and you cannot even hold the down-arrow button to scroll :D
    Am assuming the official solution would be to write a custom "BehaviorPreparator" for every class? That is a lot of text overhead.

    What I'd propose is giving the ReplayObject a [SerializedField] list of Behaviors that shall remain active during a playback. Plus an "inverse" option where it acts like a blacklist.
    What I have done for the prototype now is using a singleton with a global list of instances that shall remain active plus an empty Interface to give my custom MonoBehaviors that are then excepted from deactivation.

    Finally since that is something I had started with when attempting to do all this from scratch: Have you thought of smarter interpolation of Transform positions than linear? For example Catmull-rom should be well applicable.
    It might give an additional edge of smoothness (important in my case as the replays shall be full on videos (recorded graphically). Only requirement for that would be the possibility to look one timestep ahead (and in the past but that could easily be cached locally) since it needs 4 data points.


    However getting such a thing quite perfectly running within 2 days inside a complex project speaks for your asset. It saves a lot of time.
    For the very moment I gotta focus on a different feature but I'll likely return to try out Ultimate Replay 3.
     
    Last edited: Jul 23, 2023
    scottyboy805 likes this.
  50. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,192
    No problem, yes we are trying to get the word out about Ultimate Replay 3.0, but it seems not too many users check the WIP forums :(

    As you have discovered, there is no easy way to prevent a large number of components/scripts from being disabled during playback, since that is the default behaviour. In such a scenario when still using the default replay preparer, we would recommend that you derive from ReplayBehaviour where possible as it will allow the script to remain enabled during playback and also provide useful properties such as `IsRecording` and `IsReplaying`, although this may not always be possible or desirable for every script.
    The alternative would be to create a custom replay preparer but you would only need to do that once and not for every different type of script (One replay preparer runs for every ReplayObject/Associated Component in the ReplayScene). Your custom preparer could include some collection of allowed scripts and it can simply skip over those types when preparing the ReplayObject to keep them active during playback.

    I think there is certainly room for improvement to the state preparation though to improve usability in larger projects. Your proposed ideas sounds like it could work well for the intended purpose, the only slight doubt I would have is that replay objects should not really have any idea about state preparation as it is a higher level (and optional) construct, and those particular collections would only apply really to the default preparerer in most cases, not user implemented preparers.
    Maybe the collection could be relocated to a more suited location and I can check that, but another option that we considered previously (Specifically for scripting) was an attribute based approach where you can simply add a `[ReplayPreparerIgnore]` attribute for example and the default preparer will skip the script leaving it enabled during playback. I will check some of these options in any case to see which could be more suitable and user friendly as I agree the currently workflow can be a pain for anything more than a few scripts.

    For interpolation we have not really tested anything other than linear interpolation, mainly because I think it would not give the expected results due to how the replay squencer works. The replay system does not perform smoothing like you might find when moving an object from one position to another based on delta time. Instead it simply interpolates between 2 `snapshots` based on the `t` value representing the delta between frames (Calculated by the sequencer but we recently discovered there can be some very minor issues with this calculation):
    There are some minor flaws in the v2.0 implementation which can lead to slightly imperfect playback in some cases which may be what you are seeing? The playback sequencer was completley redesigned in version 3.0 to eliminate these issues so you might indeed see smoother playback in version 3.0 if you tested that version. I can certanly test some other interpolation options, but like I say I don't think they will give the expected `smoother` behaviour due to the way the replay system works, but no harm in trying although I think accessing 4 data points might be a bit tricky with the current implementation.

    Glad you were able to get your complex project up and running in just 2 days :). Ease of use is high on our priority list so it is nice to hear that you could achieve that in a short time for a larger more complex project. Hopefully you will find v3.0 even easier to use as the API has been changed to be as simple as possible ;).

    Thanks for all the feedback and let me know if you have any more points you think could be improved on, even very minor ones.
     
    DragonCoder likes this.