Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Utilities [WIP - Beta] Ultimate Replay 3.0 - Next generation state based replay system (Killcam, Ghost, +More)

Discussion in 'Tools In Progress' started by scottyboy805, May 8, 2023.

  1. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Ultimate Replay 3.0 is currently in open beta with ongoing devlopment!
    Follow this thread to receive news and progress updates.

    Icon.png

    Coming soon to the Unity asset store!
    Releasing: 15th September 2023

    Support / Suggestions | Discord | Documentation | Samples | Asset Store | Asset Store (Trial) | Ultimate Replay 2.0 (Previous Version)


    Ultimate Replay 3.0 Open Beta Is Now Available!
    Ultimate Replay 3.0 is now available as an open beta. You can find the latest version over on github (closed source): Ultimate Replay 3.0 - Beta

    Ultimate Replay 3.0 Is Suitable For:
    Killcam's or Deathcam's, Action or Instant Replays, Ghost Cars, Highlights Reel, Sports Montage, Rewind Time, Second Chance Gameplay, Plus many more...
    Ultimate Replay 3.0 is the next iteration of our popular Ultimate Replay state based replay system, and aims to make in-game replays, killcams and ghost vehicles easier than ever. We have received some really good feedback and suggestions over the lifecycle of version 2.0, some which we could implement and some which would cause breaking changes. Now we are starting once again with a clean slate to support as many of these features and workflows as possible, while making ease of use a top priority.

    Cover.png
    If you are not familiar with our Ultimate Replay series, the asset is designed to be a complete replay system for your game to make it easy to add action replays, killcams, ghost cars and much more with minimal effort. It works by capturing a snapshot of the scene at regular intervals containing information such as object postion, rotation, plus other data specified by replay components. The replay system then uses that information to reconstruct a smooth replay using interpolation in the Unity scene which can be rendered by any active camera. For that reason, it is possible to view the replay from any angle and even fly the camera around while the replay is occuring. Also since the replays are rendered in realtime, the replay system can run on any render pipeline with any camera syetem, post effects etc.
    Existing Users (Ultimate Replay 2.0)
    If you are a previous user of Ultimate Replay 2.0, you may wonder about the future plans for version 2.0 and what will happen when version 3.0 releases. There is no set release date for version 3.0 for the moment, however when it does become available, existing Ultimate Replay 2.0 customers will be entitled to a heavily reduced upgrade price for version 3.0 which will be handled by Unity asset store upgrade system. The final upgrade price is yet to be confirmed, however typically it will be in the area of 25% of the full asset price as with our previous asset upgrades.
    When version 3.0 does release, Ultimate Replay 2.0 will remain available on the asset store for long term support, and will continue to receive bug fixes in that time, but note that new feature will likley not be added. Also note that version 2.0 will be marked as legacy at that time and we would encourage users to update to version 3.0 if possible. Feel free to contact us if there are any question.

    Features
    Most existing features from Ultimate Replay 2.0 have been brought forward and either updated or improved in some way. However based on the great feedback we have received from existing users, we have also refectored many systems and started work on new features that have been requested. Here are some features that are in various states of completion:
    • Complete - Refactor main replay API to be simpler to use and more powerful.
    • Complete - Support for multiple simultaneous record and replay operations.
    • Complete - Highly optimized memory/file storage requirements (More that 2x improvement over the previous version in some cases).
    • Complete - Large improvements to runtime performance in terms of memory usage and CPU usage.
    • Complete - Massive improvements to replay state API and serialization speed to allow more data ond objects to be recorded on less performant devices.
    • Complete - (Highly requested) Support custom metadata stored with a replay. Includes common values like scene name and developer name by default, but can easily be expanded to support any custom data specific to your game.
    • Complete - Improvements to replay file streaming performance to avoid buffering issues on slower devices.
    • Complete - Add support for operations such as copying or appending to replay storage targets making it much easier to combine replays.
    • Complete - Redesign replay component editor inspectors for better usability and dispaly of information.
    • Complete - Offer more fine grain control when needed for updating the replay system manually. It is possible to manually update the replay system with a single call to `ReplayManager.ReplayTick(float dt)`
    • Complete - Support tokenising replay data to support annotateded output formats such as json which expects Key/Value pairs.
    • Complete - (Highly Requested) Support using interpolation when seeking. No more snapping to keyframes when dragging the slider, but now you get buttery smooth seeking.
    • Complete- Improved compression algorithm to support much smaller file sizes with minimal impact on performance.
    • Partially Completed - Single highly optimized replay component to record skeletal animation, IK or ragdoll. The previous version used a ReplayTansform on each bone which is fine, but does come with extra overhead per bone. The new system eliminates that additional overhead, and can also implement some further optimizations. Automatic setup support for humanoid and legacy rigs.
    • Completed - (Highly requested) Support streaming to and from json. Writing to json file is working but readin is currently WIP.
    • Completed - Introduce lifecycle providers for better pooling support, and to allow replay prefabs to be instantiated from resouces, asset bundles or other sources. The current prefab system in version 2.0 holds a reference to a prefab asset which is not ideal since it forces all prefabs to be loaded at startup, and also does not support loading from arbitrary locations such as resources, or addressables.
    • WIP - Support for combining multiple separate replays into a single replay montage such as a hilights reel for example.
    • Completed - Support async operations for potentially lengthy tasks such as copying storage targets.
    • Completed - Support for fully loading replay files upfront where streaming operations are not desirable.
    • WIP - Scripting reference, samples repo and user guide documentation.
    Feedback
    Missing a feature? Let us know what you would like to see worked on/added either though one of the support channles, or by posting in this thread.
    Any feedback or criticismis welcome as it will help us build a better final product to power your games.

    Showcase
    Simple ghost vehicle example for a racing game:
    GhostReplayGif.gif

    Simple action replay montage for a racing game showing highlights of the lap when the race has finished:
    ActionReplayGif.gif
     
    Last edited: Sep 15, 2023
    DragonCoder, petey and Trigve like this.
  2. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    More features have been completed since the last update, and we have also started working on the documentation and samples. Some basic code samples are already completed and are accessible on github samples repo, but they will be subject to change as development continues.

    For now there has been progress on the following features:
    • Now Complete - Improved compression algorithm to support much smaller file sizes with minimal impact on performance. We have implemented a much more efficient segment compression algorighm for reducing the size of a series of replay snapshots in a segment. On top of that we have added support for block compression when streaming to and from file, and the file size results look very promising. More info on that in a future update.
    • Now Complete- Introduce lifecycle providers for better pooling support, and to allow replay prefabs to be instantiated from resouces, asset bundles or other sources. This feature is now complete and allows prefabs to be added by reference or by resource path by default. Both methods have built in support for pooling using UnityEngine.Pool implementation that can be enabled or disabled with a simple toggle (Enabled by default). It is also now very easy to create your own lifecycle provider if you wanted to use replay prefabs from an asset bundle for example. More examples for that will follow.
    • Further work on json file reading, although there is still much more to do until that is completed. Writing json files is working well and some example output files will be showcased in the near future.
     
  3. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Just another quick update about the progress made over the last couple of weeks.
    More work has been completed on replay components for recording and replaying skeletal animations, ragdoll, IK, etc. Also some work on the main API and async operations has been completed.
    • Partially Complete - Single highly optimized replay component to record skeletal animation, IK or ragdoll. We have now finished work on support for fully recording generic rigs (Works for humanoid too but we are working on another dedicated component for humanoid rigs that can offer even better performance) with a highly optimized dedicated replay component. It is ideal for recording skeletal animation, ragdolls, IK and any other form of animation or effect that works by modifying the transforms of bones. Support for humanoid rigs is partially implemented and will be completed soon.
    • Completed - Support async operations for potentially lengthy tasks such as copying storage targets. Finished and it is now possible to stream memory storage targets to file at a later time without blocking the main thread.
    More work to come soon and we will also be planning to release a beta version over the next few weeks for existing Ultimate Replay users to try out. More info will be posted here when that becomes available.
     
  4. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    I am pleased to announce that Ultimate Replay 3.0 is now in open beta! :D
    We decided to move forward with an open beta to collect a wider range of feedback to help make a better asset, so anyone is welcome to check out the beta over on github (closed source): Ultimate Replay 3.0 - Beta

    Feedback, bug reports and suggestions are all welcome either in this thread, over on discord or by creating an issue on github.Any feedback is highly appreciated.

    Disclaimer: Currently Ultimate Replay 3.0 is considered early access as features and bugs are being activley worked on.
     
  5. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Beta version 3.0.1p1 is now avialble to try out here. This version fixes some bug fixes, includes extra code comments in preparation for documentation, and samples repo has been updated with extra code examples. There is now also support for loading streams and files upfront (Default behaviour is to stream on demand via background thread, but is not always the best solution):
    • Completed - Support for fully loading replay files upfront where streaming operations are not desirable. It is now possible to fully load replay streams and files upfront during a loading screen for example to avoid possible buffering issues on slow devices. There are also async versions available that can load without blocking the main thread
     
    Jayferd96 likes this.
  6. KoalityGame

    KoalityGame

    Joined:
    Jan 30, 2016
    Posts:
    21
    Looking forward to the full release! Keep up the great work :)
     
  7. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Hey, thanks for the support :)
    Yes we are working hard to get a full release ready. Not too long now hopefully but I will keep posting updates as progress is made.
     
  8. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    An exciting update this week!
    The highly requested JSON file/stream support is now fully implemented and working so you can now save and load your replay files in plain text if required. Using the custom binary format (Default) is still recommended for most cases since a comparible JSON file is more than 20x larger (10kb vs 230kb for a simple test case - size could be reduced by not using formatted text (tab, new line, etc.)), but the option is now there and performance also looks very reasonable so far with no obvious issues for realtime streaming.
    Just a little more testing required before it can be considered fully complete, but hopefully there should be another beta version with json support available by the end of the week.
    • Completed - (Highly requested) Support streaming to and from json. Writing to json file is working but reading is currently WIP. Completed pending further testing - Support for both reading and writing json replay files.
    As an example you can find a json file created by Ultimate Replay 3.0 here to give an idea of the structure used. If you are interested it uses pretty much the same prinicples and structure as the binary format with 5 main sections, only in text form:
    • Fixed Size Header - Contains info about file contents, duration etc. (JSON format uses hex values for header so that they are fixed size and can be overwritten with correct values when the recording ends).
    • Replay Data - Contains all replay segments that have been recorded which contains the actual recorded data for replay objects in the form of snapshots at regular intervals (A segment is the built in chunking system which improves streaming performance and file size by using chunk compression - for binary format only).
    • Segment table - A lookup table that provides information about all segments that were recorded and their location in the replay file for quick access.
    • Persistent Data - Contains any information stored using the persistent data api, for example: information about newly spawned replay objects such as position and parent.
    • Metadata (New for v3.0) - Additional metadata that can be set by the user (Can also be expanded to support custom fields) to give more information about the replay such as a name, the scene used, or anything else that might be needed. Previously another acompanying file would need to be created to store such data which was far from ideal.

    With that major step complete we are only left with a few more minor features to implement, bug fixes, testing and then finish work on the documentation in preparation for release. With that in mind I can now say that we will aim for an official release for around september, although that could change especially with the current state of asset store verification queue times. We will do our best though :)
     
  9. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Beta version 3.0.2 is now available which adds the previously mentioned json read/write support for replay files and streams, as well as many other improvements and bug fixes. You can find the latest version here (closed source).

    A source version is also available for existing Ultimate Replay 2.0 customers via discord or support email. You will just need your invoice number to gain access.

    Any feedback is welcome :)
     
  10. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Beta version 3.0.3 is now available which includes a number of bug fixes and improvements. You can try out the latest beta version here.
     
  11. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Looks like things are going well and we are on track to release in September, so I can now confirm that the release date for Ultimate Replay 3.0 onto the Unity asset store will be 15th September 2023. More updates to follow as further progress is made :)
     
    Trigve likes this.
  12. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Ultimate Replay open beta version 3.0.4 is now available for testing. This update includes the following :
    • Implement new ReplayAnimator with support for IK
    • Performance and allocation improvements.
    • Storage size improvements.
    • Support further performance improvements using unsafe code: Requires enabling unsafe code and defining `ULTIMATEREPLAY_UNSAFE` (source version only).
    • Further testing and work on demos/samples.
    • Bug fixes.
    Try the beta version here (Source version available via discord for existing 2.0 users).

    Still on track for the Sep 15th release :)
     
  13. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Further progress has been made on demos showcasing some of the common use cases and how they can be implemented with Ultimate Replay 3.0. In particular we have completed demos for ghost vehicles for racing games or similar, as well as action replays which can apply to a wide variety of racing, sports or really any game to show gameplay highlights at the end of a round for example.

    Ghost Vehicle:
    We have remastered the ghost car demo from Ultimate Replay 2.0 and updated it to use the newer and easier to work with API's. The result is a smooth and accurate ghost replay file implemented by attaching a few replay components and a little bit of basic coding (See source code below).

    Code (CSharp):
    1. using System;
    2. using System.IO;
    3. using UltimateReplay.Storage;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6.  
    7. namespace UltimateReplay.Demo
    8. {
    9.     public class GhostCarReplay : MonoBehaviour
    10.     {
    11.         // Private
    12.         private const string prefsKeyBestLap = "ultimatereplay.ghostcar.bestlap";
    13.         private const string replayFileCurrent = "current.replay";
    14.         private const string replayFileBest = "best.replay";
    15.  
    16.         private ReplayStorage recordStorage = null;
    17.         private ReplayStorage playbackStorage = null;
    18.         private ReplayRecordOperation recordOp = null;
    19.         private ReplayPlaybackOperation playbackOp = null;
    20.  
    21.         private bool lapStarted = false;
    22.         private float lapStartTime = 0;
    23.         private float lapBestTime = -1f;
    24.  
    25.         // Public
    26.         public Text timer;
    27.         public Text bestTime;
    28.         public ReplayObject playerCar;
    29.         public ReplayObject ghostCar;
    30.  
    31.         // Methods
    32.         [ContextMenu("Reset Best Lap Time")]
    33.         public void ResetBestLapTime()
    34.         {
    35.             PlayerPrefs.SetFloat(prefsKeyBestLap, -1f);
    36.         }
    37.  
    38.         public void Start()
    39.         {
    40.             // Load best time
    41.             lapBestTime = PlayerPrefs.GetFloat(prefsKeyBestLap, -1f);
    42.         }
    43.  
    44.         public void OnDestroy()
    45.         {
    46.             // Release record storage
    47.             if (recordStorage != null)
    48.                 recordStorage.Dispose();
    49.  
    50.             // Release playback storage
    51.             if (playbackStorage != null)
    52.                 playbackStorage.Dispose();          
    53.         }
    54.  
    55.         public void Update()
    56.         {
    57.             if (lapStarted == true)
    58.             {
    59.                 TimeSpan raceTime = TimeSpan.FromSeconds(Time.time - lapStartTime);
    60.                 timer.text = string.Format("{0:00}:{1:00}:{2:00}", raceTime.Minutes, raceTime.Seconds, raceTime.Milliseconds);
    61.             }
    62.  
    63.             // Update best time
    64.             if(lapBestTime >= 0f)
    65.             {
    66.                 TimeSpan bestRaceTime = TimeSpan.FromSeconds(lapBestTime);
    67.                 bestTime.text = string.Format("Best: {0:00}:{1:00}:{2:00}", bestRaceTime.Minutes, bestRaceTime.Seconds, bestRaceTime.Milliseconds);
    68.             }
    69.             else
    70.             {
    71.                 bestTime.text = "Best: --:--:---";
    72.             }
    73.         }
    74.  
    75.         public void OnTriggerEnter(Collider other)
    76.         {
    77.             // Make sure a car is triggering
    78.             if (other.GetComponentInParent<CarController>() == null)
    79.                 return;
    80.  
    81.             bool betterLap = false;
    82.             float currentLapTime = Time.time - lapStartTime;
    83.  
    84.             // Check for improved lap time
    85.             if(lapStarted == true && (lapBestTime < 0f || currentLapTime < lapBestTime))
    86.             {
    87.                 betterLap = true;
    88.                 lapBestTime = currentLapTime;
    89.  
    90.                 // Save best lap
    91.                 PlayerPrefs.SetFloat(prefsKeyBestLap, lapBestTime);
    92.  
    93.                 Debug.Log("New best lap: " + bestTime.text);
    94.             }
    95.  
    96.             lapStartTime = Time.time;
    97.  
    98.             // Stop replaying ghost
    99.             if(playbackOp != null)
    100.             {
    101.                 playbackOp.StopPlayback();
    102.                 playbackOp = null;
    103.  
    104.                 if (playbackStorage != null)
    105.                 {
    106.                     playbackStorage.Dispose();
    107.                     playbackStorage = null;
    108.                 }
    109.             }
    110.  
    111.             // Stop recording player
    112.             if(recordOp != null)
    113.             {
    114.                 recordOp.StopRecording();
    115.                 recordOp = null;
    116.  
    117.                 recordStorage.Dispose();
    118.                 recordStorage = null;
    119.  
    120.                 // Check for better lap
    121.                 if(betterLap == true)
    122.                 {
    123.                     if(File.Exists(replayFileBest) == true)
    124.                         File.Delete(replayFileBest);
    125.  
    126.                     // Save new file
    127.                     File.Move(replayFileCurrent, replayFileBest);
    128.                 }
    129.             }
    130.  
    131.             // Start replaying ghost car if available
    132.             if(lapBestTime >= 0f && File.Exists(replayFileBest) == true)
    133.             {
    134.                 // Enable the ghost car
    135.                 ghostCar.gameObject.SetActive(true);
    136.  
    137.                 // Clone identities
    138.                 ReplayObject.CloneReplayObjectIdentity(playerCar, ghostCar);
    139.  
    140.                 // Load ghost replay
    141.                 playbackStorage = ReplayFileStorage.FromFile(replayFileBest);
    142.  
    143.                 // Start replaying - Pass in the ghost replay scene since we only want to replay the ghost car
    144.                 playbackOp = ReplayManager.BeginPlayback(playbackStorage, playerCar, ghostCar);
    145.  
    146.                 // Add end playback listener
    147.                 playbackOp.OnPlaybackEnd.AddListener(OnGhostPlaybackEnd);
    148.             }
    149.  
    150.             // Create storage for current player lap
    151.             recordStorage = ReplayFileStorage.FromFile(replayFileCurrent);
    152.  
    153.             // Start recording - Pass in the player replay scene since we only want to record the player car
    154.             recordOp = ReplayManager.BeginRecording(recordStorage, playerCar);
    155.  
    156.             // Set lap started flag - player has crossed the line once
    157.             lapStarted = true;
    158.         }
    159.  
    160.         private void OnGhostPlaybackEnd()
    161.         {
    162.             // Hide ghost car
    163.             ghostCar.gameObject.SetActive(false);
    164.  
    165.             // Cleanup playback
    166.             playbackStorage.Dispose();
    167.             playbackStorage = null;
    168.  
    169.             Debug.Log("Ghost car finished");
    170.         }
    171.     }
    172. }

    Action Replay:
    For the action replay demo we have reused the driving scene to keep assets and overall package size to a minimum, but instead of a ghost replay you will see an action replay montage once the race is finished from a number of camera angles. All cameras rendered in realtime as the replay occurs, and most cameras are even moving with the car or rotating to track the car.

    Code (CSharp):
    1. using System;
    2. using UltimateReplay.StatePreparation;
    3. using UltimateReplay.Storage;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using Random = UnityEngine.Random;
    7.  
    8. namespace UltimateReplay.Demo
    9. {
    10.     public class CarActionReplay : MonoBehaviour
    11.     {
    12.         // Type
    13.         /// <summary>
    14.         /// Custom preparer that does not do any preparation to the replay objects.
    15.         /// Required because we need to keep the colliders and rigid bodies enabled during playback so that triggers are detected to activate and deactivate replay cameras.
    16.         /// </summary>
    17.         private class CustomPreparer : IReplayPreparer
    18.         {
    19.             // Methods
    20.             public void PrepareForPlayback(ReplayObject replayObject) { }
    21.             public void PrepareForGameplay(ReplayObject replayObject) { }
    22.         }
    23.  
    24.         // Private
    25.         private ReplayStorage storage = null;
    26.         private ReplayRecordOperation recordOp = null;
    27.         private ReplayPlaybackOperation playbackOp = null;
    28.         private bool lapStarted = false;
    29.         private bool lapFinished = false;
    30.         private float lapStartTime = 0;
    31.  
    32.         private Vector3 carStartPosition = Vector3.zero;
    33.         private Quaternion carStartRotation = Quaternion.identity;
    34.  
    35.         // Public
    36.         public Text timer;
    37.         public GameObject uiRacing;
    38.         public GameObject uiFinishedRace;
    39.         public ReplayObject playerCar;
    40.         public Camera chaseCamera;
    41.         public TriggerCamera[] triggerCameras;
    42.         public Camera[] carCameras;
    43.  
    44.         // Methods
    45.         public void Start()
    46.         {
    47.             // Get car starting position
    48.             carStartPosition = playerCar.transform.position;
    49.             carStartRotation = playerCar.transform.rotation;
    50.  
    51.             // Add listeners
    52.             foreach (TriggerCamera cam in triggerCameras)
    53.                 cam.OnTriggerStateChanged.AddListener(UpdateActionReplayCamera);
    54.         }
    55.  
    56.         public void OnDestroy()
    57.         {
    58.             // Release the replay storage
    59.             if(storage != null)
    60.                 storage.Dispose();
    61.         }
    62.  
    63.         public void Update()
    64.         {
    65.             if (lapStarted == true && lapFinished == false)
    66.             {
    67.                 TimeSpan raceTime = TimeSpan.FromSeconds(Time.time - lapStartTime);
    68.                 timer.text = string.Format("{0:00}:{1:00}:{2:00}", raceTime.Minutes, raceTime.Seconds, raceTime.Milliseconds);
    69.             }
    70.  
    71.             // Check for restart
    72.             if(lapFinished == true && Input.GetKeyDown(KeyCode.R) == true)
    73.             {
    74.                 // Start racing again
    75.                 RestartRace();
    76.             }
    77.         }
    78.  
    79.         public void OnTriggerEnter(Collider other)
    80.         {
    81.             // Make sure a car is triggering
    82.             if (other.GetComponentInParent<CarController>() == null)
    83.                 return;
    84.  
    85.             // Set finished flag
    86.             if (lapStarted == true)
    87.             {
    88.                 lapFinished = true;
    89.  
    90.                 // Stop recording
    91.                 if (recordOp != null)
    92.                 {
    93.                     recordOp.StopRecording();
    94.                     recordOp = null;
    95.                 }
    96.  
    97.                 // Start our action replay
    98.                 StartActionReplay();
    99.             }
    100.             else
    101.             {
    102.                 lapStartTime = Time.time;
    103.             }
    104.  
    105.             // Record the player car
    106.             if(lapFinished == false)
    107.             {
    108.                 // Create our storage
    109.                 storage = new ReplayMemoryStorage();
    110.  
    111.                 // Start recording
    112.                 recordOp = ReplayManager.BeginRecording(storage, playerCar);
    113.             }
    114.  
    115.             // Set lap started flag - player has crossed the line once
    116.             lapStarted = true;
    117.         }
    118.  
    119.         private void StartActionReplay()
    120.         {
    121.             // Start replay of player car
    122.             playbackOp = ReplayManager.BeginPlayback(storage, playerCar, new CustomPreparer());
    123.  
    124.             // Disable main camera
    125.             chaseCamera.gameObject.SetActive(false);
    126.  
    127.             // Switch UIs
    128.             uiFinishedRace.SetActive(true);
    129.             uiRacing.SetActive(false);
    130.  
    131.             // Activate replay cameras
    132.             UpdateActionReplayCamera();
    133.         }
    134.  
    135.         private void UpdateActionReplayCamera()
    136.         {
    137.             // Only update when the race has finished
    138.             if (lapFinished == false)
    139.                 return;
    140.  
    141.             TriggerCamera activeCamera = null;
    142.  
    143.             // Check if any trigger cameras are available
    144.             foreach (TriggerCamera triggerCam in triggerCameras)
    145.             {
    146.                 triggerCam.cam.gameObject.SetActive(false);
    147.  
    148.                 if (triggerCam.HasTriggerObjects == true)
    149.                 {
    150.                     activeCamera = triggerCam;
    151.                     triggerCam.cam.gameObject.SetActive(true);
    152.                 }
    153.             }
    154.  
    155.  
    156.             // Select random car camera
    157.             int carCamIndex = (activeCamera == null) ? Random.Range(0, carCameras.Length) : -1;
    158.            
    159.             // Disable all car cameras
    160.             for(int i = 0; i < carCameras.Length; i++)
    161.             {
    162.                 carCameras[i].gameObject.SetActive(carCamIndex == i);
    163.             }
    164.         }
    165.  
    166.         private void RestartRace()
    167.         {
    168.             // Stop active replay
    169.             if(playbackOp != null)
    170.             {
    171.                 playbackOp.StopPlayback();
    172.                 playbackOp = null;
    173.             }
    174.  
    175.             // Enable UI
    176.             uiRacing.SetActive(true);
    177.             uiFinishedRace.SetActive(false);
    178.  
    179.             // Disable all trigger cameras
    180.             foreach (TriggerCamera triggerCam in triggerCameras)
    181.                 triggerCam.cam.gameObject.SetActive(false);
    182.  
    183.             // Disable all car cameras
    184.             foreach(Camera cam in carCameras)
    185.                 cam.gameObject.SetActive(false);
    186.  
    187.             // Enable chase cam
    188.             chaseCamera.gameObject.SetActive(true);
    189.  
    190.             // Reset state
    191.             lapStarted = false;
    192.             lapFinished = false;
    193.             lapStartTime = Time.time;
    194.  
    195.             // Reset forces
    196.             playerCar.GetComponent<Rigidbody>().velocity = Vector3.zero;
    197.             playerCar.GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
    198.  
    199.             timer.text = "00:00:000";
    200.  
    201.             // Reset player car
    202.             playerCar.transform.position = carStartPosition;
    203.             playerCar.transform.rotation = carStartRotation;
    204.         }
    205.     }
    206. }
    207.  
     
    Trigve likes this.
  14. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Ultimate Replay open beta version 3.0.6 is now available for testing. This update includes the following :
    • Optimize memory allocations during recording and playback.
    • Optimize some replay components to record less data.
    • Fix issue with json file streaming.
    • Fix issue with replay formatter id's causing incompatibilities between versions.
    • Add API's for converting replay streams to and from byte arrays.
    • Add extra async API's for potentially slow calls.
    • Further work on demo scenes.
    • Work on user guide documentation in preparation for release.
    • Other minor bug fixes.
    Try the beta version here (Source version available via discord for existing 2.0 users).
     
  15. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Ultimate Replay open beta version 3.0.8 is now available for testing. This update includes the following:
    • Fix an issue where record fps could be ignored in some cases.
    • Reduced allocations when reading json replay stream data.
    • Improved performance when reading json replay stream data.
    • Minor bug fixes.
    Try the beta version here (Source version available via discord for existing 2.0 users).
     
  16. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Only 1 week to go now until official release :cool:

    Check out the official support and marketing thread here.
     
  17. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    I am happy to anounce that Ultimate Replay 3.0 has now released on the Unity asset store :D.

    Check it out on the asset store and grab a copy at 30% off as part of out initial release sale. Existing v2.0 users can also upgrade via the asset store for the upgrade price of just $10, simply login to see the discount!.
     
  18. scottyboy805

    scottyboy805

    Joined:
    Apr 10, 2013
    Posts:
    1,169
    Hey, I guess you are talking about moving particle systems which are not replayed correctly by the default ReplayParticles component due to how it works?
    In that case there is an additional `ReplayParticlesV2` component available which should work ok with moving particle systems, although does not simulate 100 accuratley. It is not possible to add it via the tools menu though so you would need to `AddComponent -> ReplayParticlesV2` to set that up. Hopefully it should give better results for this particular use case but let me know if not.

    Hope that helps. Let me know if there is anything else.