Пример #1
0
        unsafe void ReceiveSubSceneTargetHash(MessageEventArgs args)
        {
            using (var subSceneAssets = args.ReceiveArray <ResolvedSubSceneID>())
            {
                foreach (var subSceneAsset in subSceneAssets)
                {
                    if (m_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID))
                    {
                        return;
                    }

                    // If subscene exists locally already, just load it
                    if (IsSubSceneAvailable(subSceneAsset))
                    {
                        LiveLinkMsg.LogInfo($"ReceiveResponseSubSceneTargetHash => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, File.Exists => 'True'");

                        AddWaitForSubScene(subSceneAsset);
                    }
                    else
                    {
                        LiveLinkMsg.LogInfo($"ReceiveResponseSubSceneTargetHash => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, File.Exists => 'False'");
                        m_Connection.Send(LiveLinkMsg.PlayerRequestSubSceneForGUID, subSceneAsset);
                    }
                }
            }
        }
Пример #2
0
        protected override void OnUpdate()
        {
            // BuildConfigurationGUID isn't known in OnCreate since it could be configured from OnCreate of other systems,
            // So we delay connecting live link until first OnUpdate
            if (!m_DidRequestConnection)
            {
                if (!m_SessionHandshake)
                {
                    if (m_SessionHandshakeTimeoutTimstamp < Time.ElapsedTime)
                    {
                        Debug.LogError("LiveLink handshake timed out. This may be because your player connection is connected to an AssetWorker process or incorrect Editor.");
                        World.GetExistingSystem <LiveLinkRuntimeSystemGroup>().Enabled = false;
                    }

                    return;
                }

                m_DidRequestConnection = true;
                LiveLinkMsg.LogSend("ConnectLiveLink");
                m_Connection.Send(LiveLinkMsg.PlayerRequestConnectLiveLink, World.GetExistingSystem <SceneSystem>().BuildConfigurationGUID);
            }

            SendSetLoadedScenes();

            while (m_ResourcePacketQueue.Count != 0 && IsResourceReady(m_ResourcePacketQueue.Peek().GlobalObjectIds))
            {
                LiveLinkMsg.LogInfo($"Applying changeset ({m_ResourcePacketQueue.Count-1} left in queue)");
                using (var resourcePacket = m_ResourcePacketQueue.Dequeue())
                {
                    ApplyChangeSet(resourcePacket);
                }
            }
        }
Пример #3
0
        unsafe void ReceiveSubSceneTargetHash(MessageEventArgs args)
        {
            using (var subSceneAssets = args.ReceiveArray <ResolvedSubSceneID>())
            {
                foreach (var subSceneAsset in subSceneAssets)
                {
                    if (m_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID))
                    {
                        return;
                    }

                    // If subscene exists locally already, just load it
                    var assetDependencies = new HashSet <RuntimeGlobalObjectId>();
                    if (IsSubSceneAvailable(subSceneAsset, assetDependencies))
                    {
                        LiveLinkMsg.LogInfo($"ReceiveResponseSubSceneTargetHash => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, File.Exists => 'True'");

                        //TODO: This is a hack to make sure assets are managed by asset manifest when loading from cache for first run
                        AddWaitForSubScene(subSceneAsset, assetDependencies);
                    }
                    else
                    {
                        LiveLinkMsg.LogInfo($"ReceiveResponseSubSceneTargetHash => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, File.Exists => 'False'");

                        PlayerConnection.instance.Send(LiveLinkMsg.RequestSubSceneByGUID, subSceneAsset);
                    }
                }
            }
        }
        //@TODO: Support some sort of transaction like API so we can reload all changed things in batch.
        unsafe void ReceiveAssetBundle(MessageEventArgs args)
        {
            LiveLinkMsg.LogReceived($"AssetBundle: '{args.data.Length}' bytes");

            fixed(byte *ptr = args.data)
            {
                var reader = new UnsafeAppendBuffer.Reader(ptr, args.data.Length);
                var asset  = reader.ReadNext <ResolvedAssetID>();

                var assetBundleCachePath = GetCachePath(asset.TargetHash);
                var tempCachePath        = GetTempCachePath();

                // cache: look up asset by target hash to see if the version we want is already on the target device

                //if we already have the asset bundle revision we want, then just put that in the resolver as the active revision of the asset
                // cache: if not in cache, write actual file to Application.persistentDatapath
                var stream = File.OpenWrite(tempCachePath);

                stream.Write(args.data, reader.Offset, args.data.Length - reader.Offset);
                stream.Close();
                stream.Dispose();

                LiveLinkMsg.LogInfo($"ReceiveAssetBundle => {asset.GUID} | {asset.TargetHash}, '{tempCachePath}' => '{assetBundleCachePath}'");

                if (File.Exists(assetBundleCachePath))
                {
                    Debug.LogError($"Received {asset.GUID} | {asset.TargetHash} but it already exists on disk");
                    LiveLinkMsg.LogInfo($"Received {asset.GUID} | {asset.TargetHash} but it already exists on disk");
                    File.Delete(tempCachePath);
                }
                else
                {
                    try
                    {
                        File.Move(tempCachePath, assetBundleCachePath);
                    }
                    catch (Exception e)
                    {
                        File.Delete(tempCachePath);
                        if (!File.Exists(assetBundleCachePath))
                        {
                            Debug.LogError($"Failed to move temporary file. Exception: {e.Message}");
                            LiveLinkMsg.LogInfo($"Failed to move temporary file. Exception: {e.Message}");
                        }
                    }
                }


                if (!_WaitingForAssets.ContainsKey(asset.GUID))
                {
                    Debug.LogError($"Received {asset.GUID} | {asset.TargetHash} without requesting it");
                    LiveLinkMsg.LogInfo($"Received {asset.GUID} | {asset.TargetHash} without requesting it");
                }

                _WaitingForAssets[asset.GUID] = asset.TargetHash;
            }
        }
        //TODO: There is too much code duplication here, refactor this to receive general artifacts from the editor
        unsafe void ReceiveSubSceneRefGUIDs(MessageEventArgs args)
        {
            fixed(byte *ptr = args.data)
            {
                var reader        = new UnsafeAppendBuffer.Reader(ptr, args.data.Length);
                var subSceneAsset = reader.ReadNext <ResolvedSubSceneID>();
                var sectionIndex  = reader.ReadNext <int>();

                reader.ReadNext(out NativeArray <RuntimeGlobalObjectId> objRefGUIDs, Allocator.Persistent);
                var refObjGUIDsPath = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesUnityObjectReferences, sectionIndex);

                // Not printing error because this can happen when running the same player multiple times on the same machine
                if (File.Exists(refObjGUIDsPath))
                {
                    LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} but it already exists on disk");
                }
                else
                {
                    LiveLinkMsg.LogInfo($"ReceieveSubSceneRefGUIDs => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash},");

                    var tempCachePath = GetTempCachePath();
                    using (var writer = new StreamBinaryWriter(tempCachePath))
                    {
                        writer.Write(objRefGUIDs.Length);
                        writer.WriteArray(objRefGUIDs);
                    }

                    try
                    {
                        File.Move(tempCachePath, refObjGUIDsPath);
                    }
                    catch (Exception e)
                    {
                        File.Delete(tempCachePath);
                        if (!File.Exists(refObjGUIDsPath))
                        {
                            Debug.LogError($"Failed to move temporary file. Exception: {e.Message}");
                            LiveLinkMsg.LogInfo($"Failed to move temporary file. Exception: {e.Message}");
                        }
                    }
                }

                if (!_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID))
                {
                    Debug.LogError($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it");
                    LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it");
                    return;
                }

                var waitingSubScene = _WaitingForSubScenes[subSceneAsset.SubSceneGUID];

                waitingSubScene.SubSections.Add(objRefGUIDs);
                _WaitingForSubScenes[subSceneAsset.SubSceneGUID] = waitingSubScene;
            }
        }
        unsafe void ReceiveResponseSubSceneTargetHash(MessageEventArgs args)
        {
            using (var subSceneAssets = args.ReceiveArray <ResolvedSubSceneID>())
            {
                foreach (var subSceneAsset in subSceneAssets)
                {
                    if (_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID))
                    {
                        return;
                    }

                    var headerPath = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesHeader, -1);

                    if (File.Exists(headerPath))
                    {
                        LiveLinkMsg.LogInfo($"ReceiveResponseSubSceneTargetHash => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, File.Exists => 'True', {Path.GetFullPath(headerPath)}");

                        //TODO: This is a hack to make sure assets are managed by asset manifest when loading from cache for first run
                        if (!BlobAssetReference <SceneMetaData> .TryRead(headerPath, SceneMetaDataSerializeUtility.CurrentFileFormatVersion, out var sceneMetaDataRef))
                        {
                            Debug.LogError("Loading Entity Scene failed because the entity header file was an old version: " + subSceneAsset.SubSceneGUID);
                            return;
                        }

                        ref var sceneMetaData = ref sceneMetaDataRef.Value;

                        var waitingSubScene = new WaitingSubScene
                        {
                            TargetHash      = subSceneAsset.TargetHash,
                            SubSections     = new List <NativeArray <RuntimeGlobalObjectId> >(),
                            SubSectionCount = sceneMetaData.Sections.Length
                        };

                        for (int i = 0; i < sceneMetaData.Sections.Length; i++)
                        {
                            if (sceneMetaData.Sections[i].ObjectReferenceCount != 0)
                            {
                                var refObjGUIDsPath = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesUnityObjectReferences, i);
                                using (var reader = new StreamBinaryReader(refObjGUIDsPath))
                                {
                                    var numObjRefGUIDs = reader.ReadInt();
                                    NativeArray <RuntimeGlobalObjectId> objRefGUIDs = new NativeArray <RuntimeGlobalObjectId>(numObjRefGUIDs, Allocator.Persistent);
                                    reader.ReadArray(objRefGUIDs, numObjRefGUIDs);
                                    waitingSubScene.SubSections.Add(objRefGUIDs);
                                }
                            }
                            else
                            {
                                waitingSubScene.SubSections.Add(new NativeArray <RuntimeGlobalObjectId>(0, Allocator.Persistent));
                            }
                        }

                        _WaitingForSubScenes[subSceneAsset.SubSceneGUID] = waitingSubScene;
                    }
        unsafe void ReceiveSubSceneHeader(MessageEventArgs args)
        {
            fixed(byte *ptr = args.data)
            {
                var reader          = new UnsafeAppendBuffer.Reader(ptr, args.data.Length);
                var subSceneAsset   = reader.ReadNext <ResolvedSubSceneID>();
                var subSectionCount = reader.ReadNext <int>();
                var headerPath      = EntityScenesPaths.GetLiveLinkCachePath(subSceneAsset.TargetHash, EntityScenesPaths.PathType.EntitiesHeader, -1);

                // Not printing error because this can happen when running the same player multiple times on the same machine
                if (File.Exists(headerPath))
                {
                    LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} but it already exists on disk");
                }
                else
                {
                    var tempCachePath = GetTempCachePath();
                    LiveLinkMsg.LogInfo($"ReceiveSubSceneHeader => {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash}, '{tempCachePath}' => '{headerPath}'");

                    var stream = File.OpenWrite(tempCachePath);
                    stream.Write(args.data, reader.Offset, args.data.Length - reader.Offset);
                    stream.Close();
                    stream.Dispose();

                    try
                    {
                        File.Move(tempCachePath, headerPath);
                    }
                    catch (Exception e)
                    {
                        File.Delete(tempCachePath);
                        if (!File.Exists(headerPath))
                        {
                            Debug.LogError($"Failed to move temporary file. Exception: {e.Message}");
                            LiveLinkMsg.LogInfo($"Failed to move temporary file. Exception: {e.Message}");
                        }
                    }
                }

                if (!_WaitingForSubScenes.ContainsKey(subSceneAsset.SubSceneGUID))
                {
                    Debug.LogError($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it");
                    LiveLinkMsg.LogInfo($"Received {subSceneAsset.SubSceneGUID} | {subSceneAsset.TargetHash} without requesting it");
                    return;
                }

                var waitingSubScene = _WaitingForSubScenes[subSceneAsset.SubSceneGUID];

                waitingSubScene.TargetHash      = subSceneAsset.TargetHash;
                waitingSubScene.SubSectionCount = subSectionCount;
                _WaitingForSubScenes[subSceneAsset.SubSceneGUID] = waitingSubScene;
            }
        }
Пример #8
0
        unsafe void ReceiveSubScene(MessageEventArgs args)
        {
            var subSceneId = args.Receive <ResolvedSubSceneID>();

            LiveLinkMsg.LogInfo($"ReceiveSubScene => SubScene received {subSceneId}");

            if (!IsSubSceneAvailable(subSceneId))
            {
                Debug.LogError("SubScene is missing artifacts!");
                return;
            }

            AddWaitForSubScene(subSceneId);
        }
Пример #9
0
        unsafe void ReceiveBuildArtifact(MessageEventArgs args)
        {
            fixed(byte *ptr = args.data)
            {
                LiveLinkMsg.LogInfo($"ReceiveBuildArtifact => Buffer Size: {args.data.Length}");
                var reader = new UnsafeAppendBuffer.Reader(ptr, args.data.Length);

                reader.ReadNext(out string artifactFileName);
                string artifactPath = EntityScenesPaths.ComposeLiveLinkCachePath(artifactFileName);

                if (!File.Exists(artifactPath))
                {
                    LiveLinkMsg.LogInfo($"ReceiveBuildArtifact => {artifactPath}");

                    var tempCachePath = GetTempCachePath();

                    try
                    {
                        var stream = File.OpenWrite(tempCachePath);
                        stream.Write(args.data, reader.Offset, args.data.Length - reader.Offset);
                        stream.Close();
                        stream.Dispose();

                        File.Move(tempCachePath, artifactPath);

                        LiveLinkMsg.LogInfo($"ReceiveBuildArtifact => Successfully written to disc.");
                    }
                    catch (Exception e)
                    {
                        if (File.Exists(tempCachePath))
                        {
                            File.Delete(tempCachePath);
                        }

                        if (!File.Exists(artifactPath))
                        {
                            Debug.LogError($"Failed to move temporary file. Exception: {e.Message}");
                        }
                    }
                }
            }
        }
Пример #10
0
        unsafe void ReceiveSubScene(MessageEventArgs args)
        {
            fixed(byte *ptr = args.data)
            {
                var reader = new UnsafeAppendBuffer.Reader(ptr, args.data.Length);

                reader.ReadNext(out ResolvedSubSceneID subSceneId);
                reader.ReadNext(out NativeArray <RuntimeGlobalObjectId> runtimeGlobalObjectIds, Allocator.Persistent);

                LiveLinkMsg.LogInfo($"ReceiveSubScene => SubScene received {subSceneId} | Asset Dependencies {runtimeGlobalObjectIds.Length}");

                if (!IsSubSceneAvailable(subSceneId))
                {
                    Debug.LogError("SubScene is missing artifacts!");
                    return;
                }

                AddWaitForSubScene(subSceneId, runtimeGlobalObjectIds);
            }
        }
Пример #11
0
        protected override void OnUpdate()
        {
            var sceneSystem = World.GetExistingSystem <SceneSystem>();

            Entities.With(m_AllScenes).ForEach((Entity e, ref SceneReference sceneRef) =>
            {
                if (m_LiveLinkedScenes.Contains(sceneRef.SceneGUID))
                {
                    EntityManager.AddComponent <DisableSceneResolveAndLoad>(e);
                }
                else
                {
                    EntityManager.RemoveComponent <DisableSceneResolveAndLoad>(e);
                }
            }
                                               );


            // BuildSettingsGUID isn't known in OnCreate since it could be configured from OnCreate of other systems,
            // So we delay connecting live link until first OnUpdate
            if (!m_DidRequestConnection)
            {
                m_DidRequestConnection = true;
                LiveLinkMsg.LogSend("ConnectLiveLink");
                PlayerConnection.instance.Send(LiveLinkMsg.ConnectLiveLink, World.GetExistingSystem <SceneSystem>().BuildSettingsGUID);
            }

            SendSetLoadedScenes();

            while (m_ResourcePacketQueue.Count != 0 && IsResourceReady(m_ResourcePacketQueue.Peek()))
            {
                LiveLinkMsg.LogInfo($"Applying changeset ({m_ResourcePacketQueue.Count-1} left in queue)");
                using (var resourcePacket = m_ResourcePacketQueue.Dequeue())
                {
                    ApplyChangeSet(resourcePacket);
                }
            }
        }
Пример #12
0
        protected override void OnUpdate()
        {
            var sceneSystem = World.GetExistingSystem <SceneSystem>();

            // BuildConfigurationGUID isn't known in OnCreate since it could be configured from OnCreate of other systems,
            // So we delay connecting live link until first OnUpdate
            if (!m_DidRequestConnection)
            {
                m_DidRequestConnection = true;
                LiveLinkMsg.LogSend("ConnectLiveLink");
                PlayerConnection.instance.Send(LiveLinkMsg.RequestConnectLiveLink, World.GetExistingSystem <SceneSystem>().BuildConfigurationGUID);
            }

            SendSetLoadedScenes();

            while (m_ResourcePacketQueue.Count != 0 && IsResourceReady(m_ResourcePacketQueue.Peek().GlobalObjectIds))
            {
                LiveLinkMsg.LogInfo($"Applying changeset ({m_ResourcePacketQueue.Count-1} left in queue)");
                using (var resourcePacket = m_ResourcePacketQueue.Dequeue())
                {
                    ApplyChangeSet(resourcePacket);
                }
            }
        }
Пример #13
0
        void LoadAssetBundles(NativeArray <ResolvedAssetID> assets)
        {
            LiveLinkMsg.LogInfo("--- Begin Load asset bundles");

            var patchAssetBundles     = new List <AssetBundle>();
            var patchAssetBundlesPath = new List <string>();
            var newAssetBundles       = new List <Hash128>();
            var assetBundleToValidate = new List <Hash128>();


            foreach (var asset in assets)
            {
                var assetGUID            = asset.GUID;
                var targetHash           = asset.TargetHash;
                var assetBundleCachePath = GetCachePath(targetHash);

                //if we already loaded an asset bundle and we just need a refresh
                var oldAssetBundle = globalAssetObjectResolver.GetAssetBundle(assetGUID);
                if (oldAssetBundle != null)
                {
                    if (oldAssetBundle.isStreamedSceneAssetBundle)
                    {
                        LiveLinkMsg.LogInfo($"Unloading scene bundle: {assetGUID}");
                        var sceneSystem = World.GetExistingSystem <SceneSystem>();
                        if (sceneSystem != null)
                        {
                            sceneSystem.ReloadScenesWithHash(assetGUID, targetHash);
                        }
                        globalAssetObjectResolver.UnloadAsset(assetGUID);
                        continue;
                    }
                    else
                    {
                        LiveLinkMsg.LogInfo($"patching asset bundle: {assetGUID}");

                        patchAssetBundles.Add(oldAssetBundle);
                        patchAssetBundlesPath.Add(assetBundleCachePath);

                        globalAssetObjectResolver.UpdateTargetHash(assetGUID, targetHash);
                        newAssetBundles.Add(assetGUID);
                    }
                }
                else
                {
                    LiveLinkMsg.LogInfo($"Loaded asset bundle: {assetGUID}");

                    var loadedAssetBundle = AssetBundle.LoadFromFile(assetBundleCachePath);
                    globalAssetObjectResolver.AddAsset(assetGUID, targetHash, null, loadedAssetBundle);
                    newAssetBundles.Add(assetGUID);
                }

                assetBundleToValidate.Add(assetGUID);

                //@TODO: Keep a hashtable of guid -> entity?
                Entities.ForEach((Entity entity, ref ResourceGUID guid) =>
                {
                    if (guid.Guid == assetGUID)
                    {
                        EntityManager.AddComponentData(entity, new ResourceLoaded());
                    }
                });
            }


            AssetBundleUtility.PatchAssetBundles(patchAssetBundles.ToArray(), patchAssetBundlesPath.ToArray());

            foreach (var assetGUID in newAssetBundles)
            {
                var assetBundle = globalAssetObjectResolver.GetAssetBundle(assetGUID);
                if (assetBundle == null)
                {
                    Debug.LogError($"Could not load requested asset bundle.'");
                    return;
                }

                if (!assetBundle.isStreamedSceneAssetBundle)
                {
                    var loadedManifest = assetBundle.LoadAsset <AssetObjectManifest>(assetGUID.ToString());
                    if (loadedManifest == null)
                    {
                        Debug.LogError($"Loaded {assetGUID} failed to load ObjectManifest");
                        return;
                    }

                    globalAssetObjectResolver.UpdateObjectManifest(assetGUID, loadedManifest);
                }
            }

            foreach (var assetGUID in assetBundleToValidate)
            {
                globalAssetObjectResolver.Validate(assetGUID);
            }

            LiveLinkMsg.LogInfo("--- End Load asset bundles");
        }