/// <summary>
        ///     Iterate over the op list and populate a ViewDiff from the data contained.
        /// </summary>
        /// <returns>True if the current ViewDiff is inside a critical section.</returns>
        public bool ParseOpListIntoDiff(OpList opList, CommandMetaDataAggregate commandMetaData)
        {
            if (shouldClear)
            {
                viewDiff.Clear();
                shouldClear = false;
            }

            var netStats = viewDiff.GetNetStats();

            for (var i = 0; i < opList.GetOpCount(); ++i)
            {
                switch (opList.GetOpType(i))
                {
                case OpType.Disconnect:
                    viewDiff.Disconnect(opList.GetDisconnectOp(i).Reason);
                    break;

                case OpType.FlagUpdate:
                    var flagOp = opList.GetFlagUpdateOp(i);
                    viewDiff.SetWorkerFlag(flagOp.Name, flagOp.Value);
                    break;

                case OpType.LogMessage:
                    var logOp = opList.GetLogMessageOp(i);
                    viewDiff.AddLogMessage(logOp.Message, logOp.Level);
                    break;

                case OpType.Metrics:
                    var metricsOp = opList.GetMetricsOp(i);
                    viewDiff.AddMetrics(metricsOp.Metrics);
                    break;

                case OpType.CriticalSection:
                    var criticalSectionOp = opList.GetCriticalSectionOp(i);
                    viewDiff.SetCriticalSection(criticalSectionOp.InCriticalSection);
                    break;

                case OpType.AddEntity:
                    viewDiff.AddEntity(opList.GetAddEntityOp(i).EntityId);
                    break;

                case OpType.RemoveEntity:
                    viewDiff.RemoveEntity(opList.GetRemoveEntityOp(i).EntityId);
                    break;

                case OpType.ReserveEntityIdsResponse:
                    var reserveEntityIdsOp = opList.GetReserveEntityIdsResponseOp(i);
                    ComponentOpDeserializer.ApplyReserveEntityIdsResponse(reserveEntityIdsOp, viewDiff,
                                                                          commandMetaData);
                    netStats.AddWorldCommandResponse(WorldCommand.ReserveEntityIds);
                    break;

                case OpType.CreateEntityResponse:
                    var createEntityOp = opList.GetCreateEntityResponseOp(i);
                    ComponentOpDeserializer.ApplyCreateEntityResponse(createEntityOp, viewDiff, commandMetaData);
                    netStats.AddWorldCommandResponse(WorldCommand.CreateEntity);
                    break;

                case OpType.DeleteEntityResponse:
                    var deleteEntityOp = opList.GetDeleteEntityResponseOp(i);
                    ComponentOpDeserializer.ApplyDeleteEntityResponse(deleteEntityOp, viewDiff, commandMetaData);
                    netStats.AddWorldCommandResponse(WorldCommand.DeleteEntity);
                    break;

                case OpType.EntityQueryResponse:
                    var entityQueryOp = opList.GetEntityQueryResponseOp(i);
                    ComponentOpDeserializer.ApplyEntityQueryResponse(entityQueryOp, viewDiff, commandMetaData);
                    netStats.AddWorldCommandResponse(WorldCommand.EntityQuery);
                    break;

                case OpType.AddComponent:
                    ComponentOpDeserializer.DeserializeAndAddComponent(opList.GetAddComponentOp(i), viewDiff);
                    break;

                case OpType.RemoveComponent:
                    var removeComponentOp = opList.GetRemoveComponentOp(i);
                    viewDiff.RemoveComponent(removeComponentOp.EntityId, removeComponentOp.ComponentId);
                    break;

                case OpType.AuthorityChange:
                    var authorityOp = opList.GetAuthorityChangeOp(i);
                    viewDiff.SetAuthority(authorityOp.EntityId, authorityOp.ComponentId, authorityOp.Authority);
                    break;

                case OpType.ComponentUpdate:
                    var updateOp = opList.GetComponentUpdateOp(i);
                    ComponentOpDeserializer.DeserializeAndApplyComponentUpdate(updateOp, viewDiff,
                                                                               componentUpdateId);
                    ++componentUpdateId;
                    netStats.AddUpdate(updateOp.Update);
                    break;

                case OpType.CommandRequest:
                    var commandRequestOp = opList.GetCommandRequestOp(i);
                    ComponentOpDeserializer.DeserializeAndApplyCommandRequestReceived(commandRequestOp, viewDiff);
                    netStats.AddCommandRequest(commandRequestOp.Request);
                    break;

                case OpType.CommandResponse:
                    var commandResponseOp = opList.GetCommandResponseOp(i);
                    ComponentOpDeserializer.DeserializeAndApplyCommandResponseReceived(
                        commandResponseOp, viewDiff, commandMetaData);
                    netStats.AddCommandResponse(commandResponseOp.Response, commandResponseOp.Message);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(
                              $"Can not deserialise unkown op type {opList.GetOpType(i)}");
                }
            }

            return(viewDiff.InCriticalSection);
        }
        /// <summary>
        ///     Iterate over the op list and populate a ViewDiff from the data contained.
        ///     Must not be called again before it returns.
        /// </summary>
        public void ParseOpListIntoDiff(OpList opList, CommandMetaDataAggregate commandMetaData)
        {
            lock (viewLock)
            {
                for (int i = 0; i < opList.GetOpCount(); ++i)
                {
                    switch (opList.GetOpType(i))
                    {
                    case OpType.Disconnect:
                        DeserializationDiff.Disconnect(opList.GetDisconnectOp(i).Reason);
                        break;

                    case OpType.FlagUpdate:
                        var flagOp = opList.GetFlagUpdateOp(i);
                        break;

                    case OpType.LogMessage:
                        var logOp = opList.GetLogMessageOp(i);
                        DeserializationDiff.AddLogMessage(logOp.Message, logOp.Level);
                        break;

                    case OpType.Metrics:
                        var metricsOp = opList.GetMetricsOp(i);
                        DeserializationDiff.AddMetrics(metricsOp.Metrics);
                        break;

                    case OpType.CriticalSection:
                        var criticalSectionOp = opList.GetCriticalSectionOp(i);
                        DeserializationDiff.SetCriticalSection(criticalSectionOp.InCriticalSection);
                        break;

                    case OpType.AddEntity:
                        DeserializationDiff.AddEntity(opList.GetAddEntityOp(i).EntityId);
                        break;

                    case OpType.RemoveEntity:
                        DeserializationDiff.RemoveEntity(opList.GetRemoveEntityOp(i).EntityId);
                        break;

                    case OpType.ReserveEntityIdsResponse:
                        var reserveEntityIdsOp = opList.GetReserveEntityIdsResponseOp(i);
                        ComponentOpDeserializer.ApplyReserveEntityIdsResponse(reserveEntityIdsOp,
                                                                              DeserializationDiff,
                                                                              commandMetaData);
                        break;

                    case OpType.CreateEntityResponse:
                        var createEntityOp = opList.GetCreateEntityResponseOp(i);
                        ComponentOpDeserializer.ApplyCreateEntityResponse(createEntityOp, DeserializationDiff,
                                                                          commandMetaData);
                        break;

                    case OpType.DeleteEntityResponse:
                        var deleteEntityOp = opList.GetDeleteEntityResponseOp(i);
                        ComponentOpDeserializer.ApplyDeleteEntityResponse(deleteEntityOp, DeserializationDiff,
                                                                          commandMetaData);
                        break;

                    case OpType.EntityQueryResponse:
                        var entityQueryOp = opList.GetEntityQueryResponseOp(i);
                        ComponentOpDeserializer.ApplyEntityQueryResponse(entityQueryOp, DeserializationDiff,
                                                                         commandMetaData);
                        break;

                    case OpType.AddComponent:
                        ComponentOpDeserializer.DeserializeAndAddComponent(opList.GetAddComponentOp(i),
                                                                           DeserializationDiff);
                        break;

                    case OpType.RemoveComponent:
                        var removeComponentOp = opList.GetRemoveComponentOp(i);
                        DeserializationDiff.RemoveComponent(removeComponentOp.EntityId,
                                                            removeComponentOp.ComponentId);
                        break;

                    case OpType.AuthorityChange:
                        var authorityOp = opList.GetAuthorityChangeOp(i);
                        DeserializationDiff.SetAuthority(authorityOp.EntityId, authorityOp.ComponentId,
                                                         authorityOp.Authority);
                        break;

                    case OpType.ComponentUpdate:
                        ComponentOpDeserializer.DeserializeAndApplyComponentUpdate(opList.GetComponentUpdateOp(i),
                                                                                   DeserializationDiff, componentUpdateId);
                        ++componentUpdateId;
                        break;

                    case OpType.CommandRequest:
                        ComponentOpDeserializer.DeserializeAndApplyCommandRequestReceived(
                            opList.GetCommandRequestOp(i),
                            DeserializationDiff);
                        break;

                    case OpType.CommandResponse:
                        ComponentOpDeserializer.DeserializeAndApplyCommandResponseReceived(
                            opList.GetCommandResponseOp(i), DeserializationDiff,
                            commandMetaData);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(
                                  $"Can not deserialise unkown op type {opList.GetOpType(i)}");
                    }
                }
            }
        }