Search Unity

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

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

  1. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    Hey Scotty, what would you think of not auto-adding a Replay Object when adding a Replay Transform component to a thing? If I have a character, for example, and I'm running through the bones, I add Replay Transforms to each bone and then have a Replay Object somewhere above the skeleton in the hierarchy so that all of those Replay Transforms can be collected into a single Replay Object.

    The way this works currently is that I need to add the Replay Object _after_ I am done adding Replay Transforms. This is because of a related issue where a Replay Object will not detect child Replay Transforms if they are created after it is made. I haven't thoroughly tested if they get detected on Scene Reload or something, but my work pattern is to add the Replay Object after and blame myself if I forget.

    So the auto-adding of Replay Object messes up the parent Replay Object's detection of child Replay Transforms, so I end up having to clean them up. Make sense?
     
  2. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi again,
    The intended behaviour for this kind of setup is that you add the ReplayObject first and then add any replay components to bones after this. Attaching replay components to child objects should cause the root ReplayObject component to be refreshed so that it detects the newly added components. This appears to be working correctly for us after some quick testing but you say that the process causes the replay components to not be registered with the root ReplayObject? Would you be able to provide steps to reproduce this behaviour because that is not intended and sounds like a bug. From our testing, adding replay components under the hierarchy of a ReplayObject causes everything to be linked up correctly. Ie. The ReplayObject is refreshed when replay components are added and the 'Replay Components' collection contains all expected replay components.

    We would prefer not to remove the auto-add feature for the ReplayObject component because it makes setup for almost all cases a one step process.
     
  3. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    Ok next time I am in there I'll see if it's auto-detecting child Replay Transforms now.
     
  4. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Ok Thanks.
    We would be interested to hear if the auto-detecting is not working in some cases so we can resolve it. From out testing though, it appears to be working as intended.
     
  5. tmongy

    tmongy

    Joined:
    May 9, 2014
    Posts:
    5
    Hi,

    I'm having trouble instantiating replay prefabs. I've gone through all the steps in the manual, but it seems that when the prefabs are instantiated, there can only be one prefab at a time. This doesn't work because the prefabs are bullets and there can be many in the scene at once, however it seems that they are all being recorded as the same replayObject ID. Does the system not support instantiating multiple instances of the same prefab and tracking them?

    I even tried the CubeTest Demo included in the asset, and it also is just recording one cube when I click the playback button.

    Thanks
     
    Last edited: Oct 31, 2020
  6. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Are you using the latest version of the asset (2.0.4) released about a week ago? This version should fix all replay identity issues that may have been present in previous versions. The replay system should auto-generate a new replay identity for objects created when calling 'Instantiate' so it is certainly possible to create any number of recorded prefab instances.

    The CubeTest demo scene appears to be working correctly on my end using 2.0.4. All 300 cubes are spawned and replayed correctly as expected.Could you let me know which Unity version you are using and I can do some more testing to see if they may be an issue with different versions.
     
  7. tmongy

    tmongy

    Joined:
    May 9, 2014
    Posts:
    5
    Thanks for the reply. Yes, I'm using the latest version 2.0.4 (Trial). I'm on Unity 2018.4.22f1.

    I've also just tested the Cube Test demo scene in an empty 2019.2.19f1 project and the same issue exists where only one cube is recorded. I'm targeting iOS platform on both tests if that makes any difference.
     
    Last edited: Oct 31, 2020
  8. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    I have looked into this a bit further and have found an issue when the package has been imported. It looks like replay components attached to prefabs get reset or modified when the package is imported from the asset store and the replay identity cannot be updated after this for some reason. We will have to look into this further to find out what might be happening but there appears to be a quick fix solution in the meantime:

    The CubeDemo scene issue can be fixed by following these steps:
    1. Select the cube prefab asset located at 'Assets/Ultimate Replay 2.0/Demo/Prefabs/ReplayCube.prefab'.
    2. Remove the ReplayTransform and ReplayObject components.
    3. With the prefab still selected, go to 'Tools -> Ultimate Replay -> Make Selection Replayable -> ReplayTransform'
    4. Re-add the cube prefab asset the the replay settings. Go to 'Tools -> Ultimate Replay -> Settings' and drag the cube prefab asset under the 'prefabs' collection.
    The demo should now work as expected.

    We will look into this further when we get chance and get back to you.
     
    Erethan likes this.
  9. tmongy

    tmongy

    Joined:
    May 9, 2014
    Posts:
    5
    Thanks, I can confirm the test scene now works in both 2018.4 and 2019.2.

    I followed the same steps with my project's prefabs and they are now getting replayed correctly.

    Another thing I should note is that when the bullet gets destroyed, I get an error saying:
    "MissingReferenceException: The object of type 'ReplayTransform' has been destroyed but you are still trying to access it.".

    I can get around this error if I use recordScene.RemoveReplayObject prior to destroying the bullet, but according to the documentation this shouldn't be necessary unless I'm using a pooling system, which I'm not.
     
    Erethan likes this.
  10. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Thanks for the update.
    Glad to hear that your prefabs are now replaying correctly.

    Could you post a stack trace for the MissingReferenceException if possible and we will look into that issue too. Sounds like it should be a simple fix.
     
  11. tmongy

    tmongy

    Joined:
    May 9, 2014
    Posts:
    5
    Sure here it is:

    Code (CSharp):
    1. MissingReferenceException: The object of type 'ReplayTransform' has been destroyed but you are still trying to access it.
    2. Your script should either check if it is null or you should not destroy the object.
    3. UltimateReplay.ReplayTransform.OnReplaySerialize (UltimateReplay.ReplayState state) (at <60d9e6b4468f49e994be8f7f8ac690cd>:0)
    4. UltimateReplay.ReplayObject.OnReplaySerialize (UltimateReplay.ReplayState state) (at <60d9e6b4468f49e994be8f7f8ac690cd>:0)
    5. UltimateReplay.ReplayScene.CaptureSnapshot (System.Single timeStamp, System.Int32 sequenceID, UltimateReplay.Storage.ReplayInitialDataBuffer initialStateBuffer) (at <60d9e6b4468f49e994be8f7f8ac690cd>:0)
    6. UltimateReplay.Core.Services.ReplayRecordServiceInstance.ReplayUpdate (System.Single deltaTime) (at <60d9e6b4468f49e994be8f7f8ac690cd>:0)
    7. UltimateReplay.ReplayManager.UpdateState (UltimateReplay.UltimateReplay+UpdateMethod updateMethod, System.Single deltaTime) (at <60d9e6b4468f49e994be8f7f8ac690cd>:0)
    8. UltimateReplay.ReplayManager.Update () (at <60d9e6b4468f49e994be8f7f8ac690cd>:0)
    Also, when attempting to build the project, I am getting the following error:

    Code (CSharp):
    1. ArgumentException: The Assembly UnityEditor is referenced by UltimateReplay ('Assets/Ultimate Replay 2.0/Plugin/UltimateReplay.dll'). But the dll is not allowed to be included or could not be found.
    2. UnityEditor.AssemblyHelper.AddReferencedAssembliesRecurse (System.String assemblyPath, System.Collections.Generic.List`1[T] alreadyFoundAssemblies, System.String[] allAssemblyPaths, System.String[] foldersToSearch, System.Collections.Generic.Dictionary`2[TKey,TValue] cache, UnityEditor.BuildTarget target) (at /Users/builduser/buildslave/unity/build/Editor/Mono/AssemblyHelper.cs:150)
    3. UnityEditor.AssemblyHelper.AddReferencedAssembliesRecurse (System.String assemblyPath, System.Collections.Generic.List`1[T] alreadyFoundAssemblies, System.String[] allAssemblyPaths, System.String[] foldersToSearch, System.Collections.Generic.Dictionary`2[TKey,TValue] cache, UnityEditor.BuildTarget target) (at /Users/builduser/buildslave/unity/build/Editor/Mono/AssemblyHelper.cs:156)
    4. UnityEditor.AssemblyHelper.FindAssembliesReferencedBy (System.String[] paths, System.String[] foldersToSearch, UnityEditor.BuildTarget target) (at /Users/builduser/buildslave/unity/build/Editor/Mono/AssemblyHelper.cs:190)
    5. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr) (at /Users/builduser/buildslave/unity/build/Modules/IMGUI/GUIUtility.cs:179)
     
    Last edited: Oct 31, 2020
  12. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Ultimate Replay 2.0.5 has been submitted to the asset store. This version includes:
    • Fixed an issue where importing the package could reset some aspects of the ReplayObject component causing Replayidentities to become fixed for prefab assets.
    • Fixed a bug where playback accuracy warnings could be reported for replay objects which have been assigned cloned identities.
    • Fixed a bug where destroying a replay object during recording could cause a missing reference exception.
    • Fixed a bug in the ReplayMemoryTarget where creating a size limited target would not work as expected.
    • An error message will now be displayed when attemtping to build a standalone player with the trial version of the asset to indicate that this is not possible.
     
    tmongy likes this.
  13. flomaaa

    flomaaa

    Joined:
    Apr 12, 2019
    Posts:
    24
    Hi scottyboy, thanks a lot for all these updates. I modified some scripts (e.g., Replaycontrols) and was wondering if an update to a newer version overrides my existing files. Can you just briefly mention what happens when I update?
     
  14. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    An update will indeed overwrite any changes you have made when importing the package. If you want to keep your code changes then you will probably want to copy the ReplayControls code into your own script like' MyReplayControls' so that it will not be overwritten. You can then make any changes you like and will not be affected by updates.
     
  15. flomaaa

    flomaaa

    Joined:
    Apr 12, 2019
    Posts:
    24
    Cheers, that's what I expected!
     
  16. flomaaa

    flomaaa

    Joined:
    Apr 12, 2019
    Posts:
    24
    Hi scottyboy,

    my Replay Material and Replay Text seems to work fine! @all: Happy to share the code if you want it, just PM me. It's a bit specific to my use case, but should work for other use cases after some minor modifications. The general idea of the implementation can also be found in the user guide provided by the asset.

    I've noticed that the Replay Preparer disables some components automatically, including the TextMeshPro component. Is it somehow possible to exclude specific components such as the TextMeshPro component without rewriting the entire class? Right now I've to manually enable the TextMeshPro component in the inspector during playback.
     
  17. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Glad to hear that you have successfully created your own replay components. The upcoming ReplayMaterial replay component we mentioned previously did not make it into the update since a quick fix was needed for some bugs. It would be interesting to see how you have implemented your recorder components if you wouldn't mind sharing.

    The DefaultReplayPreparer will disable all MonoBehaviour scripts by default (with a few exceptions: ReplayObject, ReplayBehaviour etc.) and I think that all text mesh elements are behaviour scripts? To get around this, you have a couple of solutions:
    1. Implement your own replay preparer as outlined in the documentation. This approach offers the most control but you will also need to decide what happens to other components too such as RigidBody, Animator, basically anything that can affect playback accuracy.
    2. Make a slight change to the source code. Open the source file located at 'Assets/Ultimate Replay 2.0/Scripts/Core/DefaultReplayPreparer.cs' and you will see a type array towards the top of the script like so:
    Code (CSharp):
    1. // Private
    2.         private static readonly Type[] skipTypes =
    3.         {
    4.             typeof(ReplayObject),
    5.             typeof(ReplayBehaviour),
    6.             typeof(Camera),
    7.             typeof(AudioSource),
    8.             typeof(ParticleSystem),
    9.         };
    You can add in any extra types to that array in order for them to be preserved during playback. It is not ideal at the moment and we are looking for better ways to add skip types without requiring source code changes. Normally, we would suggest that you inherit from 'ReplayBehaviour' in order to keep a script alive during playback but obviously this is not possible with 3rd party components.
     
    flomaaa likes this.
  18. flomaaa

    flomaaa

    Joined:
    Apr 12, 2019
    Posts:
    24
    Thank scotty, going to share the code with you via PM.
     
  19. mirrorboy

    mirrorboy

    Joined:
    Apr 18, 2015
    Posts:
    4
    Hi,

    I'm beginner of Ultimate Replay 2.0.

    I would like to use mesh collider with this assets. But this asset disables colliders when replay. I couldn't understand how to setup scene and objects by reading manual.

    Could you please tell me about it ?

    Best
    mirrorboy
     
  20. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Ultimate Replay 2.0 will disable any colliders attached to replay objects by default as you have discovered, along with a number of other components that could interfere with the replay.The reason for this is so that components cannot move or otherwise affect objects in playback mode that could cause an inaccurate replay.

    If this behaviour is not desirable, then it is possible to implement your own 'replay preparer' to override the default behaviour. The documentation will let you know how to create a custom replay preparer. If you are not using the trial version, it may be easier to modify the source code slightly so prevent collider components from being affected. The source file you would be interested in can be found at 'Assets/Ultimate Replay 2.0/Scripts/Core/StatePreparation/ColliderPreparer.cs'.

    Note that we are working on better ways to have more control over this as we are aware that it should be easier to make changes to the default replay preparer behaviour without requiring source code changes.

    Setting up scene objects is quite a simple process and should take only 2 steps for most use cases:
    1. Select a scene object that you want to make replayable.
    2. Go to the menu 'Tools -> Ultimate Replay -> Make Selection Replayable ->' and from that menu, select a replay component that is suitable for your needs such as 'ReplayTransform'. Note that you can add multiple replay components to the same game object if required.
    Once you have done that, the scene object is ready to be recorded and replayed either using the included 'ReplayControls' script or by using the ReplayManager API.

    I hope this helps you. Let me know if there is anything else.
     
  21. mirrorboy

    mirrorboy

    Joined:
    Apr 18, 2015
    Posts:
    4
    @scottyboy805 Thank you very much for your quick reply. I will try it with your advice.
     
  22. plcuist

    plcuist

    Joined:
    Aug 29, 2013
    Posts:
    15
    Hi,
    I'm trying to register some prefabs from script as mentionned in the docs page 30. But calling RegisterReplayPrefab() does nothing.
     
  23. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    Thanks for reporting this issue. The method does nothing at the moment as you have discovered and that will be fixed in the next update. In the meantime, you can using the following code to register prefabs at runtime:

    Code (CSharp):
    1. UltimateReplay.UltimateReplay.Settings.prefabs.RegisterReplayablePrefab(ReplayObject)
     
  24. plcuist

    plcuist

    Joined:
    Aug 29, 2013
    Posts:
    15
    Thanks for your fast reply. It's working now.
     
    scottyboy805 likes this.
  25. Erethan

    Erethan

    Joined:
    Apr 27, 2015
    Posts:
    28
    Hi!

    I've been trying to save the contents of a ReplayStorageTarget into a byte[] to playback in a future moment. Currently, I am using a ReplayStreamTarget on a MemoryStream that I latter read from before stop recording. After that, I am trying to reconstruct the stream so I can playback from it.

    However, when I try to playback, I get the following errors:
    1. An exception caused the 'ReplayFileTarget' to fail (file stream thread : 44)
    2. EndOfStreamException: Unable to read beyond the end of the stream.
    3. ThreadStateException: The stream thread was aborted unexpectedly. Waiting was canceled to avoid infinite waiting but this may cause the state of the file streamer to be corrupted

    This is how I record the stream data into
    RecordedData
    :
    Code (CSharp):
    1. private ReplayStreamTarget replayStorage;
    2. private ReplayScene replayScene;
    3. private MemoryStream memStream;
    4.  
    5. public byte[] RecordedData { get; private set; }
    6.  
    7.     public void StopRecording()
    8.     {
    9.         if (ReplayManager.IsRecording(replayHandle))
    10.         {
    11.             if(IsRecording)
    12.             {
    13.                 RecordedData = new byte[memStream.Position];
    14.                 memStream.Read(RecordedData, 0, RecordedData.Length);
    15.             }
    16.  
    17.             ReplayManager.StopRecording(ref replayHandle);
    18.         }
    19.     }
    20.  
    This is how I try to playback from a byte[]
    Code (CSharp):
    1.   public void StartPlayback(byte[] replayData)
    2.     {
    3.         memStream = new MemoryStream();
    4.         memStream.Write(replayData, 0, replayData.Length);
    5.         memStream.Seek(0, SeekOrigin.Begin);
    6.         replayStorage = ReplayStreamTarget.CreateReplayStream(memStream);
    7.         replayScene = new ReplayScene();
    8.  
    9.         replayHandle = ReplayManager.BeginPlayback(replayStorage, replayScene, allowEmptyScene: true);
    10.     }

    What could be causing these errors or how else can I achieve this?
    Thanks!
     
  26. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    It looks like you are trying to read the recorded data before you have called 'StopRecording'. This will cause issues because the call to 'StopRecording' forces any buffered data to be flushed to the stream and also writes some important data tables at the end of the stream. You code will not capture that extra data which means that the errors you report are to be expected. You should be able to modify that code slightly to capture all data only after you have stopped recording like so:

    Code (CSharp):
    1.  
    2. public void StopRecording()
    3. {
    4.     if(ReplayManager.IsRecording(replayHandle) == true)
    5.     {  
    6.         // Stop recording first
    7.         ReplayManager.StopRecording(ref replayHandle);
    8.    
    9.         // Get data as byte[]
    10.         RecordedData = new byte[memStream.Length];  
    11.         memStream.Read(RecordedData, 0, RecordedData.Length);
    12.     }
    13. }
    Note: If you are recording a large number of replay objects or for a long duration then this operation may take a bit of time.

    I hope this helps you. Let me know if you have any more questions.
     
  27. Erethan

    Erethan

    Joined:
    Apr 27, 2015
    Posts:
    28
    I tried to StopRecording first but it apparently disposes the used memory stream as I get a ObjectDisposedException when calling
    RecordedData = new byte[memStream.Length]; 


    Any alternatives?
     
  28. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi again,
    It looks like an oversight on our part. Stream objects that are passed in get disposed automatically as if they were a file stream but that should not be the case when using the ReplayStreamTarget directly. We will make the necessary changes so that the Stream objects must be diposed by the caller when using a ReplayStreamTarget and submit an update to fix this problem. It will likley be a few days before we can submit an update but feel free to contact us directly at info(at)trivialinteractive.co.uk and we can send you a patch to fix this issue in the meantime.
     
    Erethan likes this.
  29. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Ultimate Replay 2.1.0 has been submitted to the asset store. This version includes:
    • Added new replay component 'ReplayMaterialChange' to record and replay material changes of a renderer component.
    • Added new replay component 'ReplayMaterial' to record and replay material properties for a specific renderer material.
    • Improved the settings window UI
    • The default replay preparer is now fully customizable via the settings window. You can now add component types that should be skipped by the default replay preparer as well as modify which component processors are enabled.
    • Fixed an issue where the 'ReplayManager.RegisterReplayPrefab' would have no effect.
    • Fixed an issue where 'ReplayManager.FindReplayPrefab' would always return null.
    • Fixed an issue with the ReplayStreamTarget where the source stream would automatially be disposed by the replay system meaning that the data could not be accessed when recording is stopped.
     
    Erethan and flomaaa like this.
  30. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    I am having a hard time getting my replay to interpolate and wondering if I'm missing something. So what I do in my game is drop timescale down to like .1 and record the replay. When I play it back, I want the option to play back full speed or drop the timescale of the replay. When I use ReplayManager.SetPlaybackTimeScale(PlaybackHandle, value) to adjust the playback speed, there is no interpolation on the character. I am using ReplayTransforms and they are set to Lerp. I am not using the ReplayAnimator component.

    I've fiddled with the record and playback FPS and the strobing is still there. How can I get interpolation to happen when I set the playback timescale to a low value for slow motion replays?
     
  31. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    You say that you drop the time scale down to 0.1 prior to recording. I assume you mean 'Time.timeScale'? If so, is there any particular reason why you cannot use the normal time scale of 1? You can still have slow motion effects during playback by setting the playback time scale value of less than 1. For example, passing a value of '0.5' will cause playback to run at half speed.

    I did a quick test using the replay cubed scene and settings the time scale to 0.1 does indeed cause choppy move for the physics objects during recording. Is this the behaviour you are refering to because playback appears to be smooth and correctly interpolated as expected. If you are using physics to update your characters movement, then the choppy behaviour during recording is likley caused by the physics time step not being set to a suitable value to match the game time scale. You should be able to avoid that by setting the fixed time update to a suitable value whenever you change your time scale as this post descibres.

    I hope I have understood the problem correctly. Let me know if not or if you have any more questions.
     
  32. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    Ok this ended up being my bad. I ran a test with the cube demo and it worked fine. Then I looked at my setup. What happened is I had implemented my own time controls, and the way I did the time slider was such that it was (inadvertantly) setting the replay playback time every frame. This was nuking the interpolation. So, yeah, I'm gonna stop doing that!
     
  33. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Glad to hear that you found the problem.
    Setting the playback time every update would indeed cause stuttery playback but nice to see it was a simple fix.
    Let me know if there is anything else.
     
  34. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    Yeah thanks for your reply. The cube test was the gold standard there.

    On another note, if you haven't already done it, would be nice to have a matching ReplayManager.GetPlaybackTimeScale(playbackHandle) method to go with SetPlaybackTimeScale.
     
  35. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    Another thing I'm running into:

    I'm setting PlaybackTimeScale and consuming normalizedTime for my time slider. The constructor in ReplayTime is being called every time PlaybackTimeScale is set, but it's setting normalizedTime to 0 in it (ReplayTime.cs:81). This is making my time slider reset to 0 while I am adjusting the playback speed. However once I restart playback, the normalizedTime is set properly. So this setting of 0 doesn't seem to be necessary. Easiest change for me would be to have that removed, or calculated at constructor time (which probably makes the most sense).

    Also, poking around your code I discovered Mathf.InverseLerp! Over 10 years of Unity and I've never seen that function. Neat.
     
  36. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    There is no 'GetPlaybackTimeScale' method as you have discovered but there is the 'GetPlaybackTime' method which should give you the information you need. You can use it like so:

    Code (CSharp):
    1. ReplayManager.GetPlaybackTime(handle).TimeScale;
    This method returns a ReplayTime object so you can also access the actual playback time, frame delta, playback direction etc.

    Perhaps the method is no so easy to find because you may expect it to return a single float value representing the playback time and as a result you disregard it thinking it is not suitable?

    Thanks for letting us know about the normalizedTime issue. We will fix that in the next update and calculate the correct value in the constructor.

    Yes, the Mathf.InverseLerp method comes in very handy :)
     
  37. _ascilograf

    _ascilograf

    Joined:
    May 18, 2014
    Posts:
    2
    Hi, I have an issue after destroying cubes through code in cubes demo when trying to playback a replay:

    Code (CSharp):
    1. MissingReferenceException: The object of type 'ReplayObject' has been destroyed but you are still trying to access it.
    2. Your script should either check if it is null or you should not destroy the object.
    3. UnityEngine.Component.GetComponentsInChildren[T] (System.Boolean includeInactive) (at <f38c71c86aa64e299d4cea9fb7c715e1>:0)
    4. UnityEngine.Component.GetComponentsInChildren[T] () (at <f38c71c86aa64e299d4cea9fb7c715e1>:0)
    5. UltimateReplay.Core.DefaultReplayPreparer.PrepareForPlayback (UltimateReplay.ReplayObject replayObject) (at Assets/Ultimate Replay 2.0/Scripts/Core/DefaultReplayPreparer.cs:130)
    6. UltimateReplay.ReplayScene.PrepareForPlayback (UltimateReplay.Storage.ReplayInitialDataBuffer initialStateBuffer) (at Assets/Ultimate Replay 2.0/Scripts/ReplayScene.cs:322)
    7. UltimateReplay.ReplayScene.SetReplaySceneMode (UltimateReplay.ReplayScene+ReplaySceneMode mode, UltimateReplay.Storage.ReplayInitialDataBuffer initialStateBuffer, UltimateReplay.ReplayHandle handle) (at Assets/Ultimate Replay 2.0/Scripts/ReplayScene.cs:288)
    8. UltimateReplay.ReplayManager.BeginPlayback (UltimateReplay.Storage.ReplayStorageTarget replaySource, UltimateReplay.ReplayScene playbackScene, UltimateReplay.ReplayPlaybackOptions playbackOptions, System.Boolean allowEmptyScene, System.Boolean fixedFrame) (at Assets/Ultimate Replay 2.0/Scripts/ReplayManager.cs:693)
    9. UltimateReplay.ReplayManager.BeginPlayback (UltimateReplay.Storage.ReplayStorageTarget replaySource, UltimateReplay.ReplayScene playbackScene, System.Boolean allowEmptyScene, UltimateReplay.ReplayPlaybackOptions playbackOptions) (at Assets/Ultimate Replay 2.0/Scripts/ReplayManager.cs:644)
    10. UltimateReplay.ReplayControls.OnGUI () (at Assets/Ultimate Replay 2.0/Scripts/ReplayControls.cs:238)
     
  38. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    Yeah I found that property for the timescale, but I still think symmetry in the API is expected an GetPlaybackTimeScale would indicate that it's available. If I see a Set I expect a Get (though the reverse is not necessarily true).
     
  39. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Yes, I tend to agree now that you have raised the point. We will look at adding such methods in the next update to make the API more user friendly and intuitive.

    Thanks for the feedback.
     
    benthroop likes this.
  40. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    I've got another issue that I could use help with. I'm able to successfully capture and playback a replay one time. However, the second time I try to record using the same storage and handles, the variable replayObjects at ReplayScene:357 is coming back with entries that are null and nothing else. So I'm going to tell you what I'm doing any maybe you can take a stab at where I might be mishandling Ultimate Replay, or if there is a bug.

    So, in my game I let the user edit the scene, then I "simulate" in game and record a replay. It's important that the scene can return to it's starting state BEFORE the simulate step. I cannot rely on Ultimate Replay for this. The way I handle this is to put all of the objects under a single parent GameObject. I deactivate that parent object and then clone that GameObject (and its children, automatically). Then the resultant clone is set active.

    This works for the first recording/playback of the replay.

    Once the replay is done being viewed, we return to the starting state. In this process, the cloned parent is destroyed and the original parent is reactivated. This looks correct until we go to start recording again, at which point we hit a nullref at ReplayScene:357, where like I said the replayObjects list is filled with null objects.

    What appears to be happening is that the replayObjects list has references to the cloned objects that were destroyed. I would expect that those references would be cleaned up at some point in the process of stopping the recording. The only function I can see that would do that is ReplayScene.RemoveReplayObject. However this is not getting called.

    That made me think maybe the entire ReplayScene would get destroyed and remade, but that appears to only happen if I do it myself. I started looking at the Racing example, which does seem to do that, but I have to leave this for tomorrow since it's getting late.

    Anyway, thanks for reading this much. If anything jumps out at you that I might be doing wrong, please let me know.

    EDIT:

    Just tried one more thing. I tried making a new ReplayScene each time a new recording was started. It still errors, but now it's different. It's saying the scene has no replay objects.

    My guess is that because I'm cloning gameobjects with ReplayObject and ReplayTransform on them, and their ID's are the same as their source, that once they get added to the system there's some code, somewhere, that thinks they are handled and doesn't add them to this new scene. Let me know if I'm on the right track. Thanks.
     
    Last edited: Nov 16, 2020
  41. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Thanks for the detailed explanation.
    You say that you deactivate the parent object when you clone the objects. Do you also destroy these objects at any point? If so, then Ultimate Replay 2.0 wexpects that you will also remove those dead objects from any replay scenes they may be registered with, or alternativley, you can recreate a new ReplayScene object.

    When you clone your objects, do you also update the ReplayScene with the new objects references? The replay scene works with object references rather than replay identities so cloning objects will not automatically update the replay scene. You would need to remove any registered objects that you will clone and then re-add the cloned versions. Alternativley, you can clone your objects and then use one of the helper methods like 'ReplayScene.FromCurrentScene' to create a new replay scene instance.

    Anytime Ultimate Replay 2.0 needs to destroy an object during recording, it will call 'ReplayScene.RemoveReplayObject' as can be seen in the 'ReplaySnapshot' class at around line '368'. This is the only time that the replay system will remove objects from the scene and similarly, it will add objects if an instantiate call is required for accurate playback.

    You also say that you get a different error while creating a new replay scene. I assume you use 'new ReplayScene()' to create an instance? This is fine if you will instantiate objects during recording or if your existing replay has objects that are instantiated dynamically. You are getting an error because you have not allowed empty scenes to be used. You can allow empty scenes by passing 'true' as the 4th argument to 'BeginRecording' or 'BeginPlayback'. Your empty replay scene will then work as expected.
     
  42. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    263
    I really appreciate you taking the time to respond. You called it. I was doing new ReplayScene() and saying ReplayScene.FromCurrentScene() instead made everything work. On to the next! Thanks!

    EDIT: haha well it didn't break on recording, but now it's having the same error when I start Playback. Will dig.

    EDIT2: SUCCESS! I didn't push the newly created ReplayScene into the call to ReplayManager.BeginPlayback. Seems obvious in hindsight.
     
    Last edited: Nov 16, 2020
  43. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    No problem, I am happy to help :)
    Glad that the issue is now resolved. If you have any thoughts or feedback about that aspect of the API and how it could be made simpler or more intuitive then feel free to share. We are always looking for ways to improve the asset or make it easier to use.
     
  44. mikleb

    mikleb

    Joined:
    Mar 5, 2020
    Posts:
    2
    Love the asset, amazing work!
    Is it possible to use this with VFX graph particles? I have some water spray I'd like to use it on that is generated via the VFX graph and can't for the life of me figure out how you would do that.
     
  45. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Hi,
    I have not used VFX graph before so i cannot say for sure if it can be supported or not. Does this system offer a way to simulate the particles to a particular time offset, much like the ParticleSystem.Simulate method? If so, then it should be possile to support recording and replaying of these particles because this is how Ultimate Replay replays the UNity particle system.
     
  46. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Ultimate Replay 2.1.1 has been submitted to the asset store for review. This version includes:
    • Fixed a bug in the playback system where replaying in reverse could cause stuttering or non-smooth movement if the replay was captured with a low record rate.
    • Depreciated method 'ReplayManager.StopRecording(ReplayHandle, bool)' in favor of 'ReplayManager.StopRecording(ReplayHandle)'. Specifying whether the replay scene will be restored can now be done when calling 'BeginPlayback' or via the new method 'ReplayManager.SetPlaybackEndRestoreSceneMode'.
    • Added method 'ReplayManager.SetPlaybackEndRestoreSceneMode(ReplayHandle, bool)'
    • Added method 'ReplayManager.GetPlaybackTimeNormalized(ReplayHandle)'
    • Added method 'ReplayManager.GetPlaybackTimeScale(ReplayHandle)'
    • Added method 'ReplayManager.GetPlaybackDirection(ReplayHandle)'
    • Added method 'ReplayManager.RemoveReplayObjectFromRecordScenes(ReplayObject)'
    • Added method 'ReplayManager.RemoveReplayObjectFromRecordScene(ReplayHandle, ReplayObject)'
    • Added method 'ReplayManager.RemoveReplayObjectFromPlaybackScenes(ReplayObject)'
    • Added method 'ReplayManager.RemoveReplayObjectFromPlaybackScene(ReplayHandle, ReplayObject)'
    • Replay scene integtrity will now be checked when starting recording or playback. Any ReplayObjects that have been destroyed but not removed from the scene will now generate an error but the replay system will continue to run. Playback accuracy errors may be unavoidable.
    • Fixed a bug in the replay time system where the normalized time value would always be initialized to a value of 0.
     
  47. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Thanks for reporting this issue.

    I assume you mean that you are destroying the cube game objects manually via script? If this is the case, then the intended behaviour is that you should also remove the replay object from any active ReplayScenes by calling ‘RemoveReplayObject’. At the moment, a ReplayScene instance is required to do this and if you are using the default ReplayControls script, then you will not have access to the ReplayScene used. To fix this, we have added helper methods to the ReplayManager script in the upcoming 2.1.1 update to support removal of replay objects from all scenes, similar to the ReplayManager.AddReplayObjectToScenes’ methods.

    We have also added better error handling so that failing to remove a dead replay object will not cause a hard error.
     
  48. mikleb

    mikleb

    Joined:
    Mar 5, 2020
    Posts:
    2
    It does have a simulate method here: https://docs.unity3d.com/2020.2/Documentation/ScriptReference/VFX.VisualEffect.Simulate.html

    It seems to be a bit different from the regular ParticleSystem simulate method however
     
  49. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,193
    Thanks for the link.
    I had a look at the API and the Simulate method looks promising and looks like it should be suitable for restoring the effect to a specific frame. The only other potential problem I can see is that there does not appear to be a way to get the current step count. Perhaps this could be calculated somehow but it would be required in order for Ultimate Replay 2.0 to be able to suport this component. Maybe you have some ideas about how the current step count value could be determined?
     
  50. mirrorboy

    mirrorboy

    Joined:
    Apr 18, 2015
    Posts:
    4
    Hi
    @scottyboy805

    I have tried iOS but replay doesn't work...

    Of course in Unity editor. My replay is working correctly.

    Is there any special setting for iOS ?


    Best.