Add templates and many other things
4
.idea/watcherTasks.xml
generated
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectTasksOptions" suppressed-tasks="Sass" />
|
||||||
|
</project>
|
1
Example Unity Project/.idea/.idea.Website-Upload-Sample/.idea/.name
generated
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Website-Upload-Sample
|
8
Example Unity Project/.idea/.idea.Website-Upload-Sample/.idea/indexLayout.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
Example Unity Project/.idea/.idea.Website-Upload-Sample/.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -2557,7 +2557,7 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 11500000, guid: 63883bd44af96e2d58b01169e5588f2c, type: 3}
|
m_Script: {fileID: 11500000, guid: 63883bd44af96e2d58b01169e5588f2c, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
url: http://127.0.0.1:5000/post
|
url: https://expo.leggy.dev/post
|
||||||
nameField: {fileID: 493760171}
|
nameField: {fileID: 493760171}
|
||||||
idField: {fileID: 2029744589}
|
idField: {fileID: 2029744589}
|
||||||
scoreField: {fileID: 2046180429}
|
scoreField: {fileID: 2046180429}
|
||||||
|
|
|
@ -112,10 +112,10 @@ MonoBehaviour:
|
||||||
y: 30
|
y: 30
|
||||||
width: 1856
|
width: 1856
|
||||||
height: 980
|
height: 980
|
||||||
m_MinSize: {x: 579, y: 492}
|
m_MinSize: {x: 578, y: 492}
|
||||||
m_MaxSize: {x: 14002, y: 14042}
|
m_MaxSize: {x: 14001, y: 14042}
|
||||||
vertical: 0
|
vertical: 0
|
||||||
controlID: 15
|
controlID: 96
|
||||||
--- !u!114 &6
|
--- !u!114 &6
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 52
|
m_ObjectHideFlags: 52
|
||||||
|
@ -135,12 +135,12 @@ MonoBehaviour:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 0
|
x: 0
|
||||||
y: 0
|
y: 0
|
||||||
width: 1429
|
width: 1495
|
||||||
height: 980
|
height: 980
|
||||||
m_MinSize: {x: 303, y: 492}
|
m_MinSize: {x: 303, y: 492}
|
||||||
m_MaxSize: {x: 10001, y: 14042}
|
m_MaxSize: {x: 10001, y: 14042}
|
||||||
vertical: 1
|
vertical: 1
|
||||||
controlID: 16
|
controlID: 97
|
||||||
--- !u!114 &7
|
--- !u!114 &7
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 52
|
m_ObjectHideFlags: 52
|
||||||
|
@ -160,12 +160,12 @@ MonoBehaviour:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 0
|
x: 0
|
||||||
y: 0
|
y: 0
|
||||||
width: 1429
|
width: 1495
|
||||||
height: 727
|
height: 712
|
||||||
m_MinSize: {x: 303, y: 221}
|
m_MinSize: {x: 303, y: 221}
|
||||||
m_MaxSize: {x: 8003, y: 4021}
|
m_MaxSize: {x: 8003, y: 4021}
|
||||||
vertical: 0
|
vertical: 0
|
||||||
controlID: 17
|
controlID: 98
|
||||||
--- !u!114 &8
|
--- !u!114 &8
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 52
|
m_ObjectHideFlags: 52
|
||||||
|
@ -183,10 +183,10 @@ MonoBehaviour:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 0
|
x: 0
|
||||||
y: 0
|
y: 0
|
||||||
width: 290
|
width: 360
|
||||||
height: 727
|
height: 712
|
||||||
m_MinSize: {x: 201, y: 221}
|
m_MinSize: {x: 200, y: 200}
|
||||||
m_MaxSize: {x: 4001, y: 4021}
|
m_MaxSize: {x: 4000, y: 4000}
|
||||||
m_ActualView: {fileID: 13}
|
m_ActualView: {fileID: 13}
|
||||||
m_Panes:
|
m_Panes:
|
||||||
- {fileID: 13}
|
- {fileID: 13}
|
||||||
|
@ -207,10 +207,10 @@ MonoBehaviour:
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Position:
|
m_Position:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 290
|
x: 360
|
||||||
y: 0
|
y: 0
|
||||||
width: 1139
|
width: 1135
|
||||||
height: 727
|
height: 712
|
||||||
m_MinSize: {x: 100, y: 100}
|
m_MinSize: {x: 100, y: 100}
|
||||||
m_MaxSize: {x: 4000, y: 4000}
|
m_MaxSize: {x: 4000, y: 4000}
|
||||||
m_ActualView: {fileID: 12}
|
m_ActualView: {fileID: 12}
|
||||||
|
@ -235,9 +235,9 @@ MonoBehaviour:
|
||||||
m_Position:
|
m_Position:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 0
|
x: 0
|
||||||
y: 727
|
y: 712
|
||||||
width: 1429
|
width: 1495
|
||||||
height: 253
|
height: 268
|
||||||
m_MinSize: {x: 231, y: 271}
|
m_MinSize: {x: 231, y: 271}
|
||||||
m_MaxSize: {x: 10001, y: 10021}
|
m_MaxSize: {x: 10001, y: 10021}
|
||||||
m_ActualView: {fileID: 15}
|
m_ActualView: {fileID: 15}
|
||||||
|
@ -262,12 +262,12 @@ MonoBehaviour:
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Position:
|
m_Position:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 1429
|
x: 1495
|
||||||
y: 0
|
y: 0
|
||||||
width: 427
|
width: 361
|
||||||
height: 980
|
height: 980
|
||||||
m_MinSize: {x: 276, y: 71}
|
m_MinSize: {x: 275, y: 50}
|
||||||
m_MaxSize: {x: 4001, y: 4021}
|
m_MaxSize: {x: 4000, y: 4000}
|
||||||
m_ActualView: {fileID: 18}
|
m_ActualView: {fileID: 18}
|
||||||
m_Panes:
|
m_Panes:
|
||||||
- {fileID: 18}
|
- {fileID: 18}
|
||||||
|
@ -294,10 +294,10 @@ MonoBehaviour:
|
||||||
m_Tooltip:
|
m_Tooltip:
|
||||||
m_Pos:
|
m_Pos:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 346
|
x: 416
|
||||||
y: 72
|
y: 72
|
||||||
width: 1137
|
width: 1133
|
||||||
height: 706
|
height: 691
|
||||||
m_ViewDataDictionary: {fileID: 0}
|
m_ViewDataDictionary: {fileID: 0}
|
||||||
m_SerializedViewNames: []
|
m_SerializedViewNames: []
|
||||||
m_SerializedViewValues: []
|
m_SerializedViewValues: []
|
||||||
|
@ -307,7 +307,7 @@ MonoBehaviour:
|
||||||
m_ShowGizmos: 0
|
m_ShowGizmos: 0
|
||||||
m_TargetDisplay: 0
|
m_TargetDisplay: 0
|
||||||
m_ClearColor: {r: 0, g: 0, b: 0, a: 0}
|
m_ClearColor: {r: 0, g: 0, b: 0, a: 0}
|
||||||
m_TargetSize: {x: 1137, y: 685}
|
m_TargetSize: {x: 1133, y: 670}
|
||||||
m_TextureFilterMode: 0
|
m_TextureFilterMode: 0
|
||||||
m_TextureHideFlags: 61
|
m_TextureHideFlags: 61
|
||||||
m_RenderIMGUI: 1
|
m_RenderIMGUI: 1
|
||||||
|
@ -322,10 +322,10 @@ MonoBehaviour:
|
||||||
m_VRangeLocked: 0
|
m_VRangeLocked: 0
|
||||||
hZoomLockedByDefault: 0
|
hZoomLockedByDefault: 0
|
||||||
vZoomLockedByDefault: 0
|
vZoomLockedByDefault: 0
|
||||||
m_HBaseRangeMin: -568.5
|
m_HBaseRangeMin: -566.5
|
||||||
m_HBaseRangeMax: 568.5
|
m_HBaseRangeMax: 566.5
|
||||||
m_VBaseRangeMin: -342.5
|
m_VBaseRangeMin: -335
|
||||||
m_VBaseRangeMax: 342.5
|
m_VBaseRangeMax: 335
|
||||||
m_HAllowExceedBaseRangeMin: 1
|
m_HAllowExceedBaseRangeMin: 1
|
||||||
m_HAllowExceedBaseRangeMax: 1
|
m_HAllowExceedBaseRangeMax: 1
|
||||||
m_VAllowExceedBaseRangeMin: 1
|
m_VAllowExceedBaseRangeMin: 1
|
||||||
|
@ -343,23 +343,23 @@ MonoBehaviour:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 0
|
x: 0
|
||||||
y: 21
|
y: 21
|
||||||
width: 1137
|
width: 1133
|
||||||
height: 685
|
height: 670
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
m_Translation: {x: 568.5, y: 342.5}
|
m_Translation: {x: 566.5, y: 335}
|
||||||
m_MarginLeft: 0
|
m_MarginLeft: 0
|
||||||
m_MarginRight: 0
|
m_MarginRight: 0
|
||||||
m_MarginTop: 0
|
m_MarginTop: 0
|
||||||
m_MarginBottom: 0
|
m_MarginBottom: 0
|
||||||
m_LastShownAreaInsideMargins:
|
m_LastShownAreaInsideMargins:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: -568.5
|
x: -566.5
|
||||||
y: -342.5
|
y: -335
|
||||||
width: 1137
|
width: 1133
|
||||||
height: 685
|
height: 670
|
||||||
m_MinimalGUI: 1
|
m_MinimalGUI: 1
|
||||||
m_defaultScale: 1
|
m_defaultScale: 1
|
||||||
m_LastWindowPixelSize: {x: 1137, y: 706}
|
m_LastWindowPixelSize: {x: 1133, y: 691}
|
||||||
m_ClearInEditMode: 1
|
m_ClearInEditMode: 1
|
||||||
m_NoCameraWarning: 1
|
m_NoCameraWarning: 1
|
||||||
m_LowResolutionForAspectRatios: 01000000000000000000
|
m_LowResolutionForAspectRatios: 01000000000000000000
|
||||||
|
@ -388,15 +388,15 @@ MonoBehaviour:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 56
|
x: 56
|
||||||
y: 72
|
y: 72
|
||||||
width: 289
|
width: 359
|
||||||
height: 706
|
height: 691
|
||||||
m_ViewDataDictionary: {fileID: 0}
|
m_ViewDataDictionary: {fileID: 0}
|
||||||
m_SceneHierarchy:
|
m_SceneHierarchy:
|
||||||
m_TreeViewState:
|
m_TreeViewState:
|
||||||
scrollPos: {x: 0, y: 0}
|
scrollPos: {x: 0, y: 0}
|
||||||
m_SelectedIDs: 90370000
|
m_SelectedIDs: 22380000
|
||||||
m_LastClickedID: 14224
|
m_LastClickedID: 14370
|
||||||
m_ExpandedIDs: 26d0ffff62d2ffff1adcffffaee0ffff66fbffff9037000098370000
|
m_ExpandedIDs: 66fbffff4c380000
|
||||||
m_RenameOverlay:
|
m_RenameOverlay:
|
||||||
m_UserAcceptedRename: 0
|
m_UserAcceptedRename: 0
|
||||||
m_Name:
|
m_Name:
|
||||||
|
@ -557,9 +557,9 @@ MonoBehaviour:
|
||||||
m_Pos:
|
m_Pos:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 56
|
x: 56
|
||||||
y: 799
|
y: 784
|
||||||
width: 1428
|
width: 1494
|
||||||
height: 232
|
height: 247
|
||||||
m_ViewDataDictionary: {fileID: 0}
|
m_ViewDataDictionary: {fileID: 0}
|
||||||
m_SearchFilter:
|
m_SearchFilter:
|
||||||
m_NameFilter:
|
m_NameFilter:
|
||||||
|
@ -580,14 +580,14 @@ MonoBehaviour:
|
||||||
m_LastFolders:
|
m_LastFolders:
|
||||||
- Assets
|
- Assets
|
||||||
m_LastFoldersGridSize: -1
|
m_LastFoldersGridSize: -1
|
||||||
m_LastProjectPath: /home/fluffy/GitHub/Website-Upload-Sample
|
m_LastProjectPath: /home/fluffy/GitHub/Highscores-Server/Example Unity Project
|
||||||
m_LockTracker:
|
m_LockTracker:
|
||||||
m_IsLocked: 0
|
m_IsLocked: 0
|
||||||
m_FolderTreeState:
|
m_FolderTreeState:
|
||||||
scrollPos: {x: 0, y: 0}
|
scrollPos: {x: 0, y: 0}
|
||||||
m_SelectedIDs: ca370000
|
m_SelectedIDs: 10390000
|
||||||
m_LastClickedID: 14282
|
m_LastClickedID: 14608
|
||||||
m_ExpandedIDs: 00000000ca37000000ca9a3b
|
m_ExpandedIDs: 000000001039000000ca9a3b
|
||||||
m_RenameOverlay:
|
m_RenameOverlay:
|
||||||
m_UserAcceptedRename: 0
|
m_UserAcceptedRename: 0
|
||||||
m_Name:
|
m_Name:
|
||||||
|
@ -615,7 +615,7 @@ MonoBehaviour:
|
||||||
scrollPos: {x: 0, y: 0}
|
scrollPos: {x: 0, y: 0}
|
||||||
m_SelectedIDs:
|
m_SelectedIDs:
|
||||||
m_LastClickedID: 0
|
m_LastClickedID: 0
|
||||||
m_ExpandedIDs: 00000000ca370000
|
m_ExpandedIDs: 0000000010390000
|
||||||
m_RenameOverlay:
|
m_RenameOverlay:
|
||||||
m_UserAcceptedRename: 0
|
m_UserAcceptedRename: 0
|
||||||
m_Name:
|
m_Name:
|
||||||
|
@ -640,8 +640,8 @@ MonoBehaviour:
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_ResourceFile:
|
m_ResourceFile:
|
||||||
m_ListAreaState:
|
m_ListAreaState:
|
||||||
m_SelectedInstanceIDs: 90370000
|
m_SelectedInstanceIDs:
|
||||||
m_LastClickedInstanceID: 14224
|
m_LastClickedInstanceID: 0
|
||||||
m_HadKeyboardFocusLastEvent: 0
|
m_HadKeyboardFocusLastEvent: 0
|
||||||
m_ExpandedInstanceIDs: c623000000000000
|
m_ExpandedInstanceIDs: c623000000000000
|
||||||
m_RenameOverlay:
|
m_RenameOverlay:
|
||||||
|
@ -693,9 +693,9 @@ MonoBehaviour:
|
||||||
m_Pos:
|
m_Pos:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 56
|
x: 56
|
||||||
y: 799
|
y: 784
|
||||||
width: 1428
|
width: 1494
|
||||||
height: 232
|
height: 247
|
||||||
m_ViewDataDictionary: {fileID: 0}
|
m_ViewDataDictionary: {fileID: 0}
|
||||||
--- !u!114 &17
|
--- !u!114 &17
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
|
@ -836,9 +836,9 @@ MonoBehaviour:
|
||||||
m_Tooltip:
|
m_Tooltip:
|
||||||
m_Pos:
|
m_Pos:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 1485
|
x: 1551
|
||||||
y: 72
|
y: 72
|
||||||
width: 426
|
width: 360
|
||||||
height: 959
|
height: 959
|
||||||
m_ViewDataDictionary: {fileID: 0}
|
m_ViewDataDictionary: {fileID: 0}
|
||||||
m_OpenAddComponentMenu: 0
|
m_OpenAddComponentMenu: 0
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"process_id" : 2062,
|
|
||||||
"version" : "2019.4.39f1",
|
|
||||||
"app_path" : "/home/fluffy/funnyfunnyies/Programing/Unity/2019.4.39f1/Editor/Unity",
|
|
||||||
"app_contents_path" : "/home/fluffy/funnyfunnyies/Programing/Unity/2019.4.39f1/Editor/Data"
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Access remote projects
|
||||||
|
|
||||||
|
1. In the Unity Hub v3 Beta, click **Open** > **Open Remote Project** to see the list of your Plastic SCM repositories that contain a Unity project.
|
||||||
|
Note: In Unity Hub 2.4.4 and up, your Plastic SCM projects will be listed alongside Collaborate projects.
|
||||||
|
2. Select the project and click **Next**.
|
||||||
|
3. Select the Editor version and platform and click the **change version** button.
|
||||||
|
4. Your local Plastic SCM workspace will be created for you. The latest version of the project will be downloaded and the Editor will open with the latest version of your Unity project.
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Add integrations
|
||||||
|
|
||||||
|
You can set up integrations for your Plastic SCM organization via your plasticscm.com Cloud Dashboard.
|
||||||
|
|
||||||
|
The Cloud dashboard gives you access to your organizations. From here, you can configure **triggers** (equivalent to integrations).
|
||||||
|
|
||||||
|
To configure a Slack notifications trigger:
|
||||||
|
|
||||||
|
1. On an organization, click **Configure** > **Triggers**.
|
||||||
|
2. Click **Add Trigger** > **Slack**.
|
||||||
|
3. In **Destination**, add your Slack channel name.
|
||||||
|
4. Select your trigger type and click **Save**.
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Add team members
|
||||||
|
|
||||||
|
To invite team members to contribute to your project:
|
||||||
|
|
||||||
|
|
||||||
|
1. Click the settings menu (gear icon) and click Invite Members to Workspace.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
2. In the Plastic SCM cloud dashboard, click Add new user.
|
||||||
|
|
||||||
|
You can also send invitations and add different permission types for each user.
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Create projects
|
||||||
|
|
||||||
|
To create projects after the upgrade:
|
||||||
|
|
||||||
|
1. In Unity, open the Plastic SCM window and click on **Create Workspace**.
|
||||||
|
Plastic SCM will suggest names for your repository (shared files and history) and workspace (your local copy).
|
||||||
|
|
||||||
|
If you wish to use an existing Plastic SCM repository, click the three dots next to the repository name, and select a repository from the list.
|
||||||
|
|
||||||
|
2. Select the type of workspace that fits your needs.
|
||||||
|
|
||||||
|
* **Plastic workspace**
|
||||||
|
With this workspace, you can work with branching and merging.
|
||||||
|
|
||||||
|
* **Gluon workspace**
|
||||||
|
This workspace tailored for artists allows you to pick the files you want to work on and check them back in without updating your whole workspace.
|
||||||
|
|
||||||
|
3. Add asset files associated with your project.
|
||||||
|
Plastic SCM will display the project files from the asset folder in the **Pending changes** tab. You can choose specific files to include or add all to the repository by selecting the files and clicking Checkin changes.
|
||||||
|
|
||||||
|
Plastic SCM will automatically perform a check in for appropriate folders and files – such as package files and project settings – when it’s set up from the Unity Editor. You can view these in the **Changesets tab.**
|
||||||
|
|
||||||
|
Once your initial asset check in is complete, you’re set up with Plastic SCM for Unity and ready to create.
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Getting started with an existing Plastic SCM repository
|
||||||
|
|
||||||
|
Suppose you want to start working on a Unity project in an existing Plastic SCM repository and already have a Plastic SCM account linked to your Unity ID. In that case, you will be able to open the project straight from the **Unity Hub**! A workspace will automatically be created for your project on your machine.
|
||||||
|
|
||||||
|
|
||||||
|
1. In the Unity Hub v3 Beta, click **Open** > **Open remote project** to see the list of your Plastic SCM repositories that contain a Unity project.
|
||||||
|
**Note**: In Unity Hub 2.4.4 and up, your Plastic SCM projects will be listed alongside Collaborate projects.
|
||||||
|
2. Click the project and click **Next**.
|
||||||
|
3. Click the Editor version and platform and click the **change version** button.
|
||||||
|
4. In the Editor pop-up, click the **Migrate** button to migrate your local workspace to a Plastic SCM workspace
|
||||||
|
5. Once the migration is completed, click the **Open Plastic SCM** button.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Accessing the Plastic SCM Window
|
||||||
|
|
||||||
|
You can access the **Plastic SCM** window in the Unity Editor by clicking **Window** > **Plastic SCM**.
|
||||||
|
|
||||||
|

|
|
@ -0,0 +1,11 @@
|
||||||
|
# Export Collaborate projects
|
||||||
|
|
||||||
|
To export your Project as a zip file that you can import into Plastic SCM:
|
||||||
|
|
||||||
|
1. Sign into the [Unity Developer Dashboard](https://developer.cloud.unity3d.com/).
|
||||||
|
2. At the top of the screen, click on the project name to open the dropdown list. Search for the project you'd like to export, then click on it to load its dashboard.
|
||||||
|
3. In the left navigation window, click **DevOps**. Scroll to the **Collaborate** section in the new navigation window when the new page loads, then click **Storage**.
|
||||||
|
4. Under **Exporting a Project**, click **Start Export** in the main window.
|
||||||
|
5. When the export is complete, click the **Download Export**. A zip file downloads onto your local machine.
|
||||||
|
|
||||||
|
The zip file contains all versions of all files stored in the Project’s repository, ready for import into Plastic SCM.
|
|
@ -0,0 +1,16 @@
|
||||||
|
# FAQ
|
||||||
|
|
||||||
|
**Which integration of Plastic SCM should I use in Unity moving forward?**
|
||||||
|
|
||||||
|
You should use the **Version Control package**, which contains Plastic SCM for Unity. This is the package the team will be actively working on moving forward.
|
||||||
|
|
||||||
|
* Plastic's standard version control integration has been removed from editor versions, and its functionality has been ported to the Version control package.
|
||||||
|
* The Asset store plugin functionality is deprecated, as the functionality from the plugin has been ported to the Version Control package.
|
||||||
|
|
||||||
|
**Where should I post questions related to Plastic SCM?**
|
||||||
|
|
||||||
|
Visit the [Unity forum](https://forum.unity.com/forums/plastic-scm.605/).
|
||||||
|
|
||||||
|
**I have a Collaborate project that I want to use with Plastic SCM. What should I do?**
|
||||||
|
|
||||||
|
To migrate your current Collaborate projects to Plastic SCM, see [Migration from Collaborate to Plastic SCM](MigrateCollab.md).
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Glossary
|
||||||
|
|
||||||
|
## General terms
|
||||||
|
|
||||||
|
#### Ignore file
|
||||||
|
|
||||||
|
A special file used in many **Version Control** Systems which specifies files to be excluded from **version control**. In Unity projects, several files can be excluded from **version control**. Using an Ignore File is the best way to achieve this. See [Using external version control systems with Unity](https://docs.unity3d.com/Manual/ExternalVersionControlSystemSupport.html).
|
||||||
|
|
||||||
|
#### Project
|
||||||
|
|
||||||
|
In Unity, you use a project to design and develop a game. A project stores all of the files related to a game, such as the asset and **Scene** files. See [2D or 3D projects](https://docs.unity3d.com/Manual/2Dor3D.html).
|
||||||
|
|
||||||
|
#### Version Control
|
||||||
|
|
||||||
|
A system for managing file changes. You can use Unity in conjunction with most **version control** tools, including **Perforce** , Git, Mercurial, and PlasticSCM. See [Version Control](https://docs.unity3d.com/Manual/VersionControl.html).
|
||||||
|
|
||||||
|
## Plastic SCM terms
|
||||||
|
|
||||||
|
#### Checkin
|
||||||
|
|
||||||
|
Checkin is the act of submitting changes to the repo. You must enter a comment in the text box before you can check in your changes.
|
||||||
|
|
||||||
|
#### Developer Workflow
|
||||||
|
|
||||||
|
Developers have access to the branch explorer directly from inside Unity and easily switch branches.
|
||||||
|
|
||||||
|
#### Gluon Workflow
|
||||||
|
|
||||||
|
Artists can take advantage of the Gluon visualized interface and workflow from inside Unity.
|
||||||
|
|
||||||
|
#### Organization
|
||||||
|
|
||||||
|
The organization handles different sets of repositories in the Cloud. Inside the organization, you can create as many repositories as you need.
|
||||||
|
|
||||||
|
#### Workspace
|
||||||
|
|
||||||
|
Your workspace interacts with the version control, where you download the files and make the required changes for each checkin.
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Overview of features
|
||||||
|
|
||||||
|
## Pending Changes
|
||||||
|
|
||||||
|
The **Pending Changes** tab allows you to view all pending changes in your workspace. These changes are not checked into the repository. In this tab, you can select which files you want to check in, add a comment, and check in the changes.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Note** : You can check in a specific file using the Plastic SCM contextual menu in the project view or the **Checkin** button in the **Inspector** window.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
In the example below, the user adds a GameScene. They can check in the scene using the **Pending Changes** tab or the **Checkin** option in the contextual menu.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Incoming Changes
|
||||||
|
|
||||||
|
The **Incoming Changes** tab allows you to view all incoming changes and conflicts and update your local project. Any changes made to your project prompts an "**Incoming changes**" notification at the top right of the Plastic SCM window.
|
||||||
|
|
||||||
|
**Tip** : Check the **Incoming Changes** tab frequently to avoid facing future change conflicts in your team.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Project History
|
||||||
|
|
||||||
|
Use the **Changesets** tab to view all changes made to your project as they occur chronologically, along with who made the changes and when. You can sort by columns and alter the chronological view of the story.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Double-click any file in a changeset to go to the **File History** tab, and display every changeset. In the **File History view**, right-click on a change and click **Save the revision as…** to restore the file's former state. This is useful if you had previously deleted some logic that you now need.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can also view the changes made to a specific file in the **Project view** through a contextual menu, then revert to an earlier revision of the file.
|
||||||
|
|
||||||
|

|
|
@ -0,0 +1,16 @@
|
||||||
|
# Upgrade from Collaborate without moving the history
|
||||||
|
|
||||||
|
|
||||||
|
If you're planning to lose all Collaborate history and just wish to move your project to Plastic as is, complete the following steps:
|
||||||
|
|
||||||
|
1. Open the project and disable Collaborate via the **Services** window.
|
||||||
|
2. Close Unity and make a new Plastic repository and workspace to house your project.
|
||||||
|
3. Do an initial set up on your repository (E.g. you may want to use an [ignore.conf file](ExistingPlasticRepo.md) that is specific to Unity projects).
|
||||||
|
4. Copy and paste your project into your new workspace.
|
||||||
|
5. Check in the content and continue working with the new workspace!
|
||||||
|
|
||||||
|
|
||||||
|
If you have the Version Control package installed in Unity, it is even easier!
|
||||||
|
|
||||||
|
1. Open the project and disable Collaborate via the **Services** window.
|
||||||
|
2. Open the Plastic SCM window in Unity and click on Create Workspace.
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Getting started with a new Plastic SCM repository
|
||||||
|
|
||||||
|
**Note**: To start from an existing Plastic SCM repository, see [Getting started with an existing Plastic SCM repository](ExistingPlasticRepo.md).
|
||||||
|
|
||||||
|
You can walk through a straightforward onboarding wizard when creating a repository for your Unity project. This new wizard will help you:
|
||||||
|
|
||||||
|
* Set up your account and configure your repository for your Unity project, enabling you to sync to a Plastic SCM Cloud Edition repository.
|
||||||
|
* Generate a standard ignore file that prevents unnecessary components of your Unity project from being checked in.
|
||||||
|
* Automatically do the first check-in so that your repository is in sync with your local changes.
|
||||||
|
|
||||||
|
1. Open your Unity project.
|
||||||
|
2. To access the Plastic SCM window in the Unity Editor, click **Window** > **Plastic SCM**:
|
||||||
|

|
||||||
|
|
||||||
|
3. In the Plastic SCM onboarding window, complete the steps to continue:
|
||||||
|

|
||||||
|
|
||||||
|
Unity connects your project to your Plastic SCM Cloud repository; Plastic SCM automatically creates an ignore file in the workspace for Unity projects so it doesn't track files that shouldn't be part of the repository. It also creates a standard automatic checkin during the initial setup. So now you're all set to start using Plastic SCM!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Note**: Basic version control actions, such as viewing pending changes, checking in changes, and viewing changesets, don’t require a Plastic SCM Client install. However, if you want to use more advanced features, such as branching and diffing changeset, you will be prompted to download the Plastic SCM client (if you have not already done so):
|
||||||
|
|
||||||
|

|
|
@ -0,0 +1,14 @@
|
||||||
|
# Plastic SCM for Git users
|
||||||
|
|
||||||
|
|
||||||
|
| **GIT**| **Plastic**| **Explanation**|
|
||||||
|
|:--|:--|:--|
|
||||||
|
| To Commit| To Check in| To Check in is to submit changes to the repo.|
|
||||||
|
| Commit| Changeset| Each new change on the history of the repo, grouping several individual file and directory changes.|
|
||||||
|
| Master| Main| When you create a repo in Plastic, there's always an "empty" branch. Plastic calls it Main.|
|
||||||
|
| To checkout | To update| Downloading content to the workspace (working copy). This is called "update" because in Plastic, "checkout" has a different meaning.|
|
||||||
|
|| Checkout| When you checkout a file in Plastic, you're telling Plastic you are going to modify the file.|
|
||||||
|
|| Exclusive checkout or lock | This is locking a file so nobody can touch it. It’s only useful for non-mergeable files, like binaries, images, or art in a video game.|
|
||||||
|
| Rebase|| Plastic handles branching differently than Git. In Plastic, a rebase is just a merge operation.|
|
||||||
|
| Repository | Repository| Where the entire history of the project is stored.
|
||||||
|
| Working copy | Workspace| In Git, you have the working copy and the repository in the exact location. You have a working copy and a .git hidden dir with the repository. In Plastic, this is slightly different since repositories and workspaces are separated. You can have several workspaces working with the same local repository.
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Quick start guide
|
||||||
|
|
||||||
|
The Version Control package will allow you to use Plastic SCM for Unity for your projects in the Unity Editor.
|
||||||
|
|
||||||
|
Plastic SCM for Unity integrates Plastic SCM in Unity that will abstract version control complexity, like Collaborate. It will also enable you to work collaboratively on more complex projects by providing additional VCS features such as branching, locking, merging, and a standalone GUI.
|
||||||
|
|
||||||
|
**Note** : For information on upgrading projects from Collaborate to Plastic SCM, see [Upgrade from Collaborate to Plastic SCM](UpgradeCollab.md).
|
||||||
|
|
||||||
|
|
||||||
|
The Version Control package follows the Unity support schedule. Currently, supported versions are:
|
||||||
|
|
||||||
|
* 2019.4.29f1
|
||||||
|
* 2020.3.15f1
|
||||||
|
* 2021.1.15f1
|
||||||
|
* 2021.2.0b6
|
||||||
|
* 2022.1.0a4
|
||||||
|
|
||||||
|
|
||||||
|
[Getting started with Plastic SCM for Unity](StartPlasticForUnity.md)
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Reconnect Unity Cloud Build
|
||||||
|
|
||||||
|
If you were using Cloud Build with Collaborate, you will need to reconnect Cloud build to use with Plastic SCM.
|
||||||
|
|
||||||
|
1. In the Unity dashboard, go to the **Projects** page and click your project.
|
||||||
|
2. Click **DevOps** > **Cloud Build** > **Config**.
|
||||||
|
3. In **Source Control Settings**, click **Edit Source Control**.
|
||||||
|
4. In the **Source Control window**, click the **Plastic SCM** tile.
|
||||||
|
5. Add the name of your organization with @cloud after it. For example, Exampleproject@cloud.
|
||||||
|
6. Click **Next**.
|
||||||
|
7. If everything is correct, click the **Continue With Unity ID** button.
|
||||||
|
8. Cloud Build is now connected to your project via Plastic SCM.
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Getting started with Plastic SCM for Unity
|
||||||
|
|
||||||
|
Plastic SCM for Unity will allow you to use Plastic SCM directly in Unity and is available via the Version Control package in the Unity Package Manager.
|
||||||
|
|
||||||
|
You will need to uninstall the Plastic SCM Asset Store plugin from your Unity project in order to use Plastic SCM for Unity via the Version Control package. Here are the steps to do so:
|
||||||
|
|
||||||
|
1. Navigate to your Assets/Plugins folder in your Unity Project.
|
||||||
|
Delete the PlasticSCM folder.
|
||||||
|
2. Re-open your Unity Project to recompile your packages.
|
||||||
|
|
||||||
|
**Note**: The .plastic workspace folder in the root of the Unity Project does not need to be removed as it can be read by the Version Control package.
|
||||||
|
|
||||||
|
**Important**: Enabling the Plastic SCM for Unity package will disable the standard VCS integration option in the Project Settings (this option will be removed from future Editor releases), which was an older integration previously offered in the Editor. Features available in the standard integration have been ported to the Plastic SCM for Unity package. This is the version that will be actively developed and maintained going forward.
|
||||||
|
|
||||||
|
Learn more about [Plastic SCM Cloud Edition](https://unity.com/products/plastic-scm).
|
||||||
|
|
||||||
|
* To start with a new Plastic SCM repository for your project, see [Getting started with a New Plastic SCM repository](NewPlasticRepo.md)
|
||||||
|
* To start from an existing Plastic SCM repository, see [Getting started with an existing Plastic SCM repository](ExistingPlasticRepo.md)
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Switch between Collaborate and Plastic SCM
|
||||||
|
|
||||||
|
To switch from Collaborate to Plastic SCM, open your **Project Settings** > **Services** > **Collaborate** and switch off Collaborate to start using Plastic SCM.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
To switch from Plastic SCM to Collaborate, navigate to your Plastic SCM window, select **Settings** (gear icon) > **Turn off Plastic SCM for Unity**.
|
||||||
|
|
||||||
|

|
|
@ -0,0 +1,24 @@
|
||||||
|
[About version control](index.md)
|
||||||
|
|
||||||
|
* [Quick start guide](QuickStartGuide.md)
|
||||||
|
* [Upgrade from Collaborate to Plastic SCM](UpgradeCollab.md)
|
||||||
|
* [Upgrade from Collaborate without moving the history](MigrateCollabHistory.md)
|
||||||
|
* [Switch between Collaborate and Plastic SCM](SwitchCollabAndPlastic.md)
|
||||||
|
* [Create projects](CreateProjects.md)
|
||||||
|
* [Access remote projects](AccessRemoteProjects.md)
|
||||||
|
* [Export Collaborate projects](ExportCollabProjects.md)
|
||||||
|
* [Add team members](AddMembers.md)
|
||||||
|
* [Reconnect Cloud Build](ReconnectCB.md)
|
||||||
|
* [Add integrations](AddIntegrations.md)
|
||||||
|
* [Getting started with Plastic SCM for Unity](StartPlasticForUnity.md)
|
||||||
|
* [Getting started with a new Plastic SCM repository](NewPlasticRepo.md)
|
||||||
|
* [Getting started with an existing Plastic SCM repository](ExistingPlasticRepo.md)
|
||||||
|
* [Main features](MainFeatures.md)
|
||||||
|
* [Pending Changes](MainFeatures.md#pending-changes)
|
||||||
|
* [Incoming Changes](MainFeatures.md#incoming-changes)
|
||||||
|
* [Project History](MainFeatures.md#project-history)
|
||||||
|
* [Plastic SCM for Git users](PlasticForGitUsers.md)
|
||||||
|
* [Glossary](Glossary.md)
|
||||||
|
* [General terms](Glossary.md#general-terms)
|
||||||
|
* [Plastic SCM terms](Glossary.md#plastic-scm-terms)
|
||||||
|
* [FAQ](Faq.md)
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Upgrade from Collaborate to Plastic SCM
|
||||||
|
|
||||||
|
To migrate your Collab projects to Plastic SCM:
|
||||||
|
|
||||||
|
1. Create a Collab project and upload your latest changes so that your project is in sync.
|
||||||
|
2. Go to the [Collab Migration Wizard](https://www.plasticscm.com/plasticscm-cloud-edition/migrate-unity-projects/) site.
|
||||||
|
3. Complete the process to migrate every Collab project in a Unity org.
|
||||||
|
4. Wait until you receive an email from Plastic SCM that the migration process has finished.
|
||||||
|
5. Re-open the same Collab project in Unity.
|
||||||
|
6. The Migration guide will pop up, guiding you through the process of converting your local instance of your Collab project into a local instance of your Plastic workspace.
|
||||||
|
7. Once it finishes, you can continue working on your project, using the Plastic SCM window to check in your changes.
|
||||||
|
|
||||||
|
**Videos**
|
||||||
|
|
||||||
|
* [Migration Wizard](https://youtu.be/TKZuvPMprKg)
|
||||||
|
* [Plastic SCM Plugin Dev workflow](https://youtu.be/6_x3SLCiyWo)
|
||||||
|
* [Plastic SCM Plugin Gluon workflow](https://youtu.be/kfRu21cArGc)
|
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 120 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 3 MiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 3.8 MiB |
|
@ -0,0 +1,12 @@
|
||||||
|
# About Version Control
|
||||||
|
|
||||||
|
The Version Control package provides an in-editor interface for teams to work with Collaborate and Plastic SCM.
|
||||||
|
|
||||||
|
## Collaborate
|
||||||
|
|
||||||
|
Collaborate makes it easy for teams to save, share, and sync their Unity projects with others, regardless of location. It's cloud-enabled and built directly into Unity. Please refer to the [Unity Collaborate Manual.](https://docs.unity3d.com/Manual/UnityCollaborate.html)
|
||||||
|
|
||||||
|
## Plastic SCM
|
||||||
|
|
||||||
|
Plastic SCM Plugin for Unity is a free Unity plugin that gives you the ability to use Plastic SCM, a leading version control solution, directly in Unity. Get started with [Plastic SCM](QuickStartGuide.md).
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Custom Nunit build to work with Unity
|
||||||
|
|
||||||
|
This version of nunit works with all platforms, il2cpp and Mono AOT.
|
||||||
|
|
||||||
|
For Nunit Documentation:
|
||||||
|
https://github.com/nunit/docs/wiki/NUnit-Documentation
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Code Editor Package for Rider
|
||||||
|
|
||||||
|
This package is not intended to be modified by users.
|
||||||
|
Nor does it provide any api intended to be included in user projects.
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Code Editor Package for Visual Studio
|
||||||
|
|
||||||
|
This package is not intended to be modified by users.
|
||||||
|
Nor does it provide any api intended to be included in user projects.
|
|
@ -0,0 +1,2 @@
|
||||||
|
* [About Visual Studio Editor](index.md)
|
||||||
|
* [Using the Visual Studio Editor package](using-visual-studio-editor.md)
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Code Editor Package for Visual Studio
|
||||||
|
|
||||||
|
## About Visual Studio Editor
|
||||||
|
|
||||||
|
The Visual Studio Editor package provides the Unity Editor with support for Unity-specific features from the [Visual Studio Tools for Unity](https://docs.microsoft.com/en-us/visualstudio/gamedev/unity/get-started/visual-studio-tools-for-unity) extension in [Visual Studio](https://visualstudio.microsoft.com/) and [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/). These include IntelliSense auto-complete suggestions, C# editing, and debugging.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This package is a built-in package and installed by default.
|
||||||
|
|
||||||
|
**Note**: If you’re using a version of the Unity Editor before 2019.4, you’ll need to install this package through the package manager.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
This version of the Visual Studio Editor package is compatible with the following versions of the Unity Editor:
|
||||||
|
|
||||||
|
* 2019.4 and later
|
||||||
|
|
||||||
|
To use this package, you must have the following third-party products installed:
|
||||||
|
|
||||||
|
* **On Windows**: Visual Studio 2019 version 16.9 or newer with Visual Studio Tools for Unity 4.0.9 or newer.
|
||||||
|
* **On macOS**: Visual Studio for Mac 2019 version 8.9 or newer with Visual Studio Tools for Unity 2.0.9 or newer.
|
||||||
|
|
||||||
|
For more information about using Visual Studio with Unity, see [Microsoft’s Visual Studio Tools for Unity documentation](https://docs.microsoft.com/en-us/visualstudio/gamedev/unity/get-started/visual-studio-tools-for-unity).
|
||||||
|
|
||||||
|
## Submitting issues
|
||||||
|
|
||||||
|
This package is maintained by Microsoft and Unity. Submit issues directly from Visual Studio and Visual Studio for Mac from the **Help** > **Submit Feedback** > **Report a Problem** menu. Unity will make this package accessible to the public on GitHub in the future.
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Using the Visual Studio Editor package
|
||||||
|
|
||||||
|
To use the package, go to **Edit** > **Preferences** > **External Tools** > **External Script Editor** and select the version of **Visual Studio** you have installed. When you select this option, the window reloads and displays settings that control production of .csproj files.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Generate .csproj files
|
||||||
|
|
||||||
|
Each setting in the table below enables or disables the production of .csproj files for a different type of package.When you click **Regenerate project files**, Unity updates the existing .csproj files and creates the necessary new ones based on the settings you choose.
|
||||||
|
|
||||||
|
|
||||||
|
These settings control whether to generate .csproj files for any installed packages. For more information on how to install packages, see [Adding and removing packages](https://docs.unity3d.com/Manual/upm-ui-actions.html).
|
||||||
|
|
||||||
|
| **Property** | **Description** |
|
||||||
|
|---|---|
|
||||||
|
| **Embedded packages** | Any package that appears under your project’s Packages folder is an embedded package. An embedded package is not necessarily built-in; you can create your own packages and embed them inside your project. This setting is enabled by default.<br/><br/>For more information on embedded packages, see [Embedded dependencies](https://docs.unity3d.com/Manual/upm-embed.html). |
|
||||||
|
| **Local packages** | Any package that you install from a local repository stored on your machine, but from outside of your Unity project. This setting is enabled by default. |
|
||||||
|
| **Registry packages** | Any package that you install from either the official Unity registry or a custom registry. Packages in the Unity registry are available to install directly from the Package Manager. For more information about the Unity package registry, see The Package Registry section of the [Unity Package Manager documentation](https://docs.unity3d.com/Packages/com.unity.package-manager-ui@1.8/manual/index.html#PackManRegistry). <br/><br/>For information on how to create and use custom registries in addition to the Unity registry, see [Scoped package registries](https://docs.unity3d.com/Manual/upm-scoped.html). |
|
||||||
|
| **Git packages** | Any package you install directly from a Git repository using a URL. |
|
||||||
|
| **Built-in packages** | Any package that is already installed as part of the default Unity installation. |
|
||||||
|
| **Tarball packages** | Any package you install from a GZip tarball archive on the local machine, outside of your Unity project. |
|
||||||
|
| **Unknown packages** | Any package which Unity cannot determine an origin for. This could be because the package doesn’t list its origin, or that Unity doesn’t recognize the origin listed. |
|
||||||
|
| **Player projects** | For each player project, generate an additional .csproj file named ‘originalProjectName.Player.csproj’. This allows different project types to have their code included in Visual Studio’s systems, such as assembly definitions or testing suites. |
|
|
@ -0,0 +1,308 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 50;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
E08E02FF236392D000A4B1BE /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = E08E02FE236392D000A4B1BE /* main.mm */; };
|
||||||
|
E08E03022363933B00A4B1BE /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E08E03012363933B00A4B1BE /* AppKit.framework */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
E08E02F5236392A300A4B1BE /* AppleEventIntegration.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AppleEventIntegration.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
E08E02F8236392A300A4B1BE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
E08E02FE236392D000A4B1BE /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
|
||||||
|
E08E03012363933B00A4B1BE /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
E08E02F2236392A300A4B1BE /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
E08E03022363933B00A4B1BE /* AppKit.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
E08E02EC236392A300A4B1BE = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E08E02F7236392A300A4B1BE /* AppleEventIntegration */,
|
||||||
|
E08E02F6236392A300A4B1BE /* Products */,
|
||||||
|
E08E03002363933B00A4B1BE /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
E08E02F6236392A300A4B1BE /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E08E02F5236392A300A4B1BE /* AppleEventIntegration.bundle */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
E08E02F7236392A300A4B1BE /* AppleEventIntegration */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E08E02F8236392A300A4B1BE /* Info.plist */,
|
||||||
|
E08E02FE236392D000A4B1BE /* main.mm */,
|
||||||
|
);
|
||||||
|
path = AppleEventIntegration;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
E08E03002363933B00A4B1BE /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E08E03012363933B00A4B1BE /* AppKit.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
E08E02F4236392A300A4B1BE /* AppleEventIntegration */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = E08E02FB236392A300A4B1BE /* Build configuration list for PBXNativeTarget "AppleEventIntegration" */;
|
||||||
|
buildPhases = (
|
||||||
|
E08E02F1236392A300A4B1BE /* Sources */,
|
||||||
|
E08E02F2236392A300A4B1BE /* Frameworks */,
|
||||||
|
E08E02F3236392A300A4B1BE /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = AppleEventIntegration;
|
||||||
|
productName = AppleEventIntegration;
|
||||||
|
productReference = E08E02F5236392A300A4B1BE /* AppleEventIntegration.bundle */;
|
||||||
|
productType = "com.apple.product-type.bundle";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
E08E02ED236392A300A4B1BE /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 1200;
|
||||||
|
ORGANIZATIONNAME = Unity;
|
||||||
|
TargetAttributes = {
|
||||||
|
E08E02F4236392A300A4B1BE = {
|
||||||
|
CreatedOnToolsVersion = 11.1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = E08E02F0236392A300A4B1BE /* Build configuration list for PBXProject "AppleEventIntegration" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = E08E02EC236392A300A4B1BE;
|
||||||
|
productRefGroup = E08E02F6236392A300A4B1BE /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
E08E02F4236392A300A4B1BE /* AppleEventIntegration */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
E08E02F3236392A300A4B1BE /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
E08E02F1236392A300A4B1BE /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
E08E02FF236392D000A4B1BE /* main.mm in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
E08E02F9236392A300A4B1BE /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
E08E02FA236392A300A4B1BE /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
E08E02FC236392A300A4B1BE /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
INFOPLIST_FILE = AppleEventIntegration/Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.unity.visualstudio.AppleEventIntegration;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
WRAPPER_EXTENSION = bundle;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
E08E02FD236392A300A4B1BE /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
INFOPLIST_FILE = AppleEventIntegration/Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.unity.visualstudio.AppleEventIntegration;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
WRAPPER_EXTENSION = bundle;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
E08E02F0236392A300A4B1BE /* Build configuration list for PBXProject "AppleEventIntegration" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
E08E02F9236392A300A4B1BE /* Debug */,
|
||||||
|
E08E02FA236392A300A4B1BE /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
E08E02FB236392A300A4B1BE /* Build configuration list for PBXNativeTarget "AppleEventIntegration" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
E08E02FC236392A300A4B1BE /* Debug */,
|
||||||
|
E08E02FD236392A300A4B1BE /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = E08E02ED236392A300A4B1BE /* Project object */;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:AppleEventIntegration.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2019 Unity. All rights reserved.</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,286 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Unity Technologies.
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
// 'FSnd' FourCC
|
||||||
|
#define keyFileSender 1179872868
|
||||||
|
|
||||||
|
// 16 bit aligned legacy struct - this should total 20 bytes
|
||||||
|
struct SelectionRange
|
||||||
|
{
|
||||||
|
int16_t unused1; // 0 (not used)
|
||||||
|
int16_t lineNum; // line to select (<0 to specify range)
|
||||||
|
int32_t startRange; // start of selection range (if line < 0)
|
||||||
|
int32_t endRange; // end of selection range (if line < 0)
|
||||||
|
int32_t unused2; // 0 (not used)
|
||||||
|
int32_t theDate; // modification date/time
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
static NSString* MakeNSString(const char* str)
|
||||||
|
{
|
||||||
|
if (!str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
NSString* ret = [NSString stringWithUTF8String: str];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UInt32 GetCreatorOfThisApp()
|
||||||
|
{
|
||||||
|
static UInt32 creator = 0;
|
||||||
|
if (creator == 0)
|
||||||
|
{
|
||||||
|
UInt32 type;
|
||||||
|
CFBundleGetPackageInfo(CFBundleGetMainBundle(), &type, &creator);
|
||||||
|
}
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL OpenFileAtLineWithAppleEvent(NSRunningApplication *runningApp, NSString* path, int line)
|
||||||
|
{
|
||||||
|
if (!runningApp)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
NSURL *pathUrl = [NSURL fileURLWithPath: path];
|
||||||
|
|
||||||
|
NSAppleEventDescriptor* targetDescriptor = [NSAppleEventDescriptor
|
||||||
|
descriptorWithProcessIdentifier: runningApp.processIdentifier];
|
||||||
|
|
||||||
|
NSAppleEventDescriptor* appleEvent = [NSAppleEventDescriptor
|
||||||
|
appleEventWithEventClass: kCoreEventClass
|
||||||
|
eventID: kAEOpenDocuments
|
||||||
|
targetDescriptor: targetDescriptor
|
||||||
|
returnID: kAutoGenerateReturnID
|
||||||
|
transactionID: kAnyTransactionID];
|
||||||
|
|
||||||
|
[appleEvent
|
||||||
|
setParamDescriptor: [NSAppleEventDescriptor
|
||||||
|
descriptorWithDescriptorType: typeFileURL
|
||||||
|
data: [[pathUrl absoluteString] dataUsingEncoding: NSUTF8StringEncoding]]
|
||||||
|
forKeyword: keyDirectObject];
|
||||||
|
|
||||||
|
UInt32 packageCreator = GetCreatorOfThisApp();
|
||||||
|
if (packageCreator == kUnknownType) {
|
||||||
|
[appleEvent
|
||||||
|
setParamDescriptor: [NSAppleEventDescriptor
|
||||||
|
descriptorWithDescriptorType: typeApplicationBundleID
|
||||||
|
data: [[[NSBundle mainBundle] bundleIdentifier] dataUsingEncoding: NSUTF8StringEncoding]]
|
||||||
|
forKeyword: keyFileSender];
|
||||||
|
} else {
|
||||||
|
[appleEvent
|
||||||
|
setParamDescriptor: [NSAppleEventDescriptor descriptorWithTypeCode: packageCreator]
|
||||||
|
forKeyword: keyFileSender];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line != -1) {
|
||||||
|
// Add selection range to event
|
||||||
|
SelectionRange range;
|
||||||
|
range.unused1 = 0;
|
||||||
|
range.lineNum = line - 1;
|
||||||
|
range.startRange = -1;
|
||||||
|
range.endRange = -1;
|
||||||
|
range.unused2 = 0;
|
||||||
|
range.theDate = -1;
|
||||||
|
|
||||||
|
[appleEvent
|
||||||
|
setParamDescriptor: [NSAppleEventDescriptor
|
||||||
|
descriptorWithDescriptorType: typeChar
|
||||||
|
bytes: &range
|
||||||
|
length: sizeof(SelectionRange)]
|
||||||
|
forKeyword: keyAEPosition];
|
||||||
|
}
|
||||||
|
|
||||||
|
AEDesc reply = { typeNull, NULL };
|
||||||
|
OSErr err = AESendMessage(
|
||||||
|
[appleEvent aeDesc],
|
||||||
|
&reply,
|
||||||
|
kAENoReply + kAENeverInteract,
|
||||||
|
kAEDefaultTimeout);
|
||||||
|
|
||||||
|
return err == noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL ApplicationSupportsQueryOpenedSolution(NSString* appPath)
|
||||||
|
{
|
||||||
|
NSURL* appUrl = [NSURL fileURLWithPath: appPath];
|
||||||
|
NSBundle* bundle = [NSBundle bundleWithURL: appUrl];
|
||||||
|
|
||||||
|
if (!bundle)
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
id versionValue = [bundle objectForInfoDictionaryKey: @"CFBundleVersion"];
|
||||||
|
if (!versionValue || ![versionValue isKindOfClass: [NSString class]])
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
NSString* version = (NSString*)versionValue;
|
||||||
|
return [version compare:@"8.6" options:NSNumericSearch] != NSOrderedAscending;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSArray<NSRunningApplication*>* QueryRunningInstances(NSString *appPath)
|
||||||
|
{
|
||||||
|
NSMutableArray<NSRunningApplication*>* instances = [[NSMutableArray alloc] init];
|
||||||
|
NSURL *appUrl = [NSURL fileURLWithPath: appPath];
|
||||||
|
|
||||||
|
for (NSRunningApplication *runningApp in NSWorkspace.sharedWorkspace.runningApplications) {
|
||||||
|
if (![runningApp isTerminated] && [runningApp.bundleURL isEqual: appUrl]) {
|
||||||
|
[instances addObject: runningApp];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instances;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kWorkspaceEventClass = 1448302419, /* 'VSWS' FourCC */
|
||||||
|
kCurrentSelectedSolutionPathEventID = 1129534288 /* 'CSSP' FourCC */
|
||||||
|
};
|
||||||
|
|
||||||
|
static BOOL TryQueryCurrentSolutionPath(NSRunningApplication* runningApp, NSString** solutionPath)
|
||||||
|
{
|
||||||
|
NSAppleEventDescriptor* targetDescriptor = [NSAppleEventDescriptor
|
||||||
|
descriptorWithProcessIdentifier: runningApp.processIdentifier];
|
||||||
|
|
||||||
|
NSAppleEventDescriptor* appleEvent = [NSAppleEventDescriptor
|
||||||
|
appleEventWithEventClass: kWorkspaceEventClass
|
||||||
|
eventID: kCurrentSelectedSolutionPathEventID
|
||||||
|
targetDescriptor: targetDescriptor
|
||||||
|
returnID: kAutoGenerateReturnID
|
||||||
|
transactionID: kAnyTransactionID];
|
||||||
|
|
||||||
|
AEDesc aeReply = { 0, };
|
||||||
|
|
||||||
|
OSErr sendResult = AESendMessage(
|
||||||
|
[appleEvent aeDesc],
|
||||||
|
&aeReply,
|
||||||
|
kAEWaitReply | kAENeverInteract,
|
||||||
|
kAEDefaultTimeout);
|
||||||
|
|
||||||
|
if (sendResult != noErr) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSAppleEventDescriptor *reply = [[NSAppleEventDescriptor alloc] initWithAEDescNoCopy: &aeReply];
|
||||||
|
*solutionPath = [[reply descriptorForKeyword: keyDirectObject] stringValue];
|
||||||
|
|
||||||
|
return *solutionPath != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSRunningApplication* QueryRunningApplicationOpenedOnSolution(NSString* appPath, NSString* solutionPath)
|
||||||
|
{
|
||||||
|
BOOL supportsQueryOpenedSolution = ApplicationSupportsQueryOpenedSolution(appPath);
|
||||||
|
|
||||||
|
for (NSRunningApplication *runningApp in QueryRunningInstances(appPath)) {
|
||||||
|
// If the currently selected external editor does not support the opened solution apple event
|
||||||
|
// then fallback to the previous behavior: take the first opened VSM and open the solution
|
||||||
|
if (!supportsQueryOpenedSolution) {
|
||||||
|
OpenFileAtLineWithAppleEvent(runningApp, solutionPath, -1);
|
||||||
|
return runningApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString* currentSolutionPath;
|
||||||
|
if (TryQueryCurrentSolutionPath(runningApp, ¤tSolutionPath)) {
|
||||||
|
if ([solutionPath isEqual:currentSolutionPath]) {
|
||||||
|
return runningApp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If VSM doesn't respond to the query opened solution event
|
||||||
|
// we fallback to the previous behavior too
|
||||||
|
OpenFileAtLineWithAppleEvent(runningApp, solutionPath, -1);
|
||||||
|
return runningApp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSRunningApplication* LaunchApplicationOnSolution(NSString* appPath, NSString* solutionPath)
|
||||||
|
{
|
||||||
|
NSURL* appUrl = [NSURL fileURLWithPath: appPath];
|
||||||
|
NSMutableDictionary* config = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
|
NSRunningApplication* runningApp = [[NSWorkspace sharedWorkspace]
|
||||||
|
launchApplicationAtURL: appUrl
|
||||||
|
options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance
|
||||||
|
configuration: config
|
||||||
|
error: nil];
|
||||||
|
|
||||||
|
OpenFileAtLineWithAppleEvent(runningApp, solutionPath, -1);
|
||||||
|
|
||||||
|
return runningApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSRunningApplication* QueryOrLaunchApplication(NSString* appPath, NSString* solutionPath)
|
||||||
|
{
|
||||||
|
NSRunningApplication* runningApp = QueryRunningApplicationOpenedOnSolution(appPath, solutionPath);
|
||||||
|
|
||||||
|
if (!runningApp)
|
||||||
|
runningApp = LaunchApplicationOnSolution(appPath, solutionPath);
|
||||||
|
|
||||||
|
if (runningApp)
|
||||||
|
[runningApp activateWithOptions: 0];
|
||||||
|
|
||||||
|
return runningApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LaunchOrReuseApp(NSString* appPath, NSString* solutionPath, NSRunningApplication** outApp)
|
||||||
|
{
|
||||||
|
NSRunningApplication* app = QueryOrLaunchApplication(appPath, solutionPath);
|
||||||
|
|
||||||
|
if (outApp)
|
||||||
|
*outApp = app;
|
||||||
|
|
||||||
|
return app != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL MonoDevelopOpenFile(NSString* appPath, NSString* solutionPath, NSString* filePath, int line)
|
||||||
|
{
|
||||||
|
NSRunningApplication* runningApp;
|
||||||
|
if (!LaunchOrReuseApp(appPath, solutionPath, &runningApp)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filePath) {
|
||||||
|
return OpenFileAtLineWithAppleEvent(runningApp, filePath, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BUILD_APP
|
||||||
|
|
||||||
|
int main(int argc, const char** argv)
|
||||||
|
{
|
||||||
|
if (argc != 5) {
|
||||||
|
printf("Usage: AppleEventIntegration appPath solutionPath filePath lineNumber\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* appPath = argv[1];
|
||||||
|
const char* solutionPath = argv[2];
|
||||||
|
const char* filePath = argv[3];
|
||||||
|
const int lineNumber = atoi(argv[4]);
|
||||||
|
|
||||||
|
@autoreleasepool
|
||||||
|
{
|
||||||
|
MonoDevelopOpenFile(MakeNSString(appPath), MakeNSString(solutionPath), MakeNSString(filePath), lineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
BOOL OpenVisualStudio(const char* appPath, const char* solutionPath, const char* filePath, int line)
|
||||||
|
{
|
||||||
|
return MonoDevelopOpenFile(MakeNSString(appPath), MakeNSString(solutionPath), MakeNSString(filePath), line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
#include <OleAuto.h>
|
||||||
|
|
||||||
|
struct BStrHolder
|
||||||
|
{
|
||||||
|
BStrHolder() :
|
||||||
|
m_Str(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BStrHolder(const wchar_t* str) :
|
||||||
|
m_Str(SysAllocString(str))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~BStrHolder()
|
||||||
|
{
|
||||||
|
if (m_Str != NULL)
|
||||||
|
SysFreeString(m_Str);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator BSTR() const
|
||||||
|
{
|
||||||
|
return m_Str;
|
||||||
|
}
|
||||||
|
|
||||||
|
BSTR* operator&()
|
||||||
|
{
|
||||||
|
if (m_Str != NULL)
|
||||||
|
{
|
||||||
|
SysFreeString(m_Str);
|
||||||
|
m_Str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &m_Str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BSTR m_Str;
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1f68874d6ae00db4a993b9507d065658
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 1
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
project(com)
|
||||||
|
set(SOURCES
|
||||||
|
COMIntegration.cpp
|
||||||
|
BStrHolder.h
|
||||||
|
ComPtr.h
|
||||||
|
dte80a.tlh
|
||||||
|
)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -Wall")
|
||||||
|
add_executable(COMIntegration ${SOURCES})
|
||||||
|
set_property(TARGET COMIntegration PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
|
||||||
|
target_link_libraries(COMIntegration Shlwapi.lib)
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7cec3e1820a40be4486946c20d7ffd00
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,470 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Unity Technologies.
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
|
||||||
|
#include "BStrHolder.h"
|
||||||
|
#include "ComPtr.h"
|
||||||
|
#include "dte80a.tlh"
|
||||||
|
|
||||||
|
constexpr int RETRY_INTERVAL_MS = 150;
|
||||||
|
constexpr int TIMEOUT_MS = 10000;
|
||||||
|
|
||||||
|
// Often a DTE call made to Visual Studio can fail after Visual Studio has just started. Usually the
|
||||||
|
// return value will be RPC_E_CALL_REJECTED, meaning that Visual Studio is probably busy on another
|
||||||
|
// thread. This types filter the RPC messages and retries to send the message until VS accepts it.
|
||||||
|
class CRetryMessageFilter : public IMessageFilter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static bool ShouldRetryCall(DWORD dwTickCount, DWORD dwRejectType)
|
||||||
|
{
|
||||||
|
if (dwRejectType == SERVERCALL_RETRYLATER || dwRejectType == SERVERCALL_REJECTED) {
|
||||||
|
return dwTickCount < TIMEOUT_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
win::ComPtr<IMessageFilter> currentFilter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRetryMessageFilter()
|
||||||
|
{
|
||||||
|
HRESULT hr = CoRegisterMessageFilter(this, ¤tFilter);
|
||||||
|
_ASSERT(SUCCEEDED(hr));
|
||||||
|
}
|
||||||
|
|
||||||
|
~CRetryMessageFilter()
|
||||||
|
{
|
||||||
|
win::ComPtr<IMessageFilter> messageFilter;
|
||||||
|
HRESULT hr = CoRegisterMessageFilter(currentFilter, &messageFilter);
|
||||||
|
_ASSERT(SUCCEEDED(hr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// IUnknown methods
|
||||||
|
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv)
|
||||||
|
{
|
||||||
|
static const QITAB qit[] =
|
||||||
|
{
|
||||||
|
QITABENT(CRetryMessageFilter, IMessageFilter),
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
return QISearch(this, qit, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD STDMETHODCALLTYPE HandleInComingCall(DWORD dwCallType, HTASK htaskCaller, DWORD dwTickCount, LPINTERFACEINFO lpInterfaceInfo)
|
||||||
|
{
|
||||||
|
if (currentFilter)
|
||||||
|
return currentFilter->HandleInComingCall(dwCallType, htaskCaller, dwTickCount, lpInterfaceInfo);
|
||||||
|
|
||||||
|
return SERVERCALL_ISHANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD STDMETHODCALLTYPE RetryRejectedCall(HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType)
|
||||||
|
{
|
||||||
|
if (ShouldRetryCall(dwTickCount, dwRejectType))
|
||||||
|
return RETRY_INTERVAL_MS;
|
||||||
|
|
||||||
|
if (currentFilter)
|
||||||
|
return currentFilter->RetryRejectedCall(htaskCallee, dwTickCount, dwRejectType);
|
||||||
|
|
||||||
|
return (DWORD)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD STDMETHODCALLTYPE MessagePending(HTASK htaskCallee, DWORD dwTickCount, DWORD dwPendingType)
|
||||||
|
{
|
||||||
|
if (currentFilter)
|
||||||
|
return currentFilter->MessagePending(htaskCallee, dwTickCount, dwPendingType);
|
||||||
|
|
||||||
|
return PENDINGMSG_WAITDEFPROCESS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void DisplayProgressbar() {
|
||||||
|
std::wcout << "displayProgressBar" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClearProgressbar() {
|
||||||
|
std::wcout << "clearprogressbar" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const std::wstring QuoteString(const std::wstring& str)
|
||||||
|
{
|
||||||
|
return L"\"" + str + L"\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::wstring ErrorCodeToMsg(DWORD code)
|
||||||
|
{
|
||||||
|
LPWSTR msgBuf = nullptr;
|
||||||
|
if (!FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, nullptr))
|
||||||
|
{
|
||||||
|
return L"Unknown error";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return msgBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an environment variable
|
||||||
|
static std::wstring GetEnvironmentVariableValue(const std::wstring& variableName) {
|
||||||
|
DWORD currentBufferSize = MAX_PATH;
|
||||||
|
std::wstring variableValue;
|
||||||
|
variableValue.resize(currentBufferSize);
|
||||||
|
|
||||||
|
DWORD requiredBufferSize = GetEnvironmentVariableW(variableName.c_str(), variableValue.data(), currentBufferSize);
|
||||||
|
if (requiredBufferSize == 0) {
|
||||||
|
// Environment variable probably does not exist.
|
||||||
|
return std::wstring();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentBufferSize < requiredBufferSize) {
|
||||||
|
variableValue.resize(requiredBufferSize);
|
||||||
|
if (GetEnvironmentVariableW(variableName.c_str(), variableValue.data(), currentBufferSize) == 0)
|
||||||
|
return std::wstring();
|
||||||
|
}
|
||||||
|
|
||||||
|
variableValue.resize(requiredBufferSize);
|
||||||
|
return variableValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool StartVisualStudioProcess(
|
||||||
|
const std::filesystem::path &visualStudioExecutablePath,
|
||||||
|
const std::filesystem::path &solutionPath,
|
||||||
|
DWORD *dwProcessId) {
|
||||||
|
|
||||||
|
STARTUPINFOW si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
BOOL result;
|
||||||
|
|
||||||
|
ZeroMemory(&si, sizeof(si));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
ZeroMemory(&pi, sizeof(pi));
|
||||||
|
|
||||||
|
std::wstring startingDirectory = visualStudioExecutablePath.parent_path();
|
||||||
|
|
||||||
|
// Build the command line that is passed as the argv of the VS process
|
||||||
|
// argv[0] must be the quoted full path to the VS exe
|
||||||
|
std::wstringstream commandLineStream;
|
||||||
|
commandLineStream << QuoteString(visualStudioExecutablePath) << L" ";
|
||||||
|
|
||||||
|
std::wstring vsArgsWide = GetEnvironmentVariableValue(L"UNITY_VS_ARGS");
|
||||||
|
if (!vsArgsWide.empty())
|
||||||
|
commandLineStream << vsArgsWide << L" ";
|
||||||
|
|
||||||
|
commandLineStream << QuoteString(solutionPath);
|
||||||
|
|
||||||
|
std::wstring commandLine = commandLineStream.str();
|
||||||
|
|
||||||
|
std::wcout << "Starting Visual Studio process with: " << commandLine << std::endl;
|
||||||
|
|
||||||
|
result = CreateProcessW(
|
||||||
|
visualStudioExecutablePath.c_str(), // Full path to VS, must not be quoted
|
||||||
|
commandLine.data(), // Command line, as passed as argv, separate arguments must be quoted if they contain spaces
|
||||||
|
nullptr, // Process handle not inheritable
|
||||||
|
nullptr, // Thread handle not inheritable
|
||||||
|
false, // Set handle inheritance to FALSE
|
||||||
|
0, // No creation flags
|
||||||
|
nullptr, // Use parent's environment block
|
||||||
|
startingDirectory.c_str(), // starting directory set to the VS directory
|
||||||
|
&si,
|
||||||
|
&pi);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
std::wcout << "Starting Visual Studio process failed: " << ErrorCodeToMsg(error) << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dwProcessId = pi.dwProcessId;
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithSolution(
|
||||||
|
const std::filesystem::path &visualStudioExecutablePath,
|
||||||
|
const std::filesystem::path &solutionPath)
|
||||||
|
{
|
||||||
|
win::ComPtr<IUnknown> punk = nullptr;
|
||||||
|
win::ComPtr<EnvDTE::_DTE> dte = nullptr;
|
||||||
|
|
||||||
|
CRetryMessageFilter retryMessageFilter;
|
||||||
|
|
||||||
|
// Search through the Running Object Table for an instance of Visual Studio
|
||||||
|
// to use that either has the correct solution already open or does not have
|
||||||
|
// any solution open.
|
||||||
|
win::ComPtr<IRunningObjectTable> ROT;
|
||||||
|
if (FAILED(GetRunningObjectTable(0, &ROT)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
win::ComPtr<IBindCtx> bindCtx;
|
||||||
|
if (FAILED(CreateBindCtx(0, &bindCtx)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
win::ComPtr<IEnumMoniker> enumMoniker;
|
||||||
|
if (FAILED(ROT->EnumRunning(&enumMoniker)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
win::ComPtr<IMoniker> moniker;
|
||||||
|
ULONG monikersFetched = 0;
|
||||||
|
while (SUCCEEDED(enumMoniker->Next(1, &moniker, &monikersFetched)) && monikersFetched) {
|
||||||
|
if (FAILED(ROT->GetObject(moniker, &punk)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
punk.As(&dte);
|
||||||
|
if (!dte)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Okay, so we found an actual running instance of Visual Studio.
|
||||||
|
|
||||||
|
// Get the executable path of this running instance.
|
||||||
|
BStrHolder visualStudioFullName;
|
||||||
|
if (FAILED(dte->get_FullName(&visualStudioFullName)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::filesystem::path currentVisualStudioExecutablePath = std::wstring(visualStudioFullName);
|
||||||
|
|
||||||
|
// Ask for its current solution.
|
||||||
|
win::ComPtr<EnvDTE::_Solution> solution;
|
||||||
|
if (FAILED(dte->get_Solution(&solution)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Get the name of that solution.
|
||||||
|
BStrHolder solutionFullName;
|
||||||
|
if (FAILED(solution->get_FullName(&solutionFullName)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::filesystem::path currentSolutionPath = std::wstring(solutionFullName);
|
||||||
|
if (currentSolutionPath.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::wcout << "Visual Studio opened on " << currentSolutionPath.wstring() << std::endl;
|
||||||
|
|
||||||
|
// If the name matches the solution we want to open and we have a Visual Studio installation path to use and this one matches that path, then use it.
|
||||||
|
// If we don't have a Visual Studio installation path to use, just use this solution.
|
||||||
|
if (std::filesystem::equivalent(currentSolutionPath, solutionPath)) {
|
||||||
|
std::wcout << "We found a running Visual Studio session with the solution open." << std::endl;
|
||||||
|
if (!visualStudioExecutablePath.empty()) {
|
||||||
|
if (std::filesystem::equivalent(currentVisualStudioExecutablePath, visualStudioExecutablePath)) {
|
||||||
|
return dte;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::wcout << "This running Visual Studio session does not seem to be the version requested in the user preferences. We will keep looking." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::wcout << "We're not sure which version of Visual Studio was requested in the user preferences. We will use this running session." << std::endl;
|
||||||
|
return dte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
MonikerIsVisualStudioProcess(const win::ComPtr<IMoniker> &moniker, const win::ComPtr<IBindCtx> &bindCtx, const DWORD dwProcessId) {
|
||||||
|
LPOLESTR oleMonikerName;
|
||||||
|
if (FAILED(moniker->GetDisplayName(bindCtx, nullptr, &oleMonikerName)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::wstring monikerName(oleMonikerName);
|
||||||
|
|
||||||
|
// VisualStudio Moniker is "!VisualStudio.DTE.$Version:$PID"
|
||||||
|
// Example "!VisualStudio.DTE.14.0:1234"
|
||||||
|
|
||||||
|
if (monikerName.find(L"!VisualStudio.DTE") != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::wstringstream suffixStream;
|
||||||
|
suffixStream << ":";
|
||||||
|
suffixStream << dwProcessId;
|
||||||
|
|
||||||
|
std::wstring suffix(suffixStream.str());
|
||||||
|
|
||||||
|
return monikerName.length() - suffix.length() == monikerName.find(suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
static win::ComPtr<EnvDTE::_DTE> FindRunningVisualStudioWithPID(const DWORD dwProcessId) {
|
||||||
|
win::ComPtr<IUnknown> punk = nullptr;
|
||||||
|
win::ComPtr<EnvDTE::_DTE> dte = nullptr;
|
||||||
|
|
||||||
|
// Search through the Running Object Table for a Visual Studio
|
||||||
|
// process with the process ID specified
|
||||||
|
win::ComPtr<IRunningObjectTable> ROT;
|
||||||
|
if (FAILED(GetRunningObjectTable(0, &ROT)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
win::ComPtr<IBindCtx> bindCtx;
|
||||||
|
if (FAILED(CreateBindCtx(0, &bindCtx)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
win::ComPtr<IEnumMoniker> enumMoniker;
|
||||||
|
if (FAILED(ROT->EnumRunning(&enumMoniker)))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
win::ComPtr<IMoniker> moniker;
|
||||||
|
ULONG monikersFetched = 0;
|
||||||
|
while (SUCCEEDED(enumMoniker->Next(1, &moniker, &monikersFetched)) && monikersFetched) {
|
||||||
|
if (FAILED(ROT->GetObject(moniker, &punk)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!MonikerIsVisualStudioProcess(moniker, bindCtx, dwProcessId))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
punk.As(&dte);
|
||||||
|
if (dte)
|
||||||
|
return dte;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HaveRunningVisualStudioOpenFile(const win::ComPtr<EnvDTE::_DTE> &dte, const std::filesystem::path &filename, int line) {
|
||||||
|
BStrHolder bstrFileName(filename.c_str());
|
||||||
|
BStrHolder bstrKind(L"{00000000-0000-0000-0000-000000000000}"); // EnvDTE::vsViewKindPrimary
|
||||||
|
win::ComPtr<EnvDTE::Window> window = nullptr;
|
||||||
|
|
||||||
|
CRetryMessageFilter retryMessageFilter;
|
||||||
|
|
||||||
|
if (!filename.empty()) {
|
||||||
|
std::wcout << "Getting operations API from the Visual Studio session." << std::endl;
|
||||||
|
|
||||||
|
win::ComPtr<EnvDTE::ItemOperations> item_ops;
|
||||||
|
if (FAILED(dte->get_ItemOperations(&item_ops)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::wcout << "Waiting for the Visual Studio session to open the file: " << filename.wstring() << "." << std::endl;
|
||||||
|
|
||||||
|
if (FAILED(item_ops->OpenFile(bstrFileName, bstrKind, &window)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (line > 0) {
|
||||||
|
win::ComPtr<IDispatch> selection_dispatch;
|
||||||
|
if (window && SUCCEEDED(window->get_Selection(&selection_dispatch))) {
|
||||||
|
win::ComPtr<EnvDTE::TextSelection> selection;
|
||||||
|
if (selection_dispatch &&
|
||||||
|
SUCCEEDED(selection_dispatch->QueryInterface(__uuidof(EnvDTE::TextSelection), &selection)) &&
|
||||||
|
selection) {
|
||||||
|
selection->GotoLine(line, false);
|
||||||
|
selection->EndOfLine(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window = nullptr;
|
||||||
|
if (SUCCEEDED(dte->get_MainWindow(&window))) {
|
||||||
|
// Allow the DTE to make its main window the foreground
|
||||||
|
HWND hWnd;
|
||||||
|
window->get_HWnd((LONG *)&hWnd);
|
||||||
|
|
||||||
|
DWORD processID;
|
||||||
|
if (SUCCEEDED(GetWindowThreadProcessId(hWnd, &processID)))
|
||||||
|
AllowSetForegroundWindow(processID);
|
||||||
|
|
||||||
|
// Activate() set the window to visible and active (blinks in taskbar)
|
||||||
|
window->Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool VisualStudioOpenFile(
|
||||||
|
const std::filesystem::path &visualStudioExecutablePath,
|
||||||
|
const std::filesystem::path &solutionPath,
|
||||||
|
const std::filesystem::path &filename,
|
||||||
|
int line)
|
||||||
|
{
|
||||||
|
win::ComPtr<EnvDTE::_DTE> dte = nullptr;
|
||||||
|
|
||||||
|
std::wcout << "Looking for a running Visual Studio session." << std::endl;
|
||||||
|
|
||||||
|
// TODO: If path does not exist pass empty, which will just try to match all windows with solution
|
||||||
|
dte = FindRunningVisualStudioWithSolution(visualStudioExecutablePath, solutionPath);
|
||||||
|
|
||||||
|
if (!dte) {
|
||||||
|
std::wcout << "No appropriate running Visual Studio session not found, creating a new one." << std::endl;
|
||||||
|
|
||||||
|
DisplayProgressbar();
|
||||||
|
|
||||||
|
DWORD dwProcessId;
|
||||||
|
if (!StartVisualStudioProcess(visualStudioExecutablePath, solutionPath, &dwProcessId)) {
|
||||||
|
ClearProgressbar();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timeWaited = 0;
|
||||||
|
|
||||||
|
while (timeWaited < TIMEOUT_MS) {
|
||||||
|
dte = FindRunningVisualStudioWithPID(dwProcessId);
|
||||||
|
|
||||||
|
if (dte)
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::wcout << "Retrying to acquire DTE" << std::endl;
|
||||||
|
|
||||||
|
Sleep(RETRY_INTERVAL_MS);
|
||||||
|
timeWaited += RETRY_INTERVAL_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearProgressbar();
|
||||||
|
|
||||||
|
if (!dte)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::wcout << "Using the existing Visual Studio session." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HaveRunningVisualStudioOpenFile(dte, filename, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
int wmain(int argc, wchar_t* argv[]) {
|
||||||
|
if (argc != 3 && argc != 5) {
|
||||||
|
std::wcerr << argc << ": wrong number of arguments\n" << "Usage: com.exe installationPath solutionPath [fileName lineNumber]" << std::endl;
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
std::wcerr << argv[i] << std::endl;
|
||||||
|
}
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(CoInitialize(nullptr))) {
|
||||||
|
std::wcerr << "CoInitialize failed." << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path visualStudioExecutablePath = std::filesystem::absolute(argv[1]);
|
||||||
|
std::filesystem::path solutionPath = std::filesystem::absolute(argv[2]);
|
||||||
|
|
||||||
|
if (argc == 3) {
|
||||||
|
VisualStudioOpenFile(visualStudioExecutablePath, solutionPath, L"", -1);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path fileName = std::filesystem::absolute(argv[3]);
|
||||||
|
int lineNumber = std::stoi(argv[4]);
|
||||||
|
|
||||||
|
VisualStudioOpenFile(visualStudioExecutablePath, solutionPath, fileName, lineNumber);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6ffa4010724f8d54aacbed867d4a5aa6
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 1
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,186 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace win
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
class ComPtr;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ComPtrRef
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ComPtr<T>& m_ComPtr;
|
||||||
|
|
||||||
|
ComPtrRef(ComPtr<T>& comPtr) :
|
||||||
|
m_ComPtr(comPtr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class ComPtr<T>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline operator T**()
|
||||||
|
{
|
||||||
|
return m_ComPtr.ReleaseAndGetAddressOf();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator void**()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<void**>(m_ComPtr.ReleaseAndGetAddressOf());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T* operator*() throw ()
|
||||||
|
{
|
||||||
|
return m_ComPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ComPtr
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
T *ptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline ComPtr(void) : ptr(NULL) {}
|
||||||
|
inline ~ComPtr(void) { this->Free(); }
|
||||||
|
|
||||||
|
ComPtr(T *ptr)
|
||||||
|
{
|
||||||
|
if (NULL != (this->ptr = ptr))
|
||||||
|
{
|
||||||
|
this->ptr->AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr(const ComPtr &ptr)
|
||||||
|
{
|
||||||
|
if (NULL != (this->ptr = ptr.ptr))
|
||||||
|
{
|
||||||
|
this->ptr->AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!() const
|
||||||
|
{
|
||||||
|
return (NULL == this->ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator T*() const { return this->ptr; }
|
||||||
|
|
||||||
|
inline T *operator->() const
|
||||||
|
{
|
||||||
|
//_assert(NULL != this->ptr);
|
||||||
|
return this->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T &operator*()
|
||||||
|
{
|
||||||
|
//_assert(NULL != this->ptr);
|
||||||
|
return *this->ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ComPtrRef<T> operator&()
|
||||||
|
{
|
||||||
|
return ComPtrRef<T>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComPtr &operator=(T *ptr)
|
||||||
|
{
|
||||||
|
if (this->ptr != ptr)
|
||||||
|
{
|
||||||
|
this->Free();
|
||||||
|
|
||||||
|
if (NULL != (this->ptr = ptr))
|
||||||
|
{
|
||||||
|
this->ptr->AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComPtr &operator=(const ComPtr &ptr)
|
||||||
|
{
|
||||||
|
if (this->ptr != ptr.ptr)
|
||||||
|
{
|
||||||
|
this->Free();
|
||||||
|
|
||||||
|
if (NULL != (this->ptr = ptr.ptr))
|
||||||
|
{
|
||||||
|
this->ptr->AddRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Free(void)
|
||||||
|
{
|
||||||
|
if (NULL != this->ptr)
|
||||||
|
{
|
||||||
|
this->ptr->Release();
|
||||||
|
this->ptr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T** ReleaseAndGetAddressOf()
|
||||||
|
{
|
||||||
|
Free();
|
||||||
|
return &ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
inline HRESULT As(ComPtrRef<U> p) const throw ()
|
||||||
|
{
|
||||||
|
return ptr->QueryInterface(__uuidof(U), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return this->ptr == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
inline bool operator==(U* other)
|
||||||
|
{
|
||||||
|
if (ptr == nullptr || other == nullptr)
|
||||||
|
return ptr == other;
|
||||||
|
|
||||||
|
ComPtr<IUnknown> meUnknown;
|
||||||
|
ComPtr<IUnknown> otherUnknown;
|
||||||
|
|
||||||
|
if (FAILED(this->ptr->QueryInterface(__uuidof(IUnknown), &meUnknown)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (FAILED(other->QueryInterface(__uuidof(IUnknown), &otherUnknown)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return static_cast<IUnknown*>(meUnknown) == static_cast<IUnknown*>(otherUnknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
inline bool operator==(ComPtr<U>& other)
|
||||||
|
{
|
||||||
|
return *this == static_cast<U*>(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return this->ptr != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
inline bool operator!=(U* other)
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename U>
|
||||||
|
inline bool operator!=(ComPtr<U>& other)
|
||||||
|
{
|
||||||
|
return *this != static_cast<U*>(other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 013868b12dff0dc43adcc33513ae71bf
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 1
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 97115cd910ade104a9d05d65a6b6b7d9
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1 @@
|
||||||
|
cl /EHsc /std:c++17 COMIntegration.cpp /link Shlwapi.lib /out:"..\Release\COMIntegration.exe"
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3b44687349be79f4184ba013fb6ffa0c
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Code Editor Package for Visual Studio Code
|
||||||
|
|
||||||
|
This package is not intended to be modified by users.
|
||||||
|
Nor does it provide any api intended to be included in user projects.
|
|
@ -0,0 +1,19 @@
|
||||||
|
# com.unity.sysroot.linux-x86_64
|
||||||
|
|
||||||
|
The Linux-x86_64 sysroot package supplies the Linux x86_64 sysroot for building Linux IL2CPP players.
|
||||||
|
You don’t need to install this package manually. The package manager automatically installs this package, along with com.unity.sysroot. You only need to install your chosen toolchain package.
|
||||||
|
|
||||||
|
For an overview of unity sysroot packages, see [Unity Sysroot Package documentation](https://docs.unity3d.com/Packages/com.unity.sysroot@0.1/manual/index.html).
|
||||||
|
|
||||||
|
This package is available as a pre-release package, so it is still in the process of becoming stable enough to release. The features and documentation in this package might change before it is ready for release.
|
||||||
|
## Installation
|
||||||
|
To install this package, refer to the instructions that match your Unity Editor version:
|
||||||
|
### Version 2021.1 and later
|
||||||
|
To install this package, make sure you [enable pre-release packages](https://docs.unity3d.com/2021.1/Documentation/Manual/class-PackageManager.html#advanced_preview) in the Unity Editor's Package Manager, and then follow the [installation instructions in the Unity User Manual](https://docs.unity3d.com/Documentation/Manual/upm-ui-install.html).
|
||||||
|
### Version 2020.3
|
||||||
|
To install this package, make sure you [show preview packages](https://docs.unity3d.com/2020.3/Documentation/Manual/class-PackageManager.html#advanced_preview) in the Unity Editor's Package Manager, and then follow the [installation instructions in the Unity User Manual](https://docs.unity3d.com/2020.3/Documentation/Manual/upm-ui-install.html).
|
||||||
|
### Version 2019.4
|
||||||
|
To install this package, make sure you [show preview packages](https://docs.unity3d.com/2019.4/Documentation/Manual/upm-ui-list.html#ShowPreview) in the Unity Editor's Package Manager, and then follow the [installation instructions in the Unity User Manual](https://docs.unity3d.com/2019.4/Documentation/Manual/upm-ui-install.html).
|
||||||
|
|
||||||
|
|
||||||
|
[!include[choosingbuilding](./snippets/choosingbuilding.md)]
|
|
@ -0,0 +1,13 @@
|
||||||
|
## Choosing the correct toolchain package
|
||||||
|
|
||||||
|
When you install a package to build the Linux IL2CPP player, choose the *com.unity.toolchain.* package based on your host (Editor) platform:
|
||||||
|
|
||||||
|
- Linux x86_64: com.unity.toolchain.linux-x86_64
|
||||||
|
- MacOS x86_64: com.unity.toolchain.macos-x86_64-linux-x86_64
|
||||||
|
- Windows x86_64: com.unity.toolchain.win-x86_64-linux-x86_64
|
||||||
|
|
||||||
|
## Building a Linux IL2CPP player
|
||||||
|
|
||||||
|
When you have installed your toolchain package, go to **Project Settings** > **Player** > **Configuration** and set the **ScriptingBackend** to **IL2CPP**.
|
||||||
|
|
||||||
|
To build your project go to **File** > **Build Settings**, in the **Target Platform** dropdown select **Linux,** then click **Build** or **Build and Run.**
|
After Width: | Height: | Size: 349 KiB |
After Width: | Height: | Size: 154 KiB |
|
@ -0,0 +1,53 @@
|
||||||
|
# Unity IL2CPP Build Support for Linux
|
||||||
|
|
||||||
|
Support for Linux players using IL2CPP is available from 2019.4 onwards.
|
||||||
|
|
||||||
|
Operating systems (OS) have their own build systems which vary from one another. If you build using the headers and libraries on a particular OS, this might result in the built player not running on a different one. To address this, Unity provides a sysroot to build against which works on all supported Linux platforms.
|
||||||
|
|
||||||
|
The sysroot also allows cross-compilation support which enables you to build Linux IL2CPP from Linux, macOS and Windows.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
To use the following packages, you need to install the Linux Build Support (IL2CPP) module in your Unity Editor version. Use the Unity Hub to do this. For further information, see [Adding Modules to the Unity Editor](https://docs.unity3d.com/2021.2/Documentation/Manual/GettingStartedAddingEditorComponents.html).
|
||||||
|
|
||||||
|
## Unity toolchain packages
|
||||||
|
|
||||||
|
Unity provides a toolchain package, which installs the sysroot and a toolchain, for building binaries for the target. The naming convention for these packages is:
|
||||||
|
|
||||||
|
* _host platform and architecture_
|
||||||
|
* _target platform and architecture_
|
||||||
|
|
||||||
|
If the host platform and architecture are the same as the target platform and architecture, shorten the name to platform and architecture.
|
||||||
|
|
||||||
|
## Installing a Unity toolchain package
|
||||||
|
|
||||||
|
To install a Unity toolchain package:
|
||||||
|
1. Go to **Window** > **Package Manager**.
|
||||||
|
2. Use the search bar to find the package, and click **Install** in the bottom right corner of the Package Manager window.
|
||||||
|
3. Choose the package based on the host platform.
|
||||||
|
|
||||||
|
| Host | Package |
|
||||||
|
| ------- | ---------------------------------------- |
|
||||||
|
| Linux | com.unity.toolchain.linux-x86_64 |
|
||||||
|
| macOS | com.unity.toolchain.macos-x86_64-linux-x86_64 |
|
||||||
|
| Windows | com.unity.toolchain.windows.x86_64-linux-x86_64 |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Using a Unity toolchain package:
|
||||||
|
|
||||||
|
When you have installed your toolchain package, go to **Project Settings** > **Player** > **Configuration** and set the **ScriptingBackend** to **IL2CPP**.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
To build your project:
|
||||||
|
1. Go to **File** > **Build Settings**.
|
||||||
|
2. In the **Target Platform** dropdown menu, select **Linux**.
|
||||||
|
3. Click **Build** or **Build and Run**.
|
||||||
|
|
||||||
|
## Technical Details
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
- Unity version 2019.4.1f1
|
||||||
|
- Linux Build Support (IL2CPP) module
|
|
@ -0,0 +1,66 @@
|
||||||
|
* [Unity Test Framework overview](./index.md)
|
||||||
|
* [Edit Mode vs. Play Mode tests](./edit-mode-vs-play-mode-tests.md)
|
||||||
|
* [Getting started with UTF](./getting-started.md)
|
||||||
|
* [How to create a new test assembly](./workflow-create-test-assembly.md)
|
||||||
|
* [How to create a test](./workflow-create-test.md)
|
||||||
|
* [How to run a test](./workflow-run-test.md)
|
||||||
|
* [How to create a Play Mode test](./workflow-create-playmode-test.md)
|
||||||
|
* [How to run a Play Mode test as standalone](./workflow-run-playmode-test-standalone.md)
|
||||||
|
* [Resources](./resources.md)
|
||||||
|
* [Extending UTF](./extending.md)
|
||||||
|
* [How to split the build and run process for standalone Play Mode tests](./reference-attribute-testplayerbuildmodifier.md#split-build-and-run-for-player-mode-tests)
|
||||||
|
* [How to run tests programmatically](./extension-run-tests.md)
|
||||||
|
* [How to get test results](./extension-get-test-results.md)
|
||||||
|
* [How to retrieve the list of tests](./extension-retrieve-test-list.md)
|
||||||
|
* [Reference](./manual.md#reference)
|
||||||
|
* [Running tests from the command-line](./reference-command-line.md)
|
||||||
|
* [UnityTest attribute](./reference-attribute-unitytest.md)
|
||||||
|
* [Setup and cleanup at build time](./reference-setup-and-cleanup.md)
|
||||||
|
* [IPrebuildSetup](./reference-setup-and-cleanup.md#iprebuildsetup)
|
||||||
|
* [IPostBuildCleanup](./reference-setup-and-cleanup.md#ipostbuildcleanup)
|
||||||
|
* [Actions outside of tests](./reference-actions-outside-tests.md)
|
||||||
|
* [Action execution order](./reference-actions-outside-tests.md#action-execution-order)
|
||||||
|
* [UnitySetUp and UnityTearDown](./reference-unitysetup-and-unityteardown.md)
|
||||||
|
* [OuterUnityTestAction](./reference-outerunitytestaction.md)
|
||||||
|
* [Domain Reloads](./reference-actions-outside-tests.md#domain-reloads)
|
||||||
|
* [Custom attributes](./reference-custom-attributes.md)
|
||||||
|
* [ConditionalIgnore attribute](./reference-attribute-conditionalignore.md)
|
||||||
|
* [PostBuildCleanup attribute](./reference-setup-and-cleanup.md#prebuildsetup-and-postbuildcleanup)
|
||||||
|
* [PrebuildSetup attribute](./reference-setup-and-cleanup.md#prebuildsetup-and-postbuildcleanup)
|
||||||
|
* [TestMustExpectAllLogs attribute](./reference-attribute-testmustexpectalllogs.md)
|
||||||
|
* [TestPlayerBuildModifier attribute](./reference-attribute-testplayerbuildmodifier.md)
|
||||||
|
* [TestRunCallback attribute](./reference-attribute-testruncallback.md)
|
||||||
|
* [UnityPlatform attribute](./reference-attribute-unityplatform.md)
|
||||||
|
* [UnitySetUp attribute](./reference-unitysetup-and-unityteardown.md)
|
||||||
|
* [UnityTearDown attribute](./reference-unitysetup-and-unityteardown.md)
|
||||||
|
* [UnityTest attribute](./reference-attribute-unitytest.md)
|
||||||
|
* [Custom equality comparers](./reference-custom-equality-comparers.md)
|
||||||
|
* [ColorEqualityComparer](./reference-comparer-color.md)
|
||||||
|
* [FloatEqualityComparer](./reference-comparer-float.md)
|
||||||
|
* [QuaternionEqualityComparer](./reference-comparer-quaternion.md)
|
||||||
|
* [Vector2EqualityComparer](./reference-comparer-vector2.md)
|
||||||
|
* [Vector3EqualityComparer](./reference-comparer-vector3.md)
|
||||||
|
* [Vector4EqualityComparer](./reference-comparer-vector4.md)
|
||||||
|
* [Custom equality comparers with equals operator](./reference-comparer-equals.md)
|
||||||
|
* [Test Utils](./reference-test-utils.md)
|
||||||
|
* [Custom yield instructions](./reference-custom-yield-instructions.md)
|
||||||
|
* [IEditModeTestYieldInstruction](./reference-custom-yield-instructions.md#IEditModeTestYieldInstruction)
|
||||||
|
* [EnterPlayMode](./reference-custom-yield-instructions.md#enterplaymode)
|
||||||
|
* [ExitPlayMode](./reference-custom-yield-instructions.md#exitplaymode)
|
||||||
|
* [RecompileScripts](./reference-recompile-scripts.md)
|
||||||
|
* [WaitForDomainReload](./reference-wait-for-domain-reload.md)
|
||||||
|
* [Custom assertion](./reference-custom-assertion.md)
|
||||||
|
* [LogAssert](./reference-custom-assertion.md#logassert)
|
||||||
|
* [Custom constraints](./reference-custom-constraints.md)
|
||||||
|
* [Is](./reference-custom-constraints.md#is)
|
||||||
|
* [Parameterized tests](./reference-tests-parameterized.md)
|
||||||
|
* [MonoBehaviour tests](./reference-tests-monobehaviour.md)
|
||||||
|
* [MonoBehaviourTest<T>](./reference-tests-monobehaviour.md#monobehaviourtestt)
|
||||||
|
* [IMonoBehaviourTest](./reference-tests-monobehaviour.md#imonobehaviourtest)
|
||||||
|
* [TestRunnerApi](./reference-test-runner-api.md)
|
||||||
|
* [ExecutionSettings](./reference-execution-settings.md)
|
||||||
|
* [Filter](./reference-filter.md)
|
||||||
|
* [ITestRunSettings](./reference-itest-run-settings.md)
|
||||||
|
* [ICallbacks](./reference-icallbacks.md)
|
||||||
|
* [IErrorCallbacks](./reference-ierror-callbacks.md)
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Edit Mode vs. Play Mode tests
|
||||||
|
|
||||||
|
Let’s clarify a bit what Play Mode and Edit Mode test means from the Unity Test Framework perspective:
|
||||||
|
|
||||||
|
## Edit Mode tests
|
||||||
|
|
||||||
|
**Edit Mode** tests (also known as Editor tests) are only run in the Unity Editor and have access to the Editor code in addition to the game code.
|
||||||
|
|
||||||
|
With Edit Mode tests it is possible to test any of your [Editor extensions](https://docs.unity3d.com/Manual/ExtendingTheEditor.html) using the [UnityTest](./reference-attribute-unitytest.md) attribute. For Edit Mode tests, your test code runs in the [EditorApplication.update](https://docs.unity3d.com/ScriptReference/EditorApplication-update.html) callback loop.
|
||||||
|
|
||||||
|
> **Note**: You can also control entering and exiting Play Mode from your Edit Mode test. This allow your test to make changes before entering Play Mode.
|
||||||
|
|
||||||
|
Edit Mode tests should meet one of the following conditions:
|
||||||
|
|
||||||
|
* They should have an [assembly definition](./workflow-create-test-assembly.md) with reference to *nunit.framework.dll* and has only the Editor as a target platform:
|
||||||
|
|
||||||
|
```assembly
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
* Legacy condition: put tests in the project’s [Editor](https://docs.unity3d.com/Manual/SpecialFolders.html) folder.
|
||||||
|
|
||||||
|
## Play Mode tests
|
||||||
|
|
||||||
|
You can run **Play Mode** tests as a [standalone in a Player](./workflow-run-playmode-test-standalone.md) or inside the Editor. Play Mode tests allow you to exercise your game code, as the tests run as [coroutines](https://docs.unity3d.com/ScriptReference/Coroutine.html) if marked with the `UnityTest` attribute.
|
||||||
|
|
||||||
|
Play Mode tests should correspond to the following conditions:
|
||||||
|
|
||||||
|
* Have an [assembly definition](./workflow-create-test-assembly.md) with reference to *nunit.framework.dll*.
|
||||||
|
* Have the test scripts located in a folder with the .asmdef file.
|
||||||
|
* The test assembly should reference an assembly within the code that you need to test.
|
||||||
|
|
||||||
|
```assembly
|
||||||
|
"references": [
|
||||||
|
"NewAssembly"
|
||||||
|
],
|
||||||
|
"optionalUnityReferences": [
|
||||||
|
"TestAssemblies"
|
||||||
|
],
|
||||||
|
"includePlatforms": [],
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recommendations
|
||||||
|
|
||||||
|
### Attributes
|
||||||
|
|
||||||
|
Use the [NUnit](http://www.nunit.org/) `Test` attribute instead of the `UnityTest` attribute, unless you need to [yield special instructions](./reference-custom-yield-instructions.md), in Edit Mode, or if you need to skip a frame or wait for a certain amount of time in Play Mode.
|
||||||
|
|
||||||
|
### References
|
||||||
|
|
||||||
|
It is possible for your Test Assemblies to reference the test tools in `UnityEngine.TestRunner` and `UnityEditor.TestRunner`. The latter is only available in Edit Mode. You can specify these references in the `Assembly Definition References` on the Assembly Definition.
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Extending Unity Test Framework
|
||||||
|
It is possible to extend the Unity Test Framework (UTF) in many ways, for custom workflows for your projects and for other packages to build on top of UTF.
|
||||||
|
|
||||||
|
These extensions are a supplement to the ones already offered by [NUnit](https://github.com/nunit/docs/wiki/Framework-Extensibility).
|
||||||
|
|
||||||
|
Some workflows for extending UTF include:
|
||||||
|
* [How to split the build and run process for standalone Play Mode tests](./reference-attribute-testplayerbuildmodifier.md#split-build-and-run-for-player-mode-tests)
|
||||||
|
* [How to run tests programmatically](./extension-run-tests.md)
|
||||||
|
* [How to get test results](./extension-get-test-results.md)
|
||||||
|
* [How to retrieve the list of tests](./extension-retrieve-test-list.md)
|
|
@ -0,0 +1,45 @@
|
||||||
|
# How to get test results
|
||||||
|
You can receive callbacks when the active test run, or individual tests, starts and finishes. You can register callbacks by invoking `RegisterCallbacks` on the [TestRunnerApi](./reference-test-runner-api.md) with an instance of a class that implements [ICallbacks](./reference-icallbacks.md). There are four `ICallbacks` methods for the start and finish of both the whole run and each level of the test tree.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
An example of how listeners can be set up:
|
||||||
|
|
||||||
|
> **Note**: Listeners receive callbacks from all test runs, regardless of the registered `TestRunnerApi` for that instance.
|
||||||
|
|
||||||
|
``` C#
|
||||||
|
public void SetupListeners()
|
||||||
|
{
|
||||||
|
var api = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||||
|
api.RegisterCallbacks(new MyCallbacks());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyCallbacks : ICallbacks
|
||||||
|
{
|
||||||
|
public void RunStarted(ITestAdaptor testsToRun)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunFinished(ITestResultAdaptor result)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TestStarted(ITestAdaptor test)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TestFinished(ITestResultAdaptor result)
|
||||||
|
{
|
||||||
|
if (!result.HasChildren && result.ResultState != "Passed")
|
||||||
|
{
|
||||||
|
Debug.Log(string.Format("Test {0} {1}", result.Test.Name, result.ResultState));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note**: The registered callbacks are not persisted on domain reloads. So it is necessary to re-register the callback after a domain reloads, usually with [InitializeOnLoad](https://docs.unity3d.com/Manual/RunningEditorCodeOnLaunch.html).
|
||||||
|
|
||||||
|
It is possible to provide a `priority` as an integer as the second argument when registering a callback. This influences the invocation order of different callbacks. The default value is zero. It is also possible to provide `RegisterCallbacks` with a class instance that implements [IErrorCallbacks](./reference-ierror-callbacks.md) that is an extended version of `ICallbacks`. `IErrorCallbacks` also has a callback method for `OnError` that invokes if the run fails to start, for example, due to compilation errors or if an [IPrebuildSetup](./reference-setup-and-cleanup.md) throws an exception.
|
|
@ -0,0 +1,13 @@
|
||||||
|
# How to retrieve the list of tests
|
||||||
|
It is possible to use the [TestRunnerApi](./reference-test-runner-api.md) to retrieve the test tree for a given test mode (**Edit Mode** or **Play Mode**). You can retrieve the test tree by invoking `RetrieveTestList` with the desired `TestMode` and a callback action, with an [ITestAdaptor](./reference-itest-adaptor.md) representing the test tree.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
The following example retrieves the test tree for Edit Mode tests and prints the number of total test cases:
|
||||||
|
``` C#
|
||||||
|
var api = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||||
|
api.RetrieveTestList(TestMode.EditMode, (testRoot) =>
|
||||||
|
{
|
||||||
|
Debug.Log(string.Format("Tree contains {0} tests.", testRoot.TestCaseCount));
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
# How to run tests programmatically
|
||||||
|
## Filters
|
||||||
|
|
||||||
|
Run tests by calling `Execute` on the [TestRunnerApi](./reference-test-runner-api.md), and provide some execution settings that consists of a [Filter](./reference-filter.md). The `Filter` specifies what tests to run.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
The following is an example of how to run all **Play Mode** tests in a project:
|
||||||
|
|
||||||
|
``` C#
|
||||||
|
var testRunnerApi = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||||
|
var filter = new Filter()
|
||||||
|
{
|
||||||
|
testMode = TestMode.PlayMode
|
||||||
|
};
|
||||||
|
testRunnerApi.Execute(new ExecutionSettings(filter));
|
||||||
|
```
|
||||||
|
## Multiple filter values
|
||||||
|
|
||||||
|
It is possible to specify a more specific filter by filling out the fields on the `Filter` class in more detail.
|
||||||
|
|
||||||
|
Many of the fields allow for multiple values. The runner tries to match tests against at least one of the values provided and then runs any tests that match.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
In this example, the API runs tests with full names that fit either of the two names provided:
|
||||||
|
|
||||||
|
``` C#
|
||||||
|
var api = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||||
|
api.Execute(new ExecutionSettings(new Filter()
|
||||||
|
{
|
||||||
|
testNames = new[] {"MyTestClass.NameOfMyTest", "SpecificTestFixture.NameOfAnotherTest"}
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
## Multiple filter fields
|
||||||
|
|
||||||
|
If using multiple different fields on the filter, then it matches against tests that fulfill all the different fields.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
In this example, it runs any test that fits either of the two test names, and that also belongs to a test assembly that fits the given name.
|
||||||
|
|
||||||
|
``` C#
|
||||||
|
var api = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||||
|
api.Execute(new ExecutionSettings(new Filter()
|
||||||
|
{
|
||||||
|
assemblyNames = new [] {"MyTestAssembly"},
|
||||||
|
testNames = new [] {"MyTestClass.NameOfMyTest", "MyTestClass.AnotherNameOfATest"}
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
## Multiple constructor filters
|
||||||
|
|
||||||
|
The execution settings take one or more filters in its constructor. If there is no filter provided, then it runs all **Edit Mode** tests by default. If there are multiple filters provided, then a test runs if it matches any of the filters.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
In this example, it runs any tests that are either in the assembly named `MyTestAssembly` or if the full name of the test matches either of the two provided test names:
|
||||||
|
|
||||||
|
``` C#
|
||||||
|
var api = ScriptableObject.CreateInstance<TestRunnerApi>();
|
||||||
|
api.Execute(new ExecutionSettings(
|
||||||
|
new Filter()
|
||||||
|
{
|
||||||
|
assemblyNames = new[] {"MyTestAssembly"},
|
||||||
|
},
|
||||||
|
new Filter()
|
||||||
|
{
|
||||||
|
testNames = new[] {"MyTestClass.NameOfMyTest", "MyTestClass.AnotherNameOfATest"}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
```
|
||||||
|
> **Note**: Specifying different test modes or platforms in each `Filter` is not currently supported. The test mode and platform is from the first `Filter` only and defaults to Edit Mode, if not supplied.
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Getting started with Unity Test Framework
|
||||||
|
|
||||||
|
To access the Unity Test Framework (UTF) in the Unity Editor, open the **Test Runner** window; go to **Window** > **General** > **Test Runner**.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
To get started with UTF, follow the workflows below:
|
||||||
|
|
||||||
|
* [How to create a new test assembly](./workflow-create-test-assembly.md)
|
||||||
|
* [How to create a test](./workflow-create-test.md)
|
||||||
|
* [How to run a test](./workflow-run-test.md)
|
||||||
|
* [How to create a Play Mode test](./workflow-create-playmode-test.md)
|
||||||
|
* [How to run a Play Mode test as standalone](./workflow-run-playmode-test-standalone.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
For further information, see the [resources](./resources.md) and [reference](./manual.md#reference) sections.
|
||||||
|
|
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 402 KiB |