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); }); }
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)); }
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); }); }
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); } }
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); } }
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); } }