void DetectChangedAssets()
        {
            if (_UsedAssetsTargetHash.Count == 0)
            {
                TimeBasedCallbackInvoker.ClearCallback(DetectChangedAssets);
                return;
            }

            var changedAssets = new NativeList <ResolvedAssetID>(Allocator.Temp);
            var buildTarget   = EditorUserBuildSettings.activeBuildTarget;

            foreach (var asset in _UsedAssetsTargetHash)
            {
                //@TODO: Artifact hash API should give error message when used on V1 pipeline (currently does not).

                var targetHash = LiveLinkBuildPipeline.CalculateTargetHash(asset.Key, buildTarget);

                if (asset.Value != targetHash)
                {
                    var path = AssetDatabase.GUIDToAssetPath(asset.Key.ToString());
                    LiveLinkMsg.LogInfo("Detected asset change: " + path);
                    changedAssets.Add(new ResolvedAssetID {
                        GUID = asset.Key, TargetHash = targetHash
                    });

                    LiveLinkBuildPipeline.CalculateTargetDependencies(asset.Key, buildTarget, out ResolvedAssetID[] dependencies);
                    foreach (var dependency in dependencies)
                    {
                        if (_UsedAssetsTargetHash.ContainsKey(dependency.GUID))
                        {
                            continue;
                        }

                        // New Dependency
                        var dependencyHash = LiveLinkBuildPipeline.CalculateTargetHash(dependency.GUID, buildTarget);
                        changedAssets.Add(new ResolvedAssetID {
                            GUID = dependency.GUID, TargetHash = dependencyHash
                        });
                    }
                }
            }

            if (changedAssets.Length != 0)
            {
                SendAssetBundleTargetHash(changedAssets, 0);
            }
        }
        void DetectSceneChanges()
        {
            if (_Connections.Count == 0)
            {
                TimeBasedCallbackInvoker.ClearCallback(DetectSceneChanges);
                LiveLinkAssetBundleBuildSystem.instance.ClearTrackedAssets();
                return;
            }

            foreach (var c in _Connections)
            {
                var connection = c.Value;
                if (!connection._IsEnabled)
                {
                    continue;
                }

                try
                {
                    connection.Update(_ChangeSets, _LoadScenes, _UnloadScenes, LiveLinkMode.LiveConvertStandalonePlayer);

                    // Load scenes that are not being edited live
                    SendLoadScenes(_LoadScenes.AsArray(), c.Key);
                    // Unload scenes that are no longer being edited / need to be reloaded etc
                    SendUnloadScenes(_UnloadScenes.AsArray(), c.Key);

                    // Apply changes to scenes that are being edited
                    foreach (var change in _ChangeSets)
                    {
                        SendChangeSet(change, c.Key);
                        change.Dispose();
                    }
                }
                finally
                {
                    _ChangeSets.Clear();
                    _UnloadScenes.Clear();
                    _LoadScenes.Clear();
                }
            }
        }