Skip to content

Instantly share code, notes, and snippets.

@CreatureSurvive
Last active May 9, 2022 23:39
Show Gist options
  • Save CreatureSurvive/f08f76427ec36599cfee9d35630b277e to your computer and use it in GitHub Desktop.
Save CreatureSurvive/f08f76427ec36599cfee9d35630b277e to your computer and use it in GitHub Desktop.
Unity editor tool to create dummy Unity projects to allow a single project to be open in multiple editor instances (Windows, Mac, Linux)
// NOTE:
// This is a modified version of https://gist.github.com/IronWarrior/005f649e443bf51b656729231d0b8af4
// This version adds support for Mac OS and Linux systems
//
// PURPOSE:
// Unity does not permit a project to be open in two different editor instances.
// This can be frustrating when building projects with multiplayer networking,
// as it would require you to create a build every time you wish you test your netcode.
// A workaround would be to duplicate the project, but this would require the duplicated
// project to be updated each time a change is made.
//
// Instead of duplicating the project, we create a new directory and populate it with
// junction links to our existing project's Assets, ProjectSettings and Packages directories.
// https://docs.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions#junctions
// The contents of these junctions are identical, but Unity will treat the directory containing
// them as a new project, allowing us to have multiple instances of our project open.
//
//
// TO USE THIS SCRIPT:
// Place it in your Unity project in a directory called "Editor". A new menu will appear
// on the top bar called "Unity Project Junction". Click it and Create Unity Junction Project.
// You can now open this "new" project in a separate Unity Editor instance.
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Diagnostics;
public class UnityProjectJunctionTool : MonoBehaviour
{
[MenuItem("Unity Project Junction/Create Junction Unity Project")]
private static void CreateJunctionUnityProject()
{
DirectoryInfo projectDirectoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());
string junctionDirectory = $"{projectDirectoryInfo.Name}-Junction";
string junctionPath = Path.Combine(projectDirectoryInfo.Parent.FullName, junctionDirectory);
if (Directory.Exists(junctionPath))
{
if (EditorUtility.DisplayDialog("Junction already exists",
$"Junction project directory already exists at {junctionPath}.\n\nWould you like to create another junction project?",
"Cancel", "Yes, create another"))
{
return;
}
else
{
int junctionIndex = 1;
do
{
junctionDirectory = $"{projectDirectoryInfo.Name}-Junction-{junctionIndex}";
junctionPath = Path.Combine(projectDirectoryInfo.Parent.FullName, junctionDirectory);
junctionIndex++;
}
while (Directory.Exists(junctionPath));
}
}
DirectoryInfo junctionDirectoryInfo = Directory.CreateDirectory(junctionPath);
string linkAssets = Path.Combine(junctionDirectoryInfo.FullName, "Assets");
string linkProjectSettings = Path.Combine(junctionDirectoryInfo.FullName, "ProjectSettings");
string linkPackages = Path.Combine(junctionDirectoryInfo.FullName, "Packages");
string targetAssets = Path.Combine(projectDirectoryInfo.FullName, "Assets");
string targetProjectSettings = Path.Combine(projectDirectoryInfo.FullName, "ProjectSettings");
string targetPackages = Path.Combine(projectDirectoryInfo.FullName, "Packages");
CreateJunction(linkAssets, targetAssets);
CreateJunction(linkProjectSettings, targetProjectSettings);
CreateJunction(linkPackages, targetPackages);
EditorUtility.DisplayDialog("Complete", $"Created junction project at {junctionPath}.\n\nYou may now open this new project in a separate Unity Editor instance.", "Ok");
EditorUtility.RevealInFinder(junctionDirectoryInfo.FullName);
}
private static void CreateJunction(string link, string target)
{
if(Application.platform == RuntimePlatform.WindowsEditor)
{
LinkWinOS(link, target);
}
else if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.LinuxEditor)
{
LinkMacLinOS(link, target);
}
}
public static void LinkWinOS(string link, string target)
{
string command = $"/C mklink /J \"{link}\" \"{target}\"";
Process.Start("cmd.exe", command);
}
public static void LinkMacLinOS(string link, string target)
{
string command = $"ln -s \"{target}\" \"{link}\"";
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = "-c \"" + command.Replace("\"", "\"\"") + "\"",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
}
};
proc.Start();
proc.WaitForExit();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment