// Methods public IEnumerator Start() { // Usually you should register replay prefabs in editor via the global settings but it can also be done via code if required UltimateReplay.Settings.prefabs.RegisterReplayablePrefab(instanitatePrefab); // Start recording - Note that we need to enable 'allowEmptyScene' if there are no replay objects in the scene initially ReplayHandle recordHandle = ReplayManager.BeginRecording(null, null, true, true); // Wait for some time to pass yield return(new WaitForSeconds(1f)); // Spawn a dynamic replay object ReplayObject obj = Instantiate(instanitatePrefab); // Add the object to all recording scenes - This is a required step otherwise the object will not be recorded ReplayManager.AddReplayObjectToRecordScenes(obj); // Wait for some time to pass now that the object has been spawned yield return(new WaitForSeconds(1)); // End recording // The resulting replay will have 1 second of nothing and then the dynamic object will be re-instantiated by the replay system ReplayManager.StopRecording(ref recordHandle); }
void ILoadableContent.Load() { _object = ReplaysManager.Instance.GetById(_id); if (_object?.TrackId != null) { var trackObject = TracksManager.Instance.GetById(_object.TrackId); if (_object.TrackConfiguration != null) { _trackObject = trackObject?.GetLayoutByLayoutId(_object.TrackConfiguration) ?? trackObject; } else { _trackObject = trackObject; } } if (_object?.CarId != null) { _carObject = CarsManager.Instance.GetById(_object.CarId); _carSkinObject = _carObject == null ? null : (_object.CarSkinId != null ? _carObject.SkinsManager.GetById(_object.CarSkinId) : null) ?? _carObject.SelectedSkin; } if (_object?.WeatherId != null) { _weather = WeatherManager.Instance.GetById(_object.WeatherId); } }
// Methods public IEnumerator Start() { // Create a record scene for the record object ReplayScene recordScene = new ReplayScene(recordObject); // Start recording the single object ReplayHandle recordHandle = ReplayManager.BeginRecording(null, recordScene); // Allow some data to be recorded for 1 second yield return(new WaitForSeconds(1f)); // Stop recording ReplayManager.StopRecording(ref recordHandle); // Clone the identity which allows the replayObject to be replayed as the recordObject ReplayObject.CloneReplayObjectIdentity(recordObject, replayObject); // Create a playback scene for the replay object ReplayScene playbackScene = new ReplayScene(replayObject); // Start playback ReplayManager.BeginPlayback(null, playbackScene); }
async Task ILoadableContent.LoadAsync(CancellationToken cancellationToken) { _object = await ReplaysManager.Instance.GetByIdAsync(_id); if (_object?.TrackId != null) { var trackObject = await TracksManager.Instance.GetByIdAsync(_object.TrackId); if (_object.TrackConfiguration != null) { _trackObject = trackObject?.GetLayoutByLayoutId(_object.TrackConfiguration) ?? trackObject; } else { _trackObject = trackObject; } } if (_object?.CarId != null) { _carObject = await CarsManager.Instance.GetByIdAsync(_object.CarId); _carSkinObject = _carObject == null ? null : (_object.CarSkinId != null ? await _carObject.SkinsManager.GetByIdAsync(_object.CarSkinId) : null) ?? _carObject.SelectedSkin; } if (_object?.WeatherId != null) { _weather = await WeatherManager.Instance.GetByIdAsync(_object.WeatherId); } }
/// <summary> /// Unregisters a replay object from the replay system so that it will no longer be recorded for playback. /// Typically all <see cref="ReplayObject"/> will auto un-register when they are destroyed so you will normally not need to un-register a replay object. /// </summary> /// <param name="replayObject"></param> public void UnregisterReplayObject(ReplayObject replayObject) { // Remove the replay object if (replayObjects.Contains(replayObject) == true) { replayObjects.Remove(replayObject); } }
public void RecordInitialReplayObjectData(ReplayObject obj, float timestamp, Vector3 position, Quaternion rotation, Vector3 scale) { // Create the initial data ReplayInitialData data = new ReplayInitialData(); // Store the object identity data.objectIdentity = obj.ReplayIdentity; data.timestamp = timestamp; // Store the transform information data.position = position; data.rotation = rotation; data.scale = scale; // Store the parent identities if (obj.transform.parent != null) { // Get the parent replay object ReplayObject replayParent = obj.transform.parent.GetComponent <ReplayObject>(); // Store parent identity if (replayParent != null) { data.parentIdentity = replayParent.ReplayIdentity; } } // Store observed component identity array int size = obj.ObservedComponentsCount; int index = 0; // Allocate array data.observedComponentIdentities = new ReplayIdentity[size]; foreach (ReplayBehaviour behaviour in obj.ObservedComponents) { // Store component identity in array data.observedComponentIdentities[index] = behaviour.Identity; index++; } // Update stored data flags data.UpdateDataFlags(); // Register the initial data with the corrosponding identity if (initialStates.ContainsKey(obj.ReplayIdentity) == false) { initialStates.Add(obj.ReplayIdentity, new List <ReplayInitialData>()); } // Store the state data initialStates[obj.ReplayIdentity].Add(data); }
// Methods /// <summary> /// Prepare the specified replay object for playback mode. /// </summary> /// <param name="replayObject">The replay object to prepare</param> public virtual void PrepareForPlayback(ReplayObject replayObject) { // Find all components on the object foreach (Component component in replayObject.GetComponentsInChildren <Component>()) { // Make sure the component is still alive if (component == null) { return; } bool skip = false; // Check if the component should be prepared or skipped foreach (Type skipType in skipTypes) { // Check if the component is a skip type or child of if (skipType.IsInstanceOfType(component)) { // Set the skip flag skip = true; break; } } // Check if we should skip the component if (skip == true) { continue; } // Get the component type Type componentType = component.GetType(); // Try to find a preparer ComponentPreparer preparer = FindPreparer(componentType); // Check for error if (preparer == null) { continue; } // Prepare the component preparer.InvokePrepareForPlayback(component); } }
// Methods /// <summary> /// Registers a replay object with the replay system so that it can be recorded for playback. /// Typically all <see cref="ReplayObject"/> will auto register when they 'Awake' meaning that you will not need to manually register objects. /// </summary> /// <param name="replayObject">The <see cref="ReplayObject"/> to register</param> public void RegisterReplayObject(ReplayObject replayObject) { // Add the replay object replayObjects.Add(replayObject); // Check if we are adding objects during playback if (isPlayback == true) { // We need to prepare the object for playback ReplayManager.Preparer.PrepareForPlayback(replayObject); } // Check if we are adding objects during recording else// if(ReplayManager.IsRecording == true) { // The object was added during recording dynamicReplayObjects.Enqueue(replayObject); } }
/// <summary> /// Take a snapshot of the current replay scene using the specified timestamp. /// </summary> /// <param name="timeStamp">The timestamp for the frame indicating its position in the playback sequence</param> /// <param name="initialStateBuffer">The <see cref="ReplayInitialDataBuffer"/> to restore dynamic object information from</param> /// <returns>A new snapshot of the current replay scene</returns> public ReplaySnapshot RecordSnapshot(float timeStamp, ReplayInitialDataBuffer initialStateBuffer) { ReplaySnapshot snapshot = new ReplaySnapshot(timeStamp); if (initialStateBuffer != null) { // Be sure to record any objects initial transform if they were spawned during the snapshot while (dynamicReplayObjects.Count > 0) { // Get the next object ReplayObject obj = dynamicReplayObjects.Dequeue(); // Make sure the object has not been destroyed if (obj != null) { // Record initial values initialStateBuffer.RecordInitialReplayObjectData(obj, timeStamp, obj.transform.position, obj.transform.rotation, obj.transform.localScale); } } } // Record each object in the scene foreach (ReplayObject obj in replayObjects) { ReplayState state = new ReplayState(); // Serialize the object obj.OnReplaySerialize(state); // Check if the state contains any information - If not then dont waste valuable memory if (state.Size == 0) { continue; } // Record the snapshot snapshot.RecordSnapshot(obj.ReplayIdentity, state); } return(snapshot); }
public void OnTriggerEnter(Collider other) { Debug.LogWarning("Trigger"); // Stop replaying if (ReplayManager.IsReplaying(playbackHandle) == true) { ReplayManager.StopPlayback(ref playbackHandle); } // Stop recording if (ReplayManager.IsRecording(recordHandle) == true) { // Stop recording ReplayManager.StopRecording(ref recordHandle); playbackStorage = recordStorage; recordStorage = new ReplayMemoryTarget(); Debug.Log("Recording Length: " + playbackStorage.Duration); // Enable the ghost car ghostCar.gameObject.SetActive(true); // Clone identities - This allows the ghost car to be replayed as the player car ReplayObject.CloneReplayObjectIdentity(playerCar, ghostCar); // Start replaying playbackHandle = ReplayManager.BeginPlayback(playbackStorage, playbackScene); // Add end playback listener ReplayManager.AddPlaybackEndListener(playbackHandle, OnGhostVehiclePlaybackComplete); } // Start recording recordHandle = ReplayManager.BeginRecording(recordStorage, recordScene); }
public IEnumerator StartAlternative() { // Create a replay scene from the active Unity scene ReplayScene recordScene = ReplayScene.FromCurrentScene(); // Start recording ReplayHandle recordHandle = ReplayManager.BeginRecording(null, recordScene); // Wait for some time to pass yield return(new WaitForSeconds(1f)); // Spawn a dynamic replay object ReplayObject obj = Instantiate(instanitatePrefab); // Add the object to the record scene only - This is a required step otherwise the object will not be recorded recordScene.AddReplayObject(obj); // Wait for some time to pass now that the object has been spawned yield return(new WaitForSeconds(1)); // End recording // The resulting replay will have 1 second of nothing and then the dynamic object will be re-instantiated by the replay system ReplayManager.StopRecording(ref recordHandle); }
private void DisplayPrefabErrors() { // Get the manager ReplayManager manager = target as ReplayManager; // Get the list of game objects GameObject[] prefabs = manager.prefabs; List <GameObject> replayErrors = new List <GameObject>(); List <GameObject> prefabErrors = new List <GameObject>(); foreach (GameObject go in prefabs) { // Check for null (Are allowed) if (go == null) { continue; } // Try to get component ReplayObject obj = go.GetComponent <ReplayObject>(); // Check for error if (obj == null) { // Mark an error replayErrors.Add(go); continue; } // Check for prefab if (obj.IsPrefab == false) { // Mark a prefab error prefabErrors.Add(go); } } // Display a help box if (replayErrors.Count > 0) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < replayErrors.Count; i++) { // Use the name in the error builder.Append(replayErrors[i].name); // There are more errors left if (i < replayErrors.Count - 1) { builder.Append(", "); } } // Display a help box EditorGUILayout.HelpBox(string.Format("The following prefabs do not have ReplayObject scripts attached and will be ignored at runtime: {0}", builder.ToString()), MessageType.Error); } // Display a help box if (prefabErrors.Count > 0) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < prefabErrors.Count; i++) { // Use the name in the error builder.Append(prefabErrors[i].name); // There are more errors left if (i < prefabErrors.Count - 1) { builder.Append(", "); } } // Display a help box EditorGUILayout.HelpBox(string.Format("The following replay prefabs are not prefab assets and will be ignored at runtime: {0}. Make sure scene prefab instances are not registered", builder.ToString()), MessageType.Error); } }
/// <summary> /// Attempts to restore any replay objects that were spawned or despawned during this snapshot. /// </summary> public void RestoreReplayObjects(ReplayScene scene, ReplayInitialDataBuffer initialStateBuffer) { // Get all active scene objects List <ReplayObject> activeReplayObjects = scene.ActiveReplayObjects; // Find all active replay objects foreach (ReplayObject obj in activeReplayObjects) { // Check if the object is no longer in the scene if (states.ContainsKey(obj.ReplayIdentity) == false) { // Check for a prefab if (obj.IsPrefab == false) { continue; } // We need to destroy the replay object sharedDestroyQueue.Enqueue(obj); } } // Destroy all waiting objects while (sharedDestroyQueue.Count > 0) { ReplayManager.ReplayDestroy(sharedDestroyQueue.Dequeue().gameObject); } // Process all snapshot state data to check if we need to add any scene objects foreach (KeyValuePair <ReplayIdentity, ReplayState> replayObject in states) { bool found = false; // Check if the desiered object is active in the scene foreach (ReplayObject obj in activeReplayObjects) { // Check for matching identity if (obj.ReplayIdentity == replayObject.Key) { // The object is in the scene - do nothing found = true; break; } } // We need to spawn the object if (found == false) { // Get the replay state for the object because it contains the prefab information we need ReplayState state = replayObject.Value; // Reset the state for reading state.PrepareForRead(); // Read the name of the prefab that we need to spawn string name = state.ReadString(); // Try to find the matching prefab in our replay manager GameObject prefab = ReplayManager.FindReplayPrefab(name); // Check if the prefab was found if (prefab == null) { // Check for no prefab name if (string.IsNullOrEmpty(name) == true) { // Name information is unknown name = "Unkwnown Replay Object (" + replayObject.Key + ")"; // Display scene object warning Debug.LogWarning(string.Format("Failed to recreate replay scene object '{0}'. The object could not be found within the current scene and it is not a registered replay prefab. You may need to reload the scene before playback to ensure that all recorded objects are present.", name)); } else { // Display prefab object warning Debug.LogWarning(string.Format("Failed to recreate replay prefab '{0}'. No such prefab is registered.", name)); } continue; } // Restore initial data ReplayInitialData initialData = new ReplayInitialData(); // Check for valid state buffer if (initialStateBuffer != null && initialStateBuffer.HasInitialReplayObjectData(replayObject.Key) == true) { // Restore the objects state data initialData = initialStateBuffer.RestoreInitialReplayObjectData(replayObject.Key, timeStamp);// RestoreInitialReplayObjectData(replayObject.Key); } Vector3 position = Vector3.zero; Quaternion rotation = Quaternion.identity; Vector3 scale = Vector3.one; // Update transform values if ((initialData.InitialFlags & ReplayInitialDataFlags.Position) != 0) { position = initialData.position; } if ((initialData.InitialFlags & ReplayInitialDataFlags.Rotation) != 0) { rotation = initialData.rotation; } if ((initialData.InitialFlags & ReplayInitialDataFlags.Scale) != 0) { scale = initialData.scale; } // Call the instantiate method GameObject result = ReplayManager.ReplayInstantiate(prefab, position, rotation); if (result == null) { Debug.LogWarning(string.Format("Replay instanitate failed for prefab '{0}'. Some replay objects may be missing", name)); continue; } // Be sure to apply initial scale also result.transform.localScale = scale; // try to find the replay object script ReplayObject obj = result.GetComponent <ReplayObject>(); // Check if we have the component if (obj != null) { // Give the replay object its serialized identity so that we can send replay data to it obj.ReplayIdentity = replayObject.Key; // Map observed component identities if (initialData.observedComponentIdentities != null) { int index = 0; foreach (ReplayBehaviour behaviour in obj.ObservedComponents) { if (initialData.observedComponentIdentities.Length > index) { behaviour.Identity = initialData.observedComponentIdentities[index]; } index++; } } // Register the created object newReplayObjectsThisFrame.Add(new ReplayCreatedObject { replayObject = obj, replayInitialData = initialData, }); // Trigger spawned event ReplayBehaviour.Events.CallReplaySpawnedEvents(obj, position, rotation); } } } // Re-parent replay objects foreach (ReplayCreatedObject created in newReplayObjectsThisFrame) { // Check for a parent identity if (created.replayInitialData.parentIdentity != null) { bool foundTargetParent = false; // We need to find the references parent foreach (ReplayObject obj in scene.ActiveReplayObjects) { if (obj.ReplayIdentity == created.replayInitialData.parentIdentity) { // Parent the objects created.replayObject.transform.SetParent(obj.transform, false); // Set the flag foundTargetParent = true; break; } } // Check if we failed to find the parent object if (foundTargetParent == false) { // The target parent object is missing Debug.LogWarning(string.Format("Newly created replay object '{0}' references identity '{1}' as a transform parent but the object could not be found in the current scene. Has the target parent been deleted this frame?", created.replayObject.name, created.replayInitialData.parentIdentity)); } } } // Clear ll tracked replay objects this frame newReplayObjectsThisFrame.Clear(); }