/// <summary> /// Applies data state changes to the entity. /// </summary> /// <remarks> /// This function is not thread-safe; no other API calls can be made to the Entity while /// this function is being executed. /// </remarks> /// <returns>If more data state change updates are needed</returns> public void DataStateChangeUpdate() { // do removals { for (int i = 0; i < _toRemoveStage1.Count; ++i) { int id = _toRemoveStage1[i].Id; _removedLastFrame[id] = _toRemoveStage1[i]; // _removedLastFrame[id] is removed in stage2 _eventDispatcher.Submit(RemovedDataEvent.Create(this, DataAccessorFactory.GetTypeFromId(id))); } for (int i = 0; i < _toRemoveStage2.Count; ++i) { int id = _toRemoveStage2[i].Id; _removedLastFrame.Remove(id); _data.Remove(id); } _toRemoveStage2.Clear(); Utils.Swap(ref _toRemoveStage1, ref _toRemoveStage2); } // We don't throw an exception immediately. If we are throwing an exception, that means // that the Entity is in an invalid state (adding a bad data instance). However, the // only way to recover from that invalid state is by having this method terminate. // Hence, we only throw an exception at the end of the method. Exception exceptionToThrow = null; // do additions for (int i = 0; i < _toAddStage1.Count; ++i) { Data.IData added = _toAddStage1[i]; int id = DataAccessorFactory.GetId(added.GetType()); // make sure we do not readd the same data instance twice if (_data.ContainsKey(id)) { exceptionToThrow = new AlreadyAddedDataException(this, new DataAccessor(added)); continue; } _addedLastFrame[id] = added; if (added is Data.IVersioned) { Data.IVersioned versioned = (Data.IVersioned)added; _data[id] = new VersionedDataContainer(versioned.Duplicate(), versioned.Duplicate(), versioned.Duplicate()); } else { Data.NonVersioned nonVersioned = (Data.NonVersioned)added; _data[id] = new NonVersionedDataContainer(nonVersioned); } // visualize the initial data _eventDispatcher.Submit(AddedDataEvent.Create(this, added.GetType())); } for (int i = 0; i < _toAddStage2.Count; ++i) { _addedLastFrame.Remove(new DataAccessor(_toAddStage2[i]).Id); } _toAddStage2.Clear(); Utils.Swap(ref _toAddStage1, ref _toAddStage2); if (exceptionToThrow != null) { throw exceptionToThrow; } }
public ContentEntitySerializationFormat GetSerializedFormat() { List <ContentEntity.DataInstance> data = new List <ContentEntity.DataInstance>(); // the data instances that have been modified in the current update HashSet <int> modifiedThisFrame = new HashSet <int>(); { List <DataAccessor> modifications = _concurrentModifications.ToList(); foreach (DataAccessor modification in modifications) { modifiedThisFrame.Add(modification.Id); } } // the data instances that have been removed in the current update HashSet <int> removedThisFrame = new HashSet <int>(); { foreach (DataAccessor item in _toRemoveStage1) { removedThisFrame.Add(item.Id); } } foreach (KeyValuePair <int, DataContainer> tuple in _data) { DataAccessor accessor = new DataAccessor(tuple.Key); // If the data was removed this frame, then next frame it won't exist anymore, so we // don't serialize it if (WasRemoved(accessor)) { continue; } var dataInstance = new ContentEntity.DataInstance() { // these items are never added this frame; if WasAdded is true now, it will be // false next frame WasAdded = false, // the data *may* have been removed this frame, though WasRemoved = removedThisFrame.Contains(accessor.Id) }; // if we were modified this frame, then we have to do a data swap (and set // WasModified to true) if (modifiedThisFrame.Contains(accessor.Id)) { // do a data swap so our modified data is correct if (_data[accessor.Id] is VersionedDataContainer) { VersionedDataContainer container = (VersionedDataContainer)_data[accessor.Id]; dataInstance.CurrentData = container.Modifying; dataInstance.PreviousData = container.Current; } else { NonVersionedDataContainer container = (NonVersionedDataContainer)_data[accessor.Id]; dataInstance.CurrentData = container.Data; } dataInstance.WasModified = true; } // we were not modified this frame, so don't perform a data swap else { // do a data swap so our modified data is correct if (_data[accessor.Id] is VersionedDataContainer) { VersionedDataContainer container = (VersionedDataContainer)_data[accessor.Id]; dataInstance.CurrentData = container.Current; dataInstance.PreviousData = container.Previous; } else { NonVersionedDataContainer container = (NonVersionedDataContainer)_data[accessor.Id]; dataInstance.CurrentData = container.Data; } dataInstance.WasModified = false; } data.Add(dataInstance); } foreach (var toAdd in _toAddStage1) { data.Add(new ContentEntity.DataInstance() { CurrentData = toAdd, PreviousData = toAdd, WasAdded = true, // added data is never modified WasModified = false, // added data also cannot be removed in the same frame it was added in WasRemoved = false }); } return(new ContentEntitySerializationFormat() { PrettyName = PrettyName, UniqueId = UniqueId, Data = data }); }