protected override void Update(TimeStruct timeStruct)
                {
                    switch (Status)
                    {
                    case ResourceCacheStatus.Loading:
                        if (!string.IsNullOrEmpty(m_LoadingTask.ErrorMessage))
                        {
                            ErrorMessage = m_LoadingTask.ErrorMessage;

                            InternalLog.DebugFormat("[ResourceCache Update] {0} loading fail", Path);
                            FailAndNotify();
                        }
                        else if (m_LoadingTask.IsDone)
                        {
                            ResourceObject = m_LoadingTask.ResourceObject;

                            InternalLog.DebugFormat("[ResourceCache Update] {0} loading success", Path);
                            SucceedAndNotify();
                        }

                        break;

                    default:
                        break;
                    }
                }
        private void OnSendCompleted(object sender, SocketAsyncEventArgs e)
        {
            foreach (var packet in m_PacketsToSendList)
            {
                Handler.OnRecycle(packet);
            }

            // Sending failed.
            if (e.SocketError != SocketError.Success)
            {
                InternalLog.DebugFormat("[TcpChannel OnSendCompleted] Failure, SocketError={0}.", e.SocketError);
                Close();
                OnError("Sending data failed. Error data is a SocketError.", e.SocketError);
                return;
            }

            InternalLog.DebugFormat("[TcpChannel OnSendCompleted] Success, bytesTransferred={0}.", e.BytesTransferred);
            lock (m_PacketsToSend)
            {
                if (m_PacketsToSend.Count <= 0)
                {
                    Interlocked.Exchange(ref m_IsSending, 0);
                    return;
                }

                CopyPacketsToSend();
            }

            DoSend();
        }
                internal override void Init()
                {
                    InternalLog.DebugFormat("[AssetCache Init] {0}", Path);
                    m_LastLoadingProgress = 0f;
                    Owner.m_AssetPathsNotReadyOrFailure.Add(Path);
                    var resourceCache = Owner.EnsureResourceCache(ResourcePath);

                    resourceCache.IncreaseRetainCount();

                    if (DependencyAssetPaths.Count <= 0)
                    {
                        InternalLog.DebugFormat("[AssetCache Init] {0} no dep. observe resource.", Path);
                        Status = AssetCacheStatus.WaitingForResource;

                        resourceCache.AddObserver(this);
                        return;
                    }

                    Status = AssetCacheStatus.WaitingForDeps;

                    foreach (var depAssetPath in DependencyAssetPaths)
                    {
                        var depAssetCache = Owner.EnsureAssetCache(depAssetPath);
                        depAssetCache.IncreaseRetainCount();
                        depAssetCache.AddObserver(this);
                    }

                    DFSAddResourceRetainCounts(resourceCache);
                }
                protected override void Update(TimeStruct timeStruct)
                {
                    switch (Status)
                    {
                    case AssetCacheStatus.Loading:
                        if (!string.IsNullOrEmpty(m_LoadingTask.ErrorMessage))
                        {
                            ErrorMessage = m_LoadingTask.ErrorMessage;
                            InternalLog.DebugFormat("[AssetCache Update] {0} loading fail.", Path);
                            FailAndNotify();
                        }
                        else if (m_LoadingTask.IsDone)
                        {
                            AssetObject = m_LoadingTask.AssetObject;
                            InternalLog.DebugFormat("[AssetCache Update] {0} loading success.", Path);
                            SucceedAndNotify();
                        }
                        else
                        {
                            if (LoadingProgress != m_LastLoadingProgress)
                            {
                                m_LastLoadingProgress = LoadingProgress;
                                ProgressAndNotify();
                            }
                        }

                        break;
                    }
                }
 internal override void Init()
 {
     InternalLog.DebugFormat("[ResourceCache Reuse] {0}", Path);
     Owner.m_ResourcePathsNotReadyOrFailure.Add(Path);
     Status = ResourceCacheStatus.WaitingForSlot;
     Owner.m_WaitingForSlotResourceCaches.Add(this);
 }
                internal virtual void ReduceRetainCount()
                {
                    if (m_RetainCount <= 0)
                    {
                        throw new InvalidOperationException(Utility.Text.Format("Reducing retain count to negative, on '{0}' ({1}).", Path,
                                                                                GetType().Name));
                    }

                    --m_RetainCount;
                    InternalLog.DebugFormat("[{0} ReduceRetainCount] '{2}' to {1}", GetType().Name, m_RetainCount, Path);
                }
                internal override void OnSlotReady()
                {
                    if (Status != ResourceCacheStatus.WaitingForSlot)
                    {
                        throw new InvalidOperationException($"Oops! '{nameof(OnSlotReady)}' cannot be called on status '{Status}'.");
                    }

                    m_LoadingTask = Owner.RunResourceLoadingTask(Path,
                                                                 ShouldLoadFromReadWritePath ? Owner.ReadWritePath : Owner.InstallerPath);
                    InternalLog.DebugFormat("[ResourceCache Update] {0} start loading", Path);
                    Status = ResourceCacheStatus.Loading;
                    StartTicking();
                }
                internal override void Reset()
                {
                    InternalLog.DebugFormat("[AssetCache Reset] {0}", Path);
                    m_CopiedAssetObservers.Clear();
                    m_AssetObservers.Clear();
                    m_CopiedAssetAccessors.Clear();
                    m_AssetAccessors.Clear();
                    StopTicking();
                    StopAndResetLoadingTask();
                    AssetObject = null;

                    foreach (var depAssetPath in DependencyAssetPaths)
                    {
                        var depAssetCache = Owner.EnsureAssetCache(depAssetPath);
                        depAssetCache.RemoveObserver(this);
                        depAssetCache.ReduceRetainCount();
                    }

                    var resourceCache = Owner.EnsureResourceCache(ResourcePath);

                    resourceCache.RemoveObserver(this);
                    resourceCache.ReduceRetainCount();

                    foreach (var dependencyResourcePath in m_DependencyResourcePaths)
                    {
                        var dependencyResourceCache = Owner.m_ResourceCaches[dependencyResourcePath];
#if DEBUG
                        if (dependencyResourceCache.Status == ResourceCacheStatus.None)
                        {
                            throw new InvalidOperationException($"Resource cache of path [{dependencyResourcePath}] is invalid.");
                        }
#endif
                        dependencyResourceCache.ReduceRetainCount();
                    }

                    m_DependencyResourcePaths.Clear();

                    DependencyAssetPaths = null;
                    Status = AssetCacheStatus.None;
                    Owner.m_AssetPathsNotReadyOrFailure.Remove(Path);
                    m_DependencyAssetReadyCount = 0;
                    ResourcePath          = null;
                    IsScene               = false;
                    m_LastLoadingProgress = 0;
                    base.Reset();
                }
 public void AddObserver(AssetCache resourceObserver)
 {
     if (Status == ResourceCacheStatus.Ready)
     {
         InternalLog.DebugFormat("[ResourceCache AddObserver] Path={0}, AssetPath={1} direct success", Path,
                                 resourceObserver.Path);
         resourceObserver.OnLoadResourceSuccess(Path, ResourceObject);
     }
     else if (Status == ResourceCacheStatus.Failure)
     {
         InternalLog.DebugFormat("[ResourceCache AddObserver] Path={0}, AssetPath={1} direct fail", Path, resourceObserver.Path);
         resourceObserver.OnLoadResourceFailure(Path, ErrorMessage);
     }
     else
     {
         m_ResourceObservers.Add(resourceObserver);
     }
 }
                internal override void OnSlotReady()
                {
                    if (Status != AssetCacheStatus.WaitingForSlot)
                    {
                        throw new InvalidOperationException($"Oops! '{nameof(OnSlotReady)}' cannot be called on status '{Status}'.");
                    }

                    if (IsScene)
                    {
                        SucceedAndNotify();
                    }
                    else
                    {
                        m_LoadingTask = Owner.RunAssetLoadingTask(Path, Owner.EnsureResourceCache(ResourcePath).ResourceObject);
                        InternalLog.DebugFormat("[AssetCache Update] {0} start loading.", Path);
                        Status = AssetCacheStatus.Loading;
                        StartTicking();
                    }
                }
                internal override void Reset()
                {
                    InternalLog.DebugFormat("[ResourceCache Reset] {0}", Path);

                    m_CopiedResourceObservers.Clear();
                    m_ResourceObservers.Clear();

                    StopTicking();
                    StopAndResetLoadingTask();

                    if (ResourceObject != null)
                    {
                        Owner.ResourceDestroyer.Destroy(ResourceObject);
                    }

                    ResourceObject = null;
                    ShouldLoadFromReadWritePath = false;
                    Status = ResourceCacheStatus.None;
                    Owner.m_ResourcePathsNotReadyOrFailure.Remove(Path);
                    base.Reset();
                }
        private void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
        {
            InternalLog.DebugFormat("[TcpChannel OnReceiveCompleted] socket error is '{0}', bytes transffered is {1}.",
                                    e.SocketError, e.BytesTransferred);

            // Receiving failed.
            if (e.SocketError != SocketError.Success)
            {
                Close();
                OnError("Receiving data failed. Error data is a SocketError.", e.SocketError);
                return;
            }

            // Server stops this connection.
            if (e.BytesTransferred == 0)
            {
                Close();
                OnError("Server stops this connection.", null);
                return;
            }

            // Receiving succeeded.
            m_ReceiveStream.Write(m_ReceiveBuffer, 0, e.BytesTransferred);
            long length = m_ReceiveStream.Position;

            m_ReceiveStream.Position = 0;

            while (m_ReceiveStream.Position < length)
            {
                if (m_CurrentPacketHeader == null) // Should read the next packet header.
                {
                    // Packet header has not been completed received.
                    if (length - m_ReceiveStream.Position < ReceivePacketHeaderLength)
                    {
                        break;
                    }

                    // Read the packet header.
                    m_CurrentPacketHeader = Handler.DeserializePacketHeader(m_ReceiveStream);
                }
                else // Should read the next packet body.
                {
                    // Current packet has not been completely received.
                    if (length - m_ReceiveStream.Position < m_CurrentPacketHeader.PacketLength)
                    {
                        break;
                    }

                    {
                        var packetHeader = m_CurrentPacketHeader;
                        m_CurrentPacketHeader = null;
                        var packet = Handler.Deserialize(packetHeader, m_ReceiveStream);
                        lock (m_PacketsToReceive)
                        {
                            m_PacketsToReceive.Enqueue(packet);
                        }
                    }
                }
            }

            var underlyingBuffer = m_ReceiveStream.GetBuffer();

            Buffer.BlockCopy(underlyingBuffer, (int)m_ReceiveStream.Position, underlyingBuffer, 0,
                             (int)(length - m_ReceiveStream.Position));
            m_ReceiveStream.Position = length - m_ReceiveStream.Position;

            if (m_State != NetChannelState.Connected)
            {
                return;
            }

            Receive();
        }
 internal virtual void IncreaseRetainCount()
 {
     m_RetainCount++;
     InternalLog.DebugFormat("[{0} IncreaseRetainCount] '{2}' to {1}", GetType().Name, m_RetainCount, Path);
 }