Unity/Else

Unity Project Junction

๐ŸŸฆ Unity Project Junction

๋นŒ๋“œํ•˜๊ธฐ ์œ„ํ•ด ํ”Œ๋žซํผ์„ ๋ณ€๊ฒฝํ•ด์•ผํ•  ๋•Œ ํ”„๋กœ์ ํŠธ ํฌ๊ธฐ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ณ€ํ™˜ํ•˜๋Š” ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง„๋‹ค.

์ด๋Ÿด ๋•Œ Junction์„ ์ด์šฉํ•˜๋ฉด ํ”Œ๋žซํผ์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

 

๋ฉ€ํ‹ฐ๋ฅผ ์ง€์›ํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ Juction์„ ์ด์šฉํ•˜๋ฉด ํŽธ๋ฆฌํ•˜๋‹ค.

 

 

 

๐ŸŸง ์‚ฌ์šฉ๋ฒ•

// gist by Roystan (IronWarrior): https://gist.github.com/IronWarrior/005f649e443bf51b656729231d0b8af4
// Video demo: https://twitter.com/DavigoGame/status/1300842800964018178
//
// CONTRIBUTIONS:
// Mac and Linux support added by Creature Coding: https://creaturecoding.com/
//
// 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 static class UnityProjectJunctionTool
{
	[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();
	}

}

- ์œ„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์œ ๋‹ˆํ‹ฐ ๋‚ด Editor ํด๋” ์•ˆ์— ์ƒ์„ฑํ•œ๋‹ค.

 

 

 

- ์—๋””ํ„ฐ ์ƒ๋‹จ์— ์œ„์™€ ๊ฐ™์ด ๋ฉ”๋‰ด๊ฐ€ ์ƒ์„ฑ๋ผ์žˆ๋‹ค.

- ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ”„๋กœ์ ํŠธ ํด๋”์™€ ๋™์ผํ•œ ๊ฒฝ๋กœ์— ํ”„๋กœ์ ํŠธ๋ช…-Junction ์ด๋ผ๋Š” ๋ณต์‚ฌ๋ณธ์ด ์ƒ์„ฑ๋œ๋‹ค.

 

 

 

๐ŸŸง ์ฐธ๊ณ ์‚ฌํ•ญ

- ์›๋ณธ ํ”„๋กœ์ ํŠธ์—์„œ ์ˆ˜์ •ํ•œ ์Šคํฌ๋ฆฝํŠธ, ํ”„๋ฆฌํŒน, ์”ฌ๋“ค์€ Junction์—๋„ ์ ์šฉ์ด ๋œ๋‹ค.

- ๋ฐ˜๋Œ€๋กœ Juction์—์„œ ์ˆ˜์ •ํ•œ ๋‚ด์šฉ๋“ค๋„ ์›๋ณธ ํ”„๋กœ์ ํŠธ์—๋„ ์ ์šฉ์ด ๋œ๋‹ค.

 

- ํ”Œ๋žซํผ ์„ธํŒ…์€ ์ ์šฉ๋˜์ง€ ์•Š๊ธฐ๋•Œ๋ฌธ์— ๊ฐ๊ธฐ ๋‹ค๋ฅธ ํ”Œ๋žซํผ์œผ๋กœ ๋ณ€๊ฒฝํ•ด๋‘๋ฉด ๋นŒ๋“œ ์‹œ ํŽธ๋ฆฌํ•˜๋‹ค

   - ex ) ์›๋ณธ ํ”Œ๋žซํผ - Android, Junction ํ”Œ๋žซํผ - WebGL