Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix RIDER-73086 Advanced Unity integration is unavailable #2240

Merged
merged 8 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using JetBrains.Application;
using JetBrains.Application.changes;
using JetBrains.Application.FileSystemTracker;
using JetBrains.Application.Settings;
using JetBrains.Application.Threading;
using JetBrains.Collections.Viewable;
using JetBrains.Lifetimes;
Expand All @@ -14,11 +12,8 @@
using JetBrains.Rd.Base;
using JetBrains.Rd.Impl;
using JetBrains.RdBackend.Common.Features;
using JetBrains.ReSharper.Plugins.Unity.Core.Application.Settings;
using JetBrains.ReSharper.Plugins.Unity.Core.ProjectModel;
using JetBrains.ReSharper.Plugins.Unity.UnityEditorIntegration;
using JetBrains.ReSharper.Psi.Util;
using JetBrains.Rider.Model.Notifications;
using JetBrains.ReSharper.Plugins.Unity.Rider.UnityEditorIntegration.EditorPlugin;
using JetBrains.Rider.Model.Unity.BackendUnity;
using JetBrains.Rider.Unity.Editor.NonUnity;
using JetBrains.Util;
Expand All @@ -36,22 +31,17 @@ public class BackendUnityProtocol
private readonly IScheduler myDispatcher;
private readonly IShellLocks myLocks;
private readonly ISolution mySolution;
private readonly UnityVersion myUnityVersion;
private readonly NotificationsModel myNotificationsModel;
private readonly IHostProductInfo myHostProductInfo;
private readonly FrontendBackendHost myFrontendBackendHost;
private readonly IContextBoundSettingsStoreLive myBoundSettingsStore;
private readonly UnityPluginInstaller myPluginInstaller;
private readonly JetHashSet<VirtualFileSystemPath> myPluginInstallations;

private DateTime myLastChangeTime;

public BackendUnityProtocol(Lifetime lifetime, ILogger logger,
BackendUnityHost backendUnityHost, FrontendBackendHost frontendBackendHost,
IScheduler dispatcher, IShellLocks locks, ISolution solution,
IApplicationWideContextBoundSettingStore settingsStore,
UnitySolutionTracker unitySolutionTracker,
UnityVersion unityVersion, NotificationsModel notificationsModel,
IHostProductInfo hostProductInfo, IFileSystemTracker fileSystemTracker)
BackendUnityHost backendUnityHost,
IScheduler dispatcher, IShellLocks locks, ISolution solution,
UnitySolutionTracker unitySolutionTracker,
IFileSystemTracker fileSystemTracker,
UnityPluginInstaller pluginInstaller)
{
myPluginInstallations = new JetHashSet<VirtualFileSystemPath>();

Expand All @@ -61,11 +51,7 @@ public BackendUnityProtocol(Lifetime lifetime, ILogger logger,
myDispatcher = dispatcher;
myLocks = locks;
mySolution = solution;
myUnityVersion = unityVersion;
myNotificationsModel = notificationsModel;
myHostProductInfo = hostProductInfo;
myFrontendBackendHost = frontendBackendHost;
myBoundSettingsStore = settingsStore.BoundSettingsStore;
myPluginInstaller = pluginInstaller;
mySessionLifetimes = new SequentialLifetimes(lifetime);

if (solution.GetData(ProjectModelExtensions.ProtocolSolutionKey) == null)
Expand Down Expand Up @@ -109,17 +95,18 @@ private void CreateProtocol(VirtualFileSystemPath protocolInstancePath)
return;

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

var thisSessionLifetime = mySessionLifetimes.Next();

if (protocolInstance.ProtocolGuid != ProtocolCompatibility.ProtocolGuid)
{
OnOutOfSync(myLifetime);
OnOutOfSync(thisSessionLifetime);
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);
Expand Down Expand Up @@ -204,24 +191,7 @@ private void OnOutOfSync(Lifetime lifetime)
// avoid displaying Notification multiple times on each AppDomain.Reload in Unity
myPluginInstallations.Add(mySolution.SolutionFilePath);

var appVersion = myUnityVersion.ActualVersionForSolution.Value;
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)
{
myFrontendBackendHost.Do(model => model.OnEditorModelOutOfSync());
}
}
else
{
var notification = new NotificationModel("Advanced Unity integration is unavailable",
$"Make sure Rider {myHostProductInfo.VersionMarketingString} is set as the External Editor in Unity preferences.",
true, RdNotificationEntryType.WARN, new List<NotificationHyperlink>());
mySolution.Locks.ExecuteOrQueue(lifetime, "OutOfSyncModels.Notify",
() => myNotificationsModel.Notification(notification));
}
myPluginInstaller.ShowOutOfSyncNotification(lifetime);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using JetBrains.Application;
using JetBrains.Application.Notifications;
using JetBrains.Application.Settings;
using JetBrains.Application.Threading;
using JetBrains.Application.Threading.Tasks;
Expand All @@ -15,6 +17,7 @@
using JetBrains.ReSharper.Plugins.Unity.Rider.Protocol;
using JetBrains.ReSharper.Plugins.Unity.UnityEditorIntegration;
using JetBrains.ReSharper.Psi.Util;
using JetBrains.Rider.Backend.Features.Notifications;
using JetBrains.Rider.Model.Notifications;
using JetBrains.Rider.Model.Unity.BackendUnity;
using JetBrains.Util;
Expand All @@ -35,6 +38,8 @@ public class UnityPluginInstaller
private readonly UnityVersion myUnityVersion;
private readonly UnitySolutionTracker myUnitySolutionTracker;
private readonly UnityRefresher myRefresher;
private readonly RiderNotificationPopupHost myNotificationPopupHost;
private readonly IHostProductInfo myHostProductInfo;
private readonly IContextBoundSettingsStoreLive myBoundSettingsStore;
private readonly ProcessingQueue myQueue;

Expand All @@ -50,7 +55,9 @@ public UnityPluginInstaller(
UnityVersion unityVersion,
FrontendBackendHost frontendBackendHost,
UnitySolutionTracker unitySolutionTracker,
UnityRefresher refresher)
UnityRefresher refresher,
IHostProductInfo hostProductInfo,
RiderNotificationPopupHost notificationPopupHost = null)
{
myPluginInstallations = new JetHashSet<VirtualFileSystemPath>();

Expand All @@ -64,13 +71,15 @@ public UnityPluginInstaller(
myUnityVersion = unityVersion;
myUnitySolutionTracker = unitySolutionTracker;
myRefresher = refresher;

myHostProductInfo = hostProductInfo;
myNotificationPopupHost = notificationPopupHost;

myBoundSettingsStore = settingsStore.BoundSettingsStore;
myQueue = new ProcessingQueue(myShellLocks, myLifetime);

frontendBackendHost.Do(frontendBackendModel =>
{
frontendBackendModel.InstallEditorPlugin.AdviseNotNull(lifetime, x =>
frontendBackendModel.InstallEditorPlugin.AdviseNotNull(lifetime, _ =>
{
myShellLocks.ExecuteOrQueueReadLockEx(myLifetime, "UnityPluginInstaller.InstallEditorPlugin", () =>
{
Expand Down Expand Up @@ -343,5 +352,43 @@ private void RestoreFromBackup(Dictionary<VirtualFileSystemPath, VirtualFileSyst
backup.Value.MoveFile(backup.Key, true);
}
}

internal void ShowOutOfSyncNotification(Lifetime lifetime)
{
var notificationLifetime = lifetime.CreateNested();
var appVersion = myUnityVersion.ActualVersionForSolution.Value;
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) return;
var notification = RiderNotification.Create(
NotificationSeverity.WARNING, "Unity editor plugin update required",
"The Unity editor plugin is out of date and automatic plugin updates are disabled. Advanced Unity integration features are unavailable until the plugin is updated.",
additionalCommands: new[]
{
new UserNotificationCommand("Never show for this solution", () =>
{
mySolution.Locks.ExecuteOrQueueReadLockEx(notificationLifetime.Lifetime,
"UnityPluginInstaller.InstallEditorPlugin", () =>
{
var installationInfo = myDetector.GetInstallationInfo(myCurrentVersion);
QueueInstall(installationInfo, true);
notificationLifetime.Terminate();
});
})
}
);
myNotificationPopupHost.ShowNotification(notificationLifetime.Lifetime, notification);
}
else
{
var notification = RiderNotification.Create(
NotificationSeverity.WARNING, "Advanced Unity integration is unavailable",
$"Make sure Rider {myHostProductInfo.VersionMarketingString} is set as the External Editor in Unity preferences."
);
myNotificationPopupHost.ShowNotification(notificationLifetime.Lifetime, notification);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private FileSystemPath GetDocumentationRoot()
var contentsPath = UnityInstallationFinder.GetApplicationContentsPath(appPath);
var root = contentsPath.Combine("Documentation");
var englishRoot = root.Combine("en");
if (!englishRoot.ExistsDirectory && root.ExistsDirectory)
if (root.IsAbsolute && !englishRoot.ExistsDirectory && root.ExistsDirectory)
return root.GetChildDirectories().FirstOrDefault(englishRoot).ToNativeFileSystemPath();
return englishRoot.ToNativeFileSystemPath();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ object FrontendBackendModel : Ext(SolutionModel.Solution) {
sink("notifyYamlHugeFiles", void)
sink("notifyAssetModeForceText", void)
sink("showDeferredCachesProgressNotification", void)
sink("onEditorModelOutOfSync", void)
callback("attachDebuggerToUnityEditor", void, bool).documentation = "Tell the frontend to attach the debugger to the Unity editor. Used for debugging unit tests"
callback("allowSetForegroundWindow", void, bool).documentation = "Tell the frontend to call AllowSetForegroundWindow for the current Unity editor process ID. Called before the backend tells Unity to show itself"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.jetbrains.rd.ide.model.RdVirtualSolution
import com.jetbrains.rd.platform.util.idea.ProtocolSubscribedProjectComponent
import com.jetbrains.rd.util.reactive.valueOrDefault
import com.jetbrains.rd.util.reactive.whenTrue
import com.jetbrains.rider.model.*
import com.jetbrains.rider.plugins.unity.UnityProjectDiscoverer
import com.jetbrains.rider.plugins.unity.model.frontendBackend.frontendBackendModel
import com.jetbrains.rider.plugins.unity.explorer.UnityExplorer
Expand All @@ -28,6 +29,9 @@ import com.jetbrains.rider.projectDir
import com.jetbrains.rider.projectView.SolutionManager
import com.jetbrains.rider.projectView.solution
import com.jetbrains.rider.projectView.solutionDescription
import com.jetbrains.rider.projectView.workspace.ProjectModelEntity
import com.jetbrains.rider.projectView.workspace.ProjectModelEntityVisitor
import com.jetbrains.rider.projectView.workspace.getSolutionEntity
import javax.swing.event.HyperlinkEvent

class OpenUnityProjectAsFolderNotification(project: Project) : ProtocolSubscribedProjectComponent(project) {
Expand All @@ -49,7 +53,12 @@ class OpenUnityProjectAsFolderNotification(project: Project) : ProtocolSubscribe
it.launchNonUrgentBackground {
// Sometimes in Unity "External Script Editor" is set to "Open by file extension"
// We check that Library/EditorInstance.json is present, but protocol connection was not initialized
if (EditorInstanceJson.getInstance(project).status == EditorInstanceJsonStatus.Valid && !project.solution.frontendBackendModel.unityEditorConnected.valueOrDefault(false)) {
// also check that all projects are loaded fine
if (EditorInstanceJson.getInstance(project).status == EditorInstanceJsonStatus.Valid
&& !project.solution.frontendBackendModel.unityEditorConnected.valueOrDefault(false)
&& !hasUnloadedProjects(project)
) {

if (!UnityInstallationFinder.getInstance(project).requiresRiderPackage())
content = "Make sure Rider $marketingVersion is set as the External Editor in Unity preferences."
val notification = Notification(notificationGroupId.displayId, title, content, NotificationType.WARNING)
Expand Down Expand Up @@ -116,4 +125,22 @@ class OpenUnityProjectAsFolderNotification(project: Project) : ProtocolSubscribe
}
}
}

private fun hasUnloadedProjects(project: Project): Boolean {
val visitor = object : ProjectModelEntityVisitor() {
var unloadedProjects = 0

override fun visitUnloadedProject(entity: ProjectModelEntity): Result {
val state = (entity.descriptor as RdUnloadProjectDescriptor).state
if (state == RdUnloadProjectState.LoadFailed)
unloadedProjects++
return Result.Stop
}
}

val solutionEntity = WorkspaceModel.getInstance(project).getSolutionEntity() ?: return true
visitor.visit(solutionEntity)

return visitor.unloadedProjects > 0
}
}

This file was deleted.

1 change: 0 additions & 1 deletion rider/src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@

<project-components>
<component><implementation-class>com.jetbrains.rider.plugins.unity.ui.unitTesting.UnitTestLauncherState</implementation-class></component>
<component><implementation-class>com.jetbrains.rider.plugins.unity.notifications.OutOfSyncEditorNotification</implementation-class></component>
<component><implementation-class>com.jetbrains.rider.plugins.unity.notifications.YamlHugeFileNotification</implementation-class></component>
<component><implementation-class>com.jetbrains.rider.plugins.unity.notifications.AssetModeForceTextNotification</implementation-class></component>
<component><implementation-class>com.jetbrains.rider.plugins.unity.settings.RiderUnitySettings</implementation-class></component>
Expand Down