Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/DllManipulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ public class DllManipulatorOptions
public bool crashLogsStackTrace;
public bool mockAllNativeFunctions;
public bool onlyInEditor;
public bool enableInEditMode;
}

public enum DllLoadingMode
Expand Down
41 changes: 35 additions & 6 deletions scripts/DllManipulatorScript.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
using System;
using System;
using System.Reflection;
using System.Threading;
using System.Linq;
using UnityEngine;
using UnityEditor;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default scripts outside of Editor folder (like this one) don't have access to UnityEditor namespace, so you should move the implementation there (maybe sth like DllManipulatorEditor(Script)? actually DllManipulatorEditor seems very appropriate for it).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that you mean to merge the two files DllManipulatorScript and DllManipulatorEditor. Would it not make more sense to just move the DllManipulatorScript to the Editor folder and keep them separate?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really want to move the main executable script to Editor folder, because I want it to be able to run it outside editor. I know I said it isn't recommended to publish games with that way, but a quick Build and Run won't hurt.

What I'm thinking now is to move most of the code from DllManipulatorScript to DllManipulator (which should really be done anyway) and make separate, dedicated script in Editor folder (or maybe use existing DllManipulatorEditor?). Btw, does a script with [ExecuteInEditMode] have to be somehow instantiated in order to be run? I will look at this more tomorrow.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I'd personally keep the custom editor IMGUI code separate.

Yes there has to be an instance for [ExecuteInEditMode].

Makes all instances of a script execute in Edit Mode (Unity docs)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you maybe know if there is a way to bootstrap code in editor, without a script in the scene? Because now that would require instantiating two scripts, one 'normal' and one for editor, with [ExecuteInEditMode]. I remember searching for something like this some time ago, but I think I didn't find anything suitable. For instance, a constructor of a custom editor class get's called automatically, but only when you select the target script. And if there was a way to do that, I could potentially even cease requiring putting my script in the scene at all.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I know you always need an instance in the scene (for it to work without any additional scripting by the user). Theres only [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)] but that would only be useful when using this tool in play mode.

I don't see why you would need two separate scripts, you can use Application.isPlaying and/or #if UNITY_EDITOR in the same script.

I guess you can use RuntimeInitializeOnLoadMethod for the 'normal' script and add an instance to the scene when you want to use it in edit mode as well? However, why would you not always use the edit mode version (given all the editor parts are in #if UNITY_EDITOR so you can still use it in a build)?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because scripts inside Editor folder are compiled into Assembly-CSharp-Editor assembly and these outside of Editor folder are compiled into Assembly-CSharp and only the former references UnityEditor.dll assembly, so you can't access the UnityEditor namespace in the non-editor scripts, even when UNITY_EDITOR symbol is specified. You can have custom assembly definition files that alter this behavior, but I don't want to force users to use them.

So that's how I remember it working, but now that I check it again I see that Assembly-CSharp also references UnityEditor.dll. So unless I messed this up, this behavior has changed in some version of unity. And if that's the case, I want be stay compatible with previous versions and not rely on this change.

As to the [RuntimeInitializeOnLoadMethod], attribute:

Methods marked [RuntimeInitializeOnLoadMethod] are invoked after the game has been loaded. This is after the Awake method has been invoked.
Note: The execution order of methods marked [RuntimeInitializeOnLoadMethod] is not guaranteed.

Which means that I can't safety use it, because some user code that uses a DLL could be have been run earlier, which would cause the DLL to be loaded by Unity (mono to be specific), and disallow further unloading.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point, however, I understood it that the Editor folders are just to save you from putting #ifs and you can still freely access the UnityEditor namespace outside of such a folder. Files in an Editor folder are not included in a build. So I think it should be fine if we use #ifs and put the script outside the Editor folder. (citing docs and this from 2015)

Regarding the attribute, I think that's because the default load type is after the scene has been loaded. See decompiled ctor below.

public RuntimeInitializeOnLoadMethodAttribute()
{
  this.loadType = RuntimeInitializeLoadType.AfterSceneLoad;
}

So if you specify the BeforeSplashScreen or BeforeSceneLoad LoadType it might work as intended.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've checked the Unity 2018 and your're right, although not all UnityEditor assemblies are referenced, the core one is and can be accessed. So this may freely stay how you initially proposed, but with #if UNITY_EDITOR checks.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still hangs there, although it is being guarded below

using UnityNativeTool.Internal;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace UnityNativeTool
{
#if UNITY_EDITOR
[ExecuteInEditMode]
#endif
public class DllManipulatorScript : MonoBehaviour
{
private static DllManipulatorScript _singletonInstance = null;
Expand All @@ -30,23 +37,44 @@ public class DllManipulatorScript : MonoBehaviour
crashLogsStackTrace = false,
mockAllNativeFunctions = true,
onlyInEditor = true,
enableInEditMode = false
};

private void OnEnable()
{
#if !UNITY_EDITOR
if (Options.onlyInEditor)
#if UNITY_EDITOR
if (_singletonInstance != null)
{
if (EditorApplication.isPlaying)
Destroy(gameObject);
else
enabled = false; //Don't destroy as the user may be editing a Prefab
return;
#endif
}
_singletonInstance = this;

if(EditorApplication.isPlaying)
DontDestroyOnLoad(gameObject);

if(EditorApplication.isPlaying || Options.enableInEditMode)
Initialize();
#else
if (Options.onlyInEditor) return;
Comment thread
mcpiroman marked this conversation as resolved.
Outdated

if (_singletonInstance != null)
{
Destroy(gameObject);
return;
}
_singletonInstance = this;
DontDestroyOnLoad(gameObject);

DontDestroyOnLoad(gameObject);
Initialize();
#endif
}

private void Initialize()
{
var initTimer = System.Diagnostics.Stopwatch.StartNew();

DllManipulator.Options = Options;
Expand All @@ -66,7 +94,8 @@ private void OnDestroy()

DllManipulator.UnloadAll();
DllManipulator.ForgetAllDlls();
DllManipulator.ClearCrashLogs();
DllManipulator.ClearCrashLogs();
_singletonInstance = null;
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions scripts/Editor/DllManipulatorEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public class DllManipulatorEditor : Editor
"If true, native functions will be mocked only in assembly that contains DllManipulator (usually Assembly-CSharp)");
private static readonly GUIContent ONLY_IN_EDITOR = new GUIContent("Only in editor",
"Whether to run only inside editor (which is recommended).");
private static readonly GUIContent ENABLE_IN_EDIT_MODE = new GUIContent("Enable in Edit Mode",
"Should the DLLs also be mocked in edit mode. " +
Comment thread
rogerbarton marked this conversation as resolved.
Outdated
"Turning this off when not needed improves performance when entering edit mode. " +
"Changed are currently only visible on the next time edit mode is entered.");
Comment thread
mcpiroman marked this conversation as resolved.
Outdated
private static readonly GUIContent TARGET_ASSEMBLIES_GUI_CONTENT = new GUIContent("Target assemblies",
"Choose from which assemblies to mock native functions");
private static readonly GUIContent DLL_PATH_PATTERN_GUI_CONTENT = new GUIContent("DLL path pattern",
Expand Down Expand Up @@ -246,6 +250,8 @@ private void DrawOptions(DllManipulatorOptions options)
}

options.onlyInEditor = EditorGUILayout.Toggle(ONLY_IN_EDITOR, options.onlyInEditor);

options.enableInEditMode = EditorGUILayout.Toggle(ENABLE_IN_EDIT_MODE, options.enableInEditMode);

options.dllPathPattern = EditorGUILayout.TextField(DLL_PATH_PATTERN_GUI_CONTENT, options.dllPathPattern);

Expand Down