public void OnReplayDeserialize(ReplayState state) { int size = state.Read32(); for (int i = 0; i < size; i++) { // Read the target identity ReplayIdentity identity = state.ReadIdentity(); int localSize = state.Read32(); // Read all states for (int j = 0; j < localSize; j++) { // Create empty data container ReplayInitialData data = new ReplayInitialData(); // Deserialize data data.OnReplayDeserialize(state); // Register state if (initialStates.ContainsKey(identity) == false) { initialStates.Add(identity, new List <ReplayInitialData>()); } initialStates[identity].Add(data); } } }
public ReplayInitialData RestoreInitialReplayObjectData(ReplayIdentity identity, float timestamp) { // Create an error return value ReplayInitialData data = new ReplayInitialData { objectIdentity = identity, timestamp = timestamp, position = Vector3.zero, rotation = Quaternion.identity, scale = Vector3.one, parentIdentity = null, observedComponentIdentities = null, }; // Check for existing object identity if (initialStates.ContainsKey(identity) == true) { // Get the state data List <ReplayInitialData> states = initialStates[identity]; // Check for any states if (states.Count > 0) { // Check for trivial case if (states.Count == 1) { return(states[0]); } int index = -1; float smallestDifference = float.MaxValue; // Find the best matching time stamp for (int i = 0; i < states.Count; i++) { // Get timestamp difference float timeDifference = Mathf.Abs(timestamp - states[i].timestamp); // Check for smaller difference if (timeDifference < smallestDifference) { // We have a new smallest time difference so make that the new target to beat index = i; smallestDifference = timeDifference; } } // Check for valid index if (index != -1) { // Use the state data at the best index match data = states[index]; } } } return(data); }
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); }
/// <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(); }