void ConnectLiveLink(MessageEventArgs args) { LiveLinkMsg.LogReceived("ConnectLiveLink"); int player = args.playerId; var buildConfigurationGuid = args.Receive <Hash128>(); //@TODO: Implement this properly //system.World.GetExistingSystem<EditorSubSceneLiveLinkSystem>().CleanupAllScenes(); //@TODO: How does this work with multiple connections? LiveLinkAssetBundleBuildSystem.instance.ClearTrackedAssets(); if (_Connections.TryGetValue(player, out var connection)) { connection.Dispose(); } var newConnection = new LiveLinkConnection(buildConfigurationGuid); _Connections[player] = newConnection; using (var scenes = newConnection.GetInitialScenes(player, Allocator.Temp)) m_Connection.SendArray(LiveLinkMsg.EditorResponseConnectLiveLink, scenes, player); TimeBasedCallbackInvoker.SetCallback(DetectSceneChanges); EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); LiveLinkPlayerConnected?.Invoke(player, newConnection._BuildConfigurationGUID); }
void ConnectLiveLink(MessageEventArgs args) { LiveLinkMsg.LogReceived("ConnectLiveLink"); int player = args.playerId; var buildSettings = args.Receive <Hash128>(); //@TODO: Implement this properly //system.World.GetExistingSystem<EditorSubSceneLiveLinkSystem>().CleanupAllScenes(); //@TODO: How does this work with multiple connections? LiveLinkAssetBundleBuildSystem.instance.ClearUsedAssetsTargetHash(); if (_Connections.TryGetValue(player, out var connection)) { connection.Dispose(); } var newConnection = new LiveLinkConnection(buildSettings); _Connections[player] = newConnection; TimeBasedCallbackInvoker.SetCallback(DetectSceneChanges); EditorUpdateUtility.EditModeQueuePlayerLoopUpdate(); LiveLinkPlayerConnected?.Invoke(player, newConnection._BuildSettingsGUID); }
void RequestAssetTargetHash(MessageEventArgs args) { //@TODO: should be based on connection / BuildSetting var buildTarget = EditorUserBuildSettings.activeBuildTarget; // Array of Asset GUIDs the player is requesting the asset hash of using (var assets = args.ReceiveArray <GUID>()) { // Set of ready to send (all valid target hashes) assets var resolvedAssets = new HashSet <ResolvedAssetID>(); foreach (var asset in assets) { LiveLinkMsg.LogReceived($"AssetBundleTargetHash request => {asset} | {AssetDatabase.GUIDToAssetPath(asset.ToString())}"); // For each Asset- queue calculating target hash and add to tracked assets Unity.Entities.Hash128 targetHash = LiveLinkBuildPipeline.CalculateTargetHash(asset, buildTarget, ImportMode.Asynchronous); m_TrackedAssets[asset] = targetHash; resolvedAssets.Add(new ResolvedAssetID { GUID = asset, TargetHash = targetHash }); // If asset hash is valid (meaning import is ready) then also do the same for dependencies if (targetHash.IsValid) { LiveLinkBuildPipeline.CalculateTargetDependencies(targetHash, buildTarget, out ResolvedAssetID[] dependencies, ImportMode.Asynchronous, asset); foreach (var dependency in dependencies) { m_TrackedAssets[dependency.GUID] = dependency.TargetHash; resolvedAssets.Add(new ResolvedAssetID { GUID = dependency.GUID, TargetHash = dependency.TargetHash }); } } } // Callback to re-send tracked assets when their targethash changes if (m_TrackedAssets.Count > 0) { TimeBasedCallbackInvoker.SetCallback(DetectChangedAssets); } // No assets? Send nothing and set no callback if (resolvedAssets.Count == 0) { return; } var resolved = new NativeArray <ResolvedAssetID>(resolvedAssets.Count, Allocator.Temp); int j = 0; foreach (var id in resolvedAssets) { resolved[j++] = id; } SendAssetTargetHash(resolved, args.playerId); } }
void SendAssetBundleTargetHash(NativeArray <ResolvedAssetID> resolvedAssets, int playerId) { foreach (var asset in resolvedAssets) { LiveLinkMsg.LogSend($"AssetBundleTargetHash response {asset.GUID} | {asset.TargetHash} to playerId: {playerId}"); } EditorConnection.instance.SendArray(LiveLinkMsg.ResponseAssetBundleTargetHash, resolvedAssets, playerId); foreach (var asset in resolvedAssets) { _UsedAssetsTargetHash[asset.GUID] = asset.TargetHash; } TimeBasedCallbackInvoker.SetCallback(DetectChangedAssets); }
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(); } } }
public void RequestSubSceneTargetHash(MessageEventArgs args) { using (var subScenes = args.ReceiveArray <SubSceneGUID>()) { var resolvedScenes = new HashSet <ResolvedSubSceneID>(); foreach (var subScene in subScenes) { LiveLinkMsg.LogInfo($"RequestSubSceneTargetHash => {subScene.Guid}, {subScene.BuildConfigurationGuid}"); var targetHash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.Guid, subScene.BuildConfigurationGuid, UnityEditor.Experimental.AssetDatabaseExperimental.ImportSyncMode.Queue); _UsedSubSceneTargetHash[subScene] = targetHash; if (targetHash.IsValid) { resolvedScenes.Add(new ResolvedSubSceneID { SubSceneGUID = subScene, TargetHash = targetHash }); } } TimeBasedCallbackInvoker.SetCallback(DetectChangedAssets); if (resolvedScenes.Count == 0) { return; } var resolved = new NativeArray <ResolvedSubSceneID>(resolvedScenes.Count, Allocator.Temp); int i = 0; foreach (var id in resolvedScenes) { resolved[i++] = id; } SendSubSceneTargetHash(resolved, args.playerId); } }
void RequestSubSceneTargetHash(MessageEventArgs args) { //@TODO: should be based on connection / BuildSetting var buildTarget = EditorUserBuildSettings.activeBuildTarget; using (var subScenes = args.ReceiveArray <SubSceneGUID>()) { var resolvedScenes = new HashSet <ResolvedSubSceneID>(); var assetDependencies = new HashSet <ResolvedAssetID>(); foreach (var subScene in subScenes) { LiveLinkMsg.LogInfo($"RequestSubSceneTargetHash => {subScene.Guid}, {subScene.BuildConfigurationGuid}"); var targetHash = EntityScenesPaths.GetSubSceneArtifactHash(subScene.Guid, subScene.BuildConfigurationGuid, ImportMode.Asynchronous); m_TrackedSubScenes[subScene] = targetHash; if (targetHash.IsValid) { resolvedScenes.Add(new ResolvedSubSceneID { SubSceneGUID = subScene, TargetHash = targetHash }); var sceneDependencies = LiveLinkBuildPipeline.GetSubSceneDependencies(targetHash); foreach (var sceneDependency in sceneDependencies) { assetDependencies.Add(sceneDependency); m_TrackedAssets[sceneDependency.GUID] = sceneDependency.TargetHash; if (sceneDependency.TargetHash.IsValid) { LiveLinkBuildPipeline.CalculateTargetDependencies(sceneDependency.TargetHash, buildTarget, out ResolvedAssetID[] dependencies, ImportMode.Asynchronous, sceneDependency.GUID); foreach (var dependency in dependencies) { m_TrackedAssets[dependency.GUID] = dependency.TargetHash; assetDependencies.Add(new ResolvedAssetID { GUID = dependency.GUID, TargetHash = dependency.TargetHash }); } } } } } TimeBasedCallbackInvoker.SetCallback(DetectChangedAssets); if (resolvedScenes.Count == 0) { return; } var resolved = new NativeArray <ResolvedSubSceneID>(resolvedScenes.Count, Allocator.Temp); int i = 0; foreach (var id in resolvedScenes) { resolved[i++] = id; } SendSubSceneTargetHash(resolved, args.playerId); if (assetDependencies.Count > 0) { var resolvedAssets = new NativeArray <ResolvedAssetID>(assetDependencies.Count, Allocator.Temp); int assetIndex = 0; foreach (var asset in assetDependencies) { resolvedAssets[assetIndex++] = asset; } SendAssetTargetHash(resolvedAssets, args.playerId); } } }