示例#1
0
        private void CreateProtocols(FileSystemPath portFileFullPath)
        {
            if (!portFileFullPath.ExistsFile)
            {
                return;
            }

            var text = File.ReadAllText(portFileFullPath.FullPath);

            if (!int.TryParse(text, out var port))
            {
                myLogger.Error("Couldn't parse port for from file:{0}, text:{1}", portFileFullPath, text);
                return;
            }

            var modelLifetime = myConnectionLifetimeProducer.Next();

            myLogger.Info("Creating SocketWire with port = {0}", port);
            var wire = new SocketWire.Client(modelLifetime, myDispatcher, port, "UnrealEditorClient");

            wire.Connected.Advise(modelLifetime, isConnected => myUnrealHost.PerformModelAction(riderModel =>
                                                                                                riderModel.IsConnectedToUnrealEditor.SetValue(isConnected)));

            var protocol = new Protocol("UnrealEditorPlugin", new Serializers(),
                                        new Identities(IdKind.Client), myDispatcher, wire, modelLifetime);

            wire.Connected.WhenTrue(modelLifetime, lifetime =>
            {
                myLogger.Info("Wire connected");
                ResetModel(lifetime, protocol);
            });
        }
示例#2
0
        internal static IProtocol Client(Lifetime lifetime, int port)
        {
            var id     = "TestClient";
            var client = new SocketWire.Client(lifetime, SynchronousScheduler.Instance, port, id);

            return(new Protocol(id, new Serializers(lifetime, null, null), new Identities(IdKind.Server), SynchronousScheduler.Instance, client, lifetime));
        }
        private void CreateProtocol(FileSystemPath protocolInstancePath, Solution solution)
        {
            int port;

            try
            {
                var protocolInstance =
                    JsonConvert.DeserializeObject <ProtocolInstance>(protocolInstancePath.ReadAllText2().Text);
                port = protocolInstance.port_id;
            }
            catch (Exception e)
            {
                myLogger.Warn($"Unable to parse {protocolInstancePath}" + Environment.NewLine + e);
                return;
            }

            myLogger.Info($"UNITY_Port {port}.");

            try
            {
                var lifetime = mySessionLifetimes.Next();
                myLogger.Info("Create protocol...");

                myLogger.Info("Creating SocketWire with port = {0}", port);
                var wire = new SocketWire.Client(lifetime, myDispatcher, port, "UnityClient");
                wire.Connected.WhenTrue(lifetime, lf =>
                {
                    myLogger.Info("WireConnected.");

                    var protocol = new Protocol("UnityEditorPlugin", new Serializers(), new Identities(IdKind.Client), myDispatcher, wire);
                    var model    = new UnityModel(lf, protocol);
                    model.IsBackendConnected.Set(rdVoid => true);
                    model.RiderProcessId.SetValue(Process.GetCurrentProcess().Id);
                    solution.SetCustomData("UNITY_SessionInitialized", "true");

                    SubscribeToLogs(lf, model, solution);
                    SubscribeToOpenFile(model, solution);
                    model.Play.AdviseNotNull(lf, b => solution.SetCustomData("UNITY_Play", b.ToString().ToLower()));
                    model.Pause.AdviseNotNull(lf, b => solution.SetCustomData("UNITY_Pause", b.ToString().ToLower()));

                    myLocks.ExecuteOrQueueEx(myLifetime, "setModel",
                                             () => { myUnityModel.SetValue(model, myReadonlyToken); });
                    lf.AddAction(() =>
                    {
                        myLocks.ExecuteOrQueueEx(myLifetime, "clearModel", () =>
                        {
                            myLogger.Info("Wire disconnected.");
                            solution.SetCustomData("UNITY_SessionInitialized", "false");
                            myUnityModel.SetValue(null, myReadonlyToken);
                        });
                    });
                });
            }
            catch (Exception ex)
            {
                myLogger.Error(ex);
            }
        }
        private static DteProtocolModel SetupModel(Lifetime lifetime, int port)
        {
            IScheduler scheduler   = new SimpleInpaceExecutingScheduler(Logger.GetLogger <ConnectionManager>());
            var        server      = new SocketWire.Client(lifetime, scheduler, port);
            var        serializers = new Serializers();
            var        identities  = new Identities(IdKind.Client);
            var        protocol    = new Protocol(Protocol, serializers, identities, scheduler, server, lifetime);

            return(new DteProtocolModel(lifetime, protocol));
        }
示例#5
0
 protected void Queue(Action action)
 {
     SingleThreadScheduler.RunOnSeparateThread(SocketLifetime, "Worker", scheduler =>
     {
         var client      = new SocketWire.Client(ModelLifetime, scheduler, myPort, "DemoClient");
         var serializers = new Serializers();
         Protocol        = new Protocol("Server", serializers, new Identities(IdKind.Client), scheduler,
                                        client, SocketLifetime);
         scheduler.Queue(action);
     });
 }
示例#6
0
        private static void MainLifetime(string[] args, LifetimeDefinition lifetimeDefinition)
        {
            var lifetime = lifetimeDefinition.Lifetime;

            var reflectionSerializers = new ReflectionSerializersFacade();
            var serializers           = new Serializers(reflectionSerializers.Registrar);

            var      scheduler = SingleThreadScheduler.RunOnSeparateThread(lifetime, "Scheduler");
            Protocol protocol;

            SocketWire.Base wire;


            var isServer = args.Length == 0 ? Util.Fork(args) : args[0] == "server";

            if (isServer)
            {
                Console.Title = "Server";
                wire          = new SocketWire.Server(lifetime, scheduler, ourIpEndPoint);
                protocol      = new Protocol("Server", serializers, new Identities(IdKind.Server), scheduler, wire, lifetime);
            }
            else
            {
                Console.Title = "Client";
                wire          = new SocketWire.Client(lifetime, scheduler, ourIpEndPoint);
                protocol      = new Protocol("Client", serializers, new Identities(IdKind.Client), scheduler, wire, lifetime);
            }

            scheduler.Queue(() => RunApplication(isServer, reflectionSerializers, lifetime, protocol));

            wire.Connected.Change.Advise(lifetime, value =>
            {
                if (value)
                {
                    Console.Title += ": connected";
                }
                else
                {
                    lifetimeDefinition.Terminate();
                }
            });

            while (lifetime.IsAlive)
            {
                if (Console.KeyAvailable && OnChar != null)
                {
                    scheduler.Queue(() => OnChar?.Invoke(Console.ReadKey(true).KeyChar));
                }

                Thread.Sleep(100);
            }
        }
        private void CreateProtocols(FileSystemPath protocolInstancePath)
        {
            if (!protocolInstancePath.ExistsFile)
            {
                return;
            }

            List <ProtocolInstance> protocolInstanceList;

            try
            {
                protocolInstanceList = ProtocolInstance.FromJson(protocolInstancePath.ReadAllText2().Text);
            }
            catch (Exception e)
            {
                myLogger.Warn($"Unable to parse {protocolInstancePath}" + Environment.NewLine + e);
                return;
            }

            var protocolInstance = protocolInstanceList?.SingleOrDefault(a => a.SolutionName == mySolution.SolutionFilePath.NameWithoutExtension);

            if (protocolInstance == null)
            {
                return;
            }

            myLogger.Info($"EditorPlugin protocol port {protocolInstance.Port} for Solution: {protocolInstance.SolutionName}.");

            try
            {
                var lifetime = mySessionLifetimes.Next();
                myLogger.Info("Create protocol...");

                myLogger.Info("Creating SocketWire with port = {0}", protocolInstance.Port);
                var wire = new SocketWire.Client(lifetime, myDispatcher, protocolInstance.Port, "UnityClient");

                var protocol = new Protocol("UnityEditorPlugin", new Serializers(),
                                            new Identities(IdKind.Client), myDispatcher, wire, lifetime);

                protocol.ThrowErrorOnOutOfSyncModels = false;

                protocol.OutOfSyncModels.AdviseOnce(lifetime, e =>
                {
                    if (myPluginInstallations.Contains(mySolution.SolutionFilePath))
                    {
                        return;
                    }

                    myPluginInstallations.Add(mySolution.SolutionFilePath); // avoid displaying Notification multiple times on each AppDomain.Reload in Unity

                    var appVersion = myUnityVersion.GetActualVersionForSolution();
                    if (appVersion < new Version(2019, 2))
                    {
                        var entry     = myBoundSettingsStore.Schema.GetScalarEntry((UnitySettings s) => s.InstallUnity3DRiderPlugin);
                        var isEnabled = myBoundSettingsStore.GetValueProperty <bool>(lifetime, entry, null).Value;
                        if (!isEnabled)
                        {
                            myHost.PerformModelAction(model => model.OnEditorModelOutOfSync());
                        }
                    }
                    else
                    {
                        var notification = new NotificationModel("Advanced Unity integration is unavailable",
                                                                 $"Please update External Editor to {myHostProductInfo.VersionMarketingString} in Unity Preferences.",
                                                                 true, RdNotificationEntryType.WARN);
                        mySolution.Locks.ExecuteOrQueue(lifetime, "OutOfSyncModels.Notify", () => myNotificationsModel.Notification(notification));
                    }
                });

                wire.Connected.WhenTrue(lifetime, lf =>
                {
                    myLogger.Info("WireConnected.");

                    var editor = new EditorPluginModel(lf, protocol);
                    editor.IsBackendConnected.Set(rdVoid => true);

                    if (PlatformUtil.RuntimePlatform == PlatformUtil.Platform.Windows)
                    {
                        var frontendProcess = Process.GetCurrentProcess().GetParent(); // RiderProcessId is not used on non-Windows, but this line gives bad warning in the log
                        if (frontendProcess != null)
                        {
                            editor.RiderProcessId.SetValue(frontendProcess.Id);
                        }
                    }

                    myHost.PerformModelAction(m => m.SessionInitialized.Value = true);

                    SubscribeToLogs(lf, editor);
                    SubscribeToOpenFile(editor);

                    editor.Play.Advise(lf, b => myHost.PerformModelAction(rd => rd.Play.SetValue(b)));
                    editor.Pause.Advise(lf, b => myHost.PerformModelAction(rd => rd.Pause.SetValue(b)));
                    editor.ClearOnPlay.Advise(lf, time => myHost.PerformModelAction(rd => rd.ClearOnPlay(time)));

                    editor.UnityProcessId.View(lf, (_, pid) => myHost.PerformModelAction(t => t.UnityProcessId.Set(pid)));

                    // I have split this into groups, because want to use async api for finding reference and pass them via groups to Unity
                    myHost.PerformModelAction(t => t.ShowFileInUnity.Advise(lf, v => editor.ShowFileInUnity.Fire(v)));
                    myHost.PerformModelAction(t => t.ShowPreferences.Advise(lf, v =>
                    {
                        editor.ShowPreferences.Fire();
                    }));

                    editor.EditorLogPath.Advise(lifetime,
                                                s => myHost.PerformModelAction(a => a.EditorLogPath.SetValue(s)));
                    editor.PlayerLogPath.Advise(lifetime,
                                                s => myHost.PerformModelAction(a => a.PlayerLogPath.SetValue(s)));

                    // Note that these are late-init properties. Once set, they are always set and do not allow nulls.
                    // This means that if/when the Unity <-> Backend protocol closes, they still retain the last value
                    // they had - so the front end will retain the log and application paths of the just-closed editor.
                    // Opening a new editor instance will reconnect and push a new value through to the front end
                    editor.UnityApplicationData.Advise(lifetime,
                                                       s => myHost.PerformModelAction(a =>
                    {
                        var version = UnityVersion.Parse(s.ApplicationVersion);
                        a.UnityApplicationData.SetValue(new UnityApplicationData(s.ApplicationPath,
                                                                                 s.ApplicationContentsPath, s.ApplicationVersion, UnityVersion.RequiresRiderPackage(version)));
                    }));
                    editor.ScriptCompilationDuringPlay.Advise(lifetime,
                                                              s => myHost.PerformModelAction(a => a.ScriptCompilationDuringPlay.Set(ConvertToScriptCompilationEnum(s))));

                    myHost.PerformModelAction(rd =>
                    {
                        rd.GenerateUIElementsSchema.Set((l, u) =>
                                                        editor.GenerateUIElementsSchema.Start(l, u).ToRdTask(l));
                    });

                    TrackActivity(editor, lf);

                    if (!myComponentLifetime.IsTerminated)
                    {
                        myLocks.ExecuteOrQueueEx(myComponentLifetime, "setModel",
                                                 () => { UnityModel.SetValue(editor); });
                    }

                    lf.AddAction(() =>
                    {
                        if (!myComponentLifetime.IsTerminated)
                        {
                            myLocks.ExecuteOrQueueEx(myComponentLifetime, "clearModel", () =>
                            {
                                myLogger.Info("Wire disconnected.");
                                myHost.PerformModelAction(m => m.SessionInitialized.Value = false);
                                UnityModel.SetValue(null);
                            });
                        }
                    });
                });
            }
            catch (Exception ex)
            {
                myLogger.Error(ex);
            }
        }
示例#8
0
        private void CreateProtocols(FileSystemPath protocolInstancePath)
        {
            if (!protocolInstancePath.ExistsFile)
            {
                return;
            }

            List <ProtocolInstance> protocolInstanceList;

            try
            {
                protocolInstanceList = ProtocolInstance.FromJson(protocolInstancePath.ReadAllText2().Text);
            }
            catch (Exception e)
            {
                myLogger.Warn($"Unable to parse {protocolInstancePath}" + Environment.NewLine + e);
                return;
            }

            var protocolInstance = protocolInstanceList?.SingleOrDefault(a => a.SolutionName == mySolution.SolutionFilePath.NameWithoutExtension);

            if (protocolInstance == null)
            {
                return;
            }

            myLogger.Info($"EditorPlugin protocol port {protocolInstance.Port} for Solution: {protocolInstance.SolutionName}.");

            try
            {
                var lifetime = mySessionLifetimes.Next();
                myLogger.Info("Create protocol...");

                myLogger.Info("Creating SocketWire with port = {0}", protocolInstance.Port);
                var wire = new SocketWire.Client(lifetime, myDispatcher, protocolInstance.Port, "UnityClient");
                wire.Connected.WhenTrue(lifetime, lf =>
                {
                    myLogger.Info("WireConnected.");

                    var protocol = new Protocol("UnityEditorPlugin", new Serializers(),
                                                new Identities(IdKind.Client), myDispatcher, wire);
                    var editor = new EditorPluginModel(lf, protocol);
                    editor.IsBackendConnected.Set(rdVoid => true);

                    if (PlatformUtil.RuntimePlatform == PlatformUtil.Platform.Windows)
                    {
                        var frontendProcess = Process.GetCurrentProcess().GetParent(); // RiderProcessId is not used on non-Windows, but this line gives bad warning in the log
                        if (frontendProcess != null)
                        {
                            editor.RiderProcessId.SetValue(frontendProcess.Id);
                        }
                    }

                    myHost.PerformModelAction(m => m.SessionInitialized.Value = true);

                    SubscribeToLogs(lf, editor);
                    SubscribeToOpenFile(editor);

                    editor.Play.AdviseNotNull(lf, b => myHost.PerformModelAction(rd => rd.Play.SetValue(b)));
                    editor.Pause.AdviseNotNull(lf, b => myHost.PerformModelAction(rd => rd.Pause.SetValue(b)));


                    editor.UnityProcessId.View(lf, (_, pid) => myHost.PerformModelAction(t => t.UnityProcessId.Set(pid)));

                    // I have split this into groups, because want to use async api for finding reference and pass them via groups to Unity
                    myHost.PerformModelAction(t => t.ShowGameObjectOnScene.Advise(lf, v => editor.ShowGameObjectOnScene.Fire(v.ConvertToUnityModel())));

                    // pass all references to Unity TODO temp workaround, replace with async api
                    myHost.PerformModelAction(t => t.FindUsageResults.Advise(lf, v => editor.FindUsageResults.Fire(v.ConvertToUnityModel())));

                    editor.EditorLogPath.Advise(lifetime,
                                                s => myHost.PerformModelAction(a => a.EditorLogPath.SetValue(s)));
                    editor.PlayerLogPath.Advise(lifetime,
                                                s => myHost.PerformModelAction(a => a.PlayerLogPath.SetValue(s)));

                    // Note that these are late-init properties. Once set, they are always set and do not allow nulls.
                    // This means that if/when the Unity <-> Backend protocol closes, they still retain the last value
                    // they had - so the front end will retain the log and application paths of the just-closed editor.
                    // Opening a new editor instance will reconnect and push a new value through to the front end
                    editor.ApplicationPath.Advise(lifetime,
                                                  s => myHost.PerformModelAction(a => a.ApplicationPath.SetValue(s)));
                    editor.ApplicationContentsPath.Advise(lifetime,
                                                          s => myHost.PerformModelAction(a => a.ApplicationContentsPath.SetValue(s)));
                    editor.NotifyIsRecompileAndContinuePlaying.AdviseOnce(lifetime,
                                                                          s => myHost.PerformModelAction(a => a.NotifyIsRecompileAndContinuePlaying.Fire(s)));

                    BindPluginPathToSettings(lf, editor);

                    TrackActivity(editor, lf);

                    if (!myComponentLifetime.IsTerminated)
                    {
                        myLocks.ExecuteOrQueueEx(myComponentLifetime, "setModel",
                                                 () => { UnityModel.SetValue(editor); });
                    }

                    lf.AddAction(() =>
                    {
                        if (!myComponentLifetime.IsTerminated)
                        {
                            myLocks.ExecuteOrQueueEx(myComponentLifetime, "clearModel", () =>
                            {
                                myLogger.Info("Wire disconnected.");
                                myHost.PerformModelAction(m => m.SessionInitialized.Value = false);
                                UnityModel.SetValue(null);
                            });
                        }
                    });
                });
            }
            catch (Exception ex)
            {
                myLogger.Error(ex);
            }
        }
        private void CreateProtocols(FileSystemPath protocolInstancePath)
        {
            if (!protocolInstancePath.ExistsFile)
            {
                return;
            }

            List <ProtocolInstance> protocolInstanceList;

            try
            {
                protocolInstanceList = ProtocolInstance.FromJson(protocolInstancePath.ReadAllText2().Text);
            }
            catch (Exception e)
            {
                myLogger.Warn($"Unable to parse {protocolInstancePath}" + Environment.NewLine + e);
                return;
            }

            var protocolInstance = protocolInstanceList?.SingleOrDefault(a => a.SolutionName == mySolution.SolutionFilePath.NameWithoutExtension);

            if (protocolInstance == null)
            {
                return;
            }

            myLogger.Info($"UNITY_Port {protocolInstance.Port} for Solution: {protocolInstance.SolutionName}.");

            try
            {
                var lifetime = mySessionLifetimes.Next();
                myLogger.Info("Create protocol...");

                myLogger.Info("Creating SocketWire with port = {0}", protocolInstance.Port);
                var wire = new SocketWire.Client(lifetime, myDispatcher, protocolInstance.Port, "UnityClient");
                wire.Connected.WhenTrue(lifetime, lf =>
                {
                    myLogger.Info("WireConnected.");

                    var protocol = new Protocol("UnityEditorPlugin", new Serializers(),
                                                new Identities(IdKind.Client), myDispatcher, wire);
                    var model = new EditorPluginModel(lf, protocol);
                    model.IsBackendConnected.Set(rdVoid => true);
                    var frontendProcess = Process.GetCurrentProcess().GetParent();
                    if (frontendProcess != null)
                    {
                        model.RiderProcessId.SetValue(frontendProcess.Id);
                    }

                    myHost.SetModelData("UNITY_SessionInitialized", "true");

                    SubscribeToLogs(lf, model);
                    SubscribeToOpenFile(model);
                    model.Play.AdviseNotNull(lf, b => myHost.PerformModelAction(a => a.Play.SetValue(b)));
                    model.Pause.AdviseNotNull(lf, b => myHost.SetModelData("UNITY_Pause", b.ToString().ToLower()));

                    // Note that these are late-init properties. Once set, they are always set and do not allow nulls.
                    // This means that if/when the Unity <-> Backend protocol closes, they still retain the last value
                    // they had - so the front end will retain the log and application paths of the just-closed editor.
                    // Opening a new editor instance will reconnect and push a new value through to the front end
                    model.EditorLogPath.Advise(lifetime,
                                               s => myHost.PerformModelAction(a => a.EditorLogPath.SetValue(s)));
                    model.PlayerLogPath.Advise(lifetime,
                                               s => myHost.PerformModelAction(a => a.PlayerLogPath.SetValue(s)));

                    model.ApplicationPath.Advise(lifetime,
                                                 s => myHost.PerformModelAction(a => a.ApplicationPath.SetValue(s)));
                    model.ApplicationContentsPath.Advise(lifetime,
                                                         s => myHost.PerformModelAction(a => a.ApplicationContentsPath.SetValue(s)));

                    BindPluginPathToSettings(lf, model);

                    TrackActivity(model, lf);

                    if (!myComponentLifetime.IsTerminated)
                    {
                        myLocks.ExecuteOrQueueEx(myComponentLifetime, "setModel",
                                                 () => { myUnityModel.SetValue(model, myReadonlyToken); });
                    }

                    lf.AddAction(() =>
                    {
                        if (!myComponentLifetime.IsTerminated)
                        {
                            myLocks.ExecuteOrQueueEx(myComponentLifetime, "clearModel", () =>
                            {
                                myLogger.Info("Wire disconnected.");
                                myHost.SetModelData("UNITY_SessionInitialized", "false");
                                myUnityModel.SetValue(null, myReadonlyToken);
                            });
                        }
                    });
                });
            }
            catch (Exception ex)
            {
                myLogger.Error(ex);
            }
        }
示例#10
0
        private void CreateProtocol(FileSystemPath protocolInstancePath)
        {
            var protocolInstance = GetProtocolInstanceData(protocolInstancePath);

            if (protocolInstance == null)
            {
                return;
            }

            myLogger.Info($"EditorPlugin protocol port {protocolInstance.Port} for Solution: {protocolInstance.SolutionName}.");

            if (protocolInstance.ProtocolGuid != ProtocolCompatibility.ProtocolGuid)
            {
                OnOutOfSync(myLifetime);
                myLogger.Info("Avoid attempt to create protocol, incompatible.");
                return;
            }

            try
            {
                var thisSessionLifetime = mySessionLifetimes.Next();
                myLogger.Info("Create protocol...");

                myLogger.Info("Creating SocketWire with port = {0}", protocolInstance.Port);
                var wire = new SocketWire.Client(thisSessionLifetime, myDispatcher, protocolInstance.Port, "UnityClient")
                {
                    BackwardsCompatibleWireFormat = true
                };

                var protocol = new Rd.Impl.Protocol("UnityEditorPlugin", new Serializers(thisSessionLifetime, null, null),
                                                    new Identities(IdKind.Client), myDispatcher, wire, thisSessionLifetime)
                {
                    ThrowErrorOnOutOfSyncModels = false
                };

                protocol.OutOfSyncModels.AdviseOnce(thisSessionLifetime, _ => OnOutOfSync(thisSessionLifetime));

                wire.Connected.WhenTrue(thisSessionLifetime, connectionLifetime =>
                {
                    myLogger.Info("WireConnected.");

                    var backendUnityModel = new BackendUnityModel(connectionLifetime, protocol);

                    SafeExecuteOrQueueEx("setModel",
                                         () => myBackendUnityHost.BackendUnityModel.SetValue(backendUnityModel));

                    connectionLifetime.OnTermination(() =>
                    {
                        SafeExecuteOrQueueEx("clearModel", () =>
                        {
                            myLogger.Info("Wire disconnected.");

                            // Clear model
                            myBackendUnityHost.BackendUnityModel.SetValue(null);
                        });
                    });
                });
            }
            catch (Exception ex)
            {
                myLogger.Error(ex);
            }
        }