Initial Commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// Derive from this class, add [InitializeOnLoad], and then call Install
|
||||
// in a static constructor to add some editor time bindings
|
||||
// For example:
|
||||
//
|
||||
// [InitializeOnLoad]
|
||||
// public class FooInstaller : EditorStaticInstaller<FooInstaller>
|
||||
// {
|
||||
// static FooInstaller()
|
||||
// {
|
||||
// Install();
|
||||
// }
|
||||
//
|
||||
// public override void InstallBindings()
|
||||
// {
|
||||
// Container.BindInstance("hello world");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
public abstract class EditorStaticInstaller<T> : InstallerBase
|
||||
where T : EditorStaticInstaller<T>
|
||||
{
|
||||
public static void Install()
|
||||
{
|
||||
StaticContext.Container.Instantiate<T>().InstallBindings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcb2e11e0ed56de48b0ba9b5e3ae10c9
|
||||
timeCreated: 1486079412
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd8d602c69b71714babee52a2d454aed
|
||||
folderAsset: yes
|
||||
timeCreated: 1461708046
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public abstract class ZenjectEditorWindow : EditorWindow
|
||||
{
|
||||
[Inject]
|
||||
[NonSerialized]
|
||||
Kernel _kernel;
|
||||
|
||||
[Inject]
|
||||
[NonSerialized]
|
||||
GuiRenderableManager _guiRenderableManager;
|
||||
|
||||
[NonSerialized]
|
||||
DiContainer _container;
|
||||
|
||||
[NonSerialized]
|
||||
Exception _fatalError;
|
||||
|
||||
[NonSerialized]
|
||||
GUIStyle _errorTextStyle;
|
||||
|
||||
GUIStyle ErrorTextStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_errorTextStyle == null)
|
||||
{
|
||||
_errorTextStyle = new GUIStyle(GUI.skin.label);
|
||||
_errorTextStyle.fontSize = 18;
|
||||
_errorTextStyle.normal.textColor = Color.red;
|
||||
_errorTextStyle.wordWrap = true;
|
||||
_errorTextStyle.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
|
||||
return _errorTextStyle;
|
||||
}
|
||||
}
|
||||
|
||||
protected DiContainer Container
|
||||
{
|
||||
get { return _container; }
|
||||
}
|
||||
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
if (_fatalError != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
protected virtual void Initialize()
|
||||
{
|
||||
Assert.IsNull(_container);
|
||||
|
||||
_container = new DiContainer(new[] { StaticContext.Container });
|
||||
|
||||
// Make sure we don't create any game objects since editor windows don't have a scene
|
||||
_container.AssertOnNewGameObjects = true;
|
||||
|
||||
ZenjectManagersInstaller.Install(_container);
|
||||
|
||||
_container.Bind<Kernel>().AsSingle();
|
||||
_container.Bind<GuiRenderableManager>().AsSingle();
|
||||
_container.BindInstance(this);
|
||||
|
||||
InstallBindings();
|
||||
|
||||
_container.QueueForInject(this);
|
||||
_container.ResolveRoots();
|
||||
|
||||
_kernel.Initialize();
|
||||
}
|
||||
|
||||
public virtual void OnDisable()
|
||||
{
|
||||
if (_fatalError != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_kernel.Dispose();
|
||||
}
|
||||
|
||||
public virtual void Update()
|
||||
{
|
||||
if (_fatalError != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_kernel.Tick();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.ErrorException(e);
|
||||
_fatalError = e;
|
||||
}
|
||||
|
||||
// We might also consider only calling Repaint when changes occur
|
||||
Repaint();
|
||||
}
|
||||
|
||||
public virtual void OnGUI()
|
||||
{
|
||||
if (_fatalError != null)
|
||||
{
|
||||
var labelWidth = 600;
|
||||
var labelHeight = 200;
|
||||
|
||||
GUI.Label(new Rect(Screen.width / 2 - labelWidth / 2, Screen.height / 3 - labelHeight / 2, labelWidth, labelHeight), "Unrecoverable error occurred! \nSee log for details.", ErrorTextStyle);
|
||||
|
||||
var buttonWidth = 100;
|
||||
var buttonHeight = 50;
|
||||
var offset = new Vector2(0, 100);
|
||||
|
||||
if (GUI.Button(new Rect(Screen.width / 2 - buttonWidth / 2 + offset.x, Screen.height / 3 - buttonHeight / 2 + offset.y, buttonWidth, buttonHeight), "Reload"))
|
||||
{
|
||||
ExecuteFullReload();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_guiRenderableManager != null)
|
||||
{
|
||||
_guiRenderableManager.OnGui();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.ErrorException(e);
|
||||
_fatalError = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ExecuteFullReload()
|
||||
{
|
||||
_kernel = null;
|
||||
_guiRenderableManager = null;
|
||||
_container = null;
|
||||
_fatalError = null;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public abstract void InstallBindings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc25e694ccedbed4893d980ee61d1c8f
|
||||
timeCreated: 1527961729
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fbb1477b2e261944dad77cce5626aab0
|
||||
folderAsset: yes
|
||||
timeCreated: 1461708046
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
#if !ODIN_INSPECTOR
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class ContextEditor : UnityInspectorListEditor
|
||||
{
|
||||
protected override string[] PropertyNames
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
"_scriptableObjectInstallers",
|
||||
"_monoInstallers",
|
||||
"_installerPrefabs",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override string[] PropertyDisplayNames
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
"Scriptable Object Installers",
|
||||
"Mono Installers",
|
||||
"Prefab Installers",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override string[] PropertyDescriptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[]
|
||||
{
|
||||
"Drag any assets in your Project that implement ScriptableObjectInstaller here",
|
||||
"Drag any MonoInstallers that you have added to your Scene Hierarchy here.",
|
||||
"Drag any prefabs that contain a MonoInstaller on them here",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23155ecdf203bf24480fd49763b73677
|
||||
timeCreated: 1461708049
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
#if !ODIN_INSPECTOR
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[CustomEditor(typeof(GameObjectContext))]
|
||||
[NoReflectionBaking]
|
||||
public class GameObjectContextEditor : RunnableContextEditor
|
||||
{
|
||||
SerializedProperty _kernel;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_kernel = serializedObject.FindProperty("_kernel");
|
||||
}
|
||||
|
||||
protected override void OnGui()
|
||||
{
|
||||
base.OnGui();
|
||||
|
||||
EditorGUILayout.PropertyField(_kernel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0873c763efd1e94fb3a56ff80843cf1
|
||||
timeCreated: 1461708052
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
#if !ODIN_INSPECTOR
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[CustomEditor(typeof(ProjectContext))]
|
||||
[NoReflectionBaking]
|
||||
public class ProjectContextEditor : ContextEditor
|
||||
{
|
||||
SerializedProperty _settingsProperty;
|
||||
SerializedProperty _editorReflectionBakingCoverageModeProperty;
|
||||
SerializedProperty _buildsReflectionBakingCoverageModeProperty;
|
||||
SerializedProperty _parentNewObjectsUnderContextProperty;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_settingsProperty = serializedObject.FindProperty("_settings");
|
||||
_editorReflectionBakingCoverageModeProperty = serializedObject.FindProperty("_editorReflectionBakingCoverageMode");
|
||||
_buildsReflectionBakingCoverageModeProperty = serializedObject.FindProperty("_buildsReflectionBakingCoverageMode");
|
||||
_parentNewObjectsUnderContextProperty = serializedObject.FindProperty("_parentNewObjectsUnderContext");
|
||||
}
|
||||
|
||||
protected override void OnGui()
|
||||
{
|
||||
base.OnGui();
|
||||
|
||||
EditorGUILayout.PropertyField(_settingsProperty, true);
|
||||
EditorGUILayout.PropertyField(_editorReflectionBakingCoverageModeProperty, true);
|
||||
EditorGUILayout.PropertyField(_buildsReflectionBakingCoverageModeProperty, true);
|
||||
EditorGUILayout.PropertyField(_parentNewObjectsUnderContextProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5ad40b612e67574aad508d053e6965b
|
||||
timeCreated: 1461708053
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
#if !ODIN_INSPECTOR
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class RunnableContextEditor : ContextEditor
|
||||
{
|
||||
SerializedProperty _autoRun;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_autoRun = serializedObject.FindProperty("_autoRun");
|
||||
}
|
||||
|
||||
protected override void OnGui()
|
||||
{
|
||||
base.OnGui();
|
||||
|
||||
EditorGUILayout.PropertyField(_autoRun);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02bed9738f9c4323ac05524465473dee
|
||||
timeCreated: 1494728675
|
||||
@@ -0,0 +1,37 @@
|
||||
#if !ODIN_INSPECTOR
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(SceneContext))]
|
||||
[NoReflectionBaking]
|
||||
public class SceneContextEditor : RunnableContextEditor
|
||||
{
|
||||
SerializedProperty _contractNameProperty;
|
||||
SerializedProperty _parentNamesProperty;
|
||||
SerializedProperty _parentNewObjectsUnderSceneContextProperty;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_contractNameProperty = serializedObject.FindProperty("_contractNames");
|
||||
_parentNamesProperty = serializedObject.FindProperty("_parentContractNames");
|
||||
_parentNewObjectsUnderSceneContextProperty = serializedObject.FindProperty("_parentNewObjectsUnderSceneContext");
|
||||
}
|
||||
|
||||
protected override void OnGui()
|
||||
{
|
||||
base.OnGui();
|
||||
|
||||
EditorGUILayout.PropertyField(_contractNameProperty, true);
|
||||
EditorGUILayout.PropertyField(_parentNamesProperty, true);
|
||||
EditorGUILayout.PropertyField(_parentNewObjectsUnderSceneContextProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c04ae1d59f53f514f96e284ba43122f7
|
||||
timeCreated: 1461708053
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
#if !ODIN_INSPECTOR
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[CustomEditor(typeof(SceneDecoratorContext))]
|
||||
[NoReflectionBaking]
|
||||
public class SceneDecoratorContextEditor : ContextEditor
|
||||
{
|
||||
SerializedProperty _decoratedContractNameProperty;
|
||||
|
||||
protected override string[] PropertyNames
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.PropertyNames.Concat(new string[]
|
||||
{
|
||||
"_lateInstallers",
|
||||
"_lateInstallerPrefabs",
|
||||
"_lateScriptableObjectInstallers"
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
protected override string[] PropertyDisplayNames
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.PropertyDisplayNames.Concat(new string[]
|
||||
{
|
||||
"Late Installers",
|
||||
"Late Prefab Installers",
|
||||
"Late Scriptable Object Installers"
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
protected override string[] PropertyDescriptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.PropertyDescriptions.Concat(new string[]
|
||||
{
|
||||
"Drag any MonoInstallers that you have added to your Scene Hierarchy here. They'll be installed after the target installs its bindings",
|
||||
"Drag any prefabs that contain a MonoInstaller on them here. They'll be installed after the target installs its bindings",
|
||||
"Drag any assets in your Project that implement ScriptableObjectInstaller here. They'll be installed after the target installs its bindings"
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
_decoratedContractNameProperty = serializedObject.FindProperty("_decoratedContractName");
|
||||
}
|
||||
|
||||
protected override void OnGui()
|
||||
{
|
||||
base.OnGui();
|
||||
|
||||
EditorGUILayout.PropertyField(_decoratedContractNameProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2b9289e80031104295e10acf518d75a
|
||||
timeCreated: 1461708053
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// Responsibilities:
|
||||
// - Output a file specifying the full object graph for a given root dependency
|
||||
// - This file uses the DOT language with can be fed into GraphViz to generate an image
|
||||
// - http://www.graphviz.org/
|
||||
public static class ObjectGraphVisualizer
|
||||
{
|
||||
public static void OutputObjectGraphToFile(
|
||||
DiContainer container, string outputPath,
|
||||
IEnumerable<Type> externalIgnoreTypes, IEnumerable<Type> contractTypes)
|
||||
{
|
||||
// Output the entire object graph to file
|
||||
var graph = CalculateObjectGraph(container, contractTypes);
|
||||
|
||||
var ignoreTypes = new List<Type>
|
||||
{
|
||||
typeof(DiContainer),
|
||||
typeof(InitializableManager)
|
||||
};
|
||||
|
||||
ignoreTypes.AddRange(externalIgnoreTypes);
|
||||
|
||||
var resultStr = "digraph { \n";
|
||||
|
||||
resultStr += "rankdir=LR;\n";
|
||||
|
||||
foreach (var entry in graph)
|
||||
{
|
||||
if (ShouldIgnoreType(entry.Key, ignoreTypes))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var dependencyType in entry.Value)
|
||||
{
|
||||
if (ShouldIgnoreType(dependencyType, ignoreTypes))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
resultStr += GetFormattedTypeName(entry.Key) + " -> " + GetFormattedTypeName(dependencyType) + "; \n";
|
||||
}
|
||||
}
|
||||
|
||||
resultStr += " }";
|
||||
|
||||
File.WriteAllText(outputPath, resultStr);
|
||||
}
|
||||
|
||||
static bool ShouldIgnoreType(Type type, List<Type> ignoreTypes)
|
||||
{
|
||||
return ignoreTypes.Contains(type);
|
||||
}
|
||||
|
||||
static Dictionary<Type, List<Type>> CalculateObjectGraph(
|
||||
DiContainer container, IEnumerable<Type> contracts)
|
||||
{
|
||||
var map = new Dictionary<Type, List<Type>>();
|
||||
|
||||
foreach (var contractType in contracts)
|
||||
{
|
||||
var depends = GetDependencies(container, contractType);
|
||||
|
||||
if (depends.Any())
|
||||
{
|
||||
map.Add(contractType, depends);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static List<Type> GetDependencies(
|
||||
DiContainer container, Type type)
|
||||
{
|
||||
var dependencies = new List<Type>();
|
||||
|
||||
foreach (var contractType in container.GetDependencyContracts(type))
|
||||
{
|
||||
List<Type> dependTypes;
|
||||
|
||||
if (contractType.FullName.StartsWith("System.Collections.Generic.List"))
|
||||
{
|
||||
var subTypes = contractType.GenericArguments();
|
||||
Assert.IsEqual(subTypes.Length, 1);
|
||||
|
||||
var subType = subTypes[0];
|
||||
dependTypes = container.ResolveTypeAll(subType);
|
||||
}
|
||||
else
|
||||
{
|
||||
dependTypes = container.ResolveTypeAll(contractType);
|
||||
Assert.That(dependTypes.Count <= 1);
|
||||
}
|
||||
|
||||
foreach (var dependType in dependTypes)
|
||||
{
|
||||
dependencies.Add(dependType);
|
||||
}
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
static string GetFormattedTypeName(Type type)
|
||||
{
|
||||
var str = type.PrettyName();
|
||||
|
||||
// GraphViz does not read names with <, >, or . characters so replace them
|
||||
str = str.Replace(">", "_");
|
||||
str = str.Replace("<", "_");
|
||||
str = str.Replace(".", "_");
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29f47f2a06418244e8fcbe27db1a0eea
|
||||
timeCreated: 1461708049
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b93c2560e2014a4893f387eb7690dbd
|
||||
folderAsset: yes
|
||||
timeCreated: 1520777708
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Internal
|
||||
{
|
||||
public class DefaultSceneContractConfig : ScriptableObject
|
||||
{
|
||||
public const string ResourcePath = "ZenjectDefaultSceneContractConfig";
|
||||
|
||||
public List<ContractInfo> DefaultContracts;
|
||||
|
||||
[Serializable]
|
||||
public class ContractInfo
|
||||
{
|
||||
public string ContractName;
|
||||
public SceneAsset Scene;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8620c058a9173b84a97d72ed5e94dbd7
|
||||
timeCreated: 1520778887
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+326
@@ -0,0 +1,326 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModestTree;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Zenject.Internal
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class SceneParentAutomaticLoader
|
||||
{
|
||||
static SceneParentAutomaticLoader()
|
||||
{
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
}
|
||||
|
||||
static void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (state == PlayModeStateChange.ExitingEditMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
ValidateMultiSceneSetupAndLoadDefaultSceneParents();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
EditorApplication.isPlaying = false;
|
||||
throw new ZenjectException(
|
||||
"Failure occurred when attempting to load default scene parent contracts!", e);
|
||||
}
|
||||
}
|
||||
else if (state == PlayModeStateChange.EnteredEditMode)
|
||||
{
|
||||
// It would be cool to restore the initial scene set up here but in order to do this
|
||||
// we would have to make sure that the user saves the scene before running which
|
||||
// would be too annoying, so just leave any changes we've made alone
|
||||
}
|
||||
}
|
||||
|
||||
public static void ValidateMultiSceneSetupAndLoadDefaultSceneParents()
|
||||
{
|
||||
var defaultContractsMap = LoadDefaultContractsMap();
|
||||
|
||||
// NOTE: Even if configs is empty we still want to do the below logic to validate the
|
||||
// multi scene setup
|
||||
|
||||
var sceneInfos = GetLoadedZenjectSceneInfos();
|
||||
var contractMap = GetCurrentSceneContractsMap(sceneInfos);
|
||||
|
||||
foreach (var sceneInfo in sceneInfos)
|
||||
{
|
||||
ProcessScene(sceneInfo, contractMap, defaultContractsMap);
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<string, LoadedSceneInfo> GetCurrentSceneContractsMap(
|
||||
List<LoadedSceneInfo> sceneInfos)
|
||||
{
|
||||
var contractMap = new Dictionary<string, LoadedSceneInfo>();
|
||||
|
||||
foreach (var info in sceneInfos)
|
||||
{
|
||||
AddToContractMap(contractMap, info);
|
||||
}
|
||||
|
||||
return contractMap;
|
||||
}
|
||||
|
||||
static void ProcessScene(
|
||||
LoadedSceneInfo sceneInfo,
|
||||
Dictionary<string, LoadedSceneInfo> contractMap,
|
||||
Dictionary<string, string> defaultContractsMap)
|
||||
{
|
||||
if (sceneInfo.SceneContext != null)
|
||||
{
|
||||
Assert.IsNull(sceneInfo.DecoratorContext);
|
||||
ProcessSceneParents(sceneInfo, contractMap, defaultContractsMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNotNull(sceneInfo.DecoratorContext);
|
||||
ProcessSceneDecorators(sceneInfo, contractMap, defaultContractsMap);
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessSceneDecorators(
|
||||
LoadedSceneInfo sceneInfo,
|
||||
Dictionary<string, LoadedSceneInfo> contractMap,
|
||||
Dictionary<string, string> defaultContractsMap)
|
||||
{
|
||||
var decoratedContractName = sceneInfo.DecoratorContext.DecoratedContractName;
|
||||
|
||||
LoadedSceneInfo decoratedSceneInfo;
|
||||
|
||||
if (contractMap.TryGetValue(decoratedContractName, out decoratedSceneInfo))
|
||||
{
|
||||
ValidateDecoratedSceneMatch(sceneInfo, decoratedSceneInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
decoratedSceneInfo = LoadDefaultSceneForContract(
|
||||
sceneInfo, decoratedContractName, defaultContractsMap);
|
||||
|
||||
EditorSceneManager.MoveSceneAfter(decoratedSceneInfo.Scene, sceneInfo.Scene);
|
||||
|
||||
ValidateDecoratedSceneMatch(sceneInfo, decoratedSceneInfo);
|
||||
|
||||
ProcessScene(decoratedSceneInfo, contractMap, defaultContractsMap);
|
||||
}
|
||||
|
||||
static void ProcessSceneParents(
|
||||
LoadedSceneInfo sceneInfo,
|
||||
Dictionary<string, LoadedSceneInfo> contractMap,
|
||||
Dictionary<string, string> defaultContractsMap)
|
||||
{
|
||||
foreach (var parentContractName in sceneInfo.SceneContext.ParentContractNames)
|
||||
{
|
||||
LoadedSceneInfo parentInfo;
|
||||
|
||||
if (contractMap.TryGetValue(parentContractName, out parentInfo))
|
||||
{
|
||||
ValidateParentChildMatch(parentInfo, sceneInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
parentInfo = LoadDefaultSceneForContract(sceneInfo, parentContractName, defaultContractsMap);
|
||||
|
||||
AddToContractMap(contractMap, parentInfo);
|
||||
|
||||
EditorSceneManager.MoveSceneBefore(parentInfo.Scene, sceneInfo.Scene);
|
||||
|
||||
ValidateParentChildMatch(parentInfo, sceneInfo);
|
||||
|
||||
ProcessScene(parentInfo, contractMap, defaultContractsMap);
|
||||
}
|
||||
}
|
||||
|
||||
static LoadedSceneInfo LoadDefaultSceneForContract(
|
||||
LoadedSceneInfo sceneInfo, string contractName, Dictionary<string, string> defaultContractsMap)
|
||||
{
|
||||
string scenePath;
|
||||
|
||||
if (!defaultContractsMap.TryGetValue(contractName, out scenePath))
|
||||
{
|
||||
throw Assert.CreateException(
|
||||
"Could not fill contract '{0}' for scene '{1}'. No scenes with that contract name are loaded, and could not find a match in any default scene contract configs to auto load one either."
|
||||
.Fmt(contractName, sceneInfo.Scene.name));
|
||||
}
|
||||
|
||||
Scene scene;
|
||||
|
||||
try
|
||||
{
|
||||
scene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Additive);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ZenjectException(
|
||||
"Error while attempting to load contracts for scene '{0}'".Fmt(sceneInfo.Scene.name), e);
|
||||
}
|
||||
|
||||
return CreateLoadedSceneInfo(scene);
|
||||
}
|
||||
|
||||
static void ValidateDecoratedSceneMatch(
|
||||
LoadedSceneInfo decoratorInfo, LoadedSceneInfo decoratedInfo)
|
||||
{
|
||||
var decoratorIndex = GetSceneIndex(decoratorInfo.Scene);
|
||||
var decoratedIndex = GetSceneIndex(decoratedInfo.Scene);
|
||||
var activeIndex = GetSceneIndex(EditorSceneManager.GetActiveScene());
|
||||
|
||||
Assert.That(decoratorIndex < decoratedIndex,
|
||||
"Decorator scene '{0}' must be loaded before decorated scene '{1}'. Please drag the decorator scene to be placed above the other scene in the scene hierarchy.",
|
||||
decoratorInfo.Scene.name, decoratedInfo.Scene.name);
|
||||
|
||||
if (activeIndex > decoratorIndex)
|
||||
{
|
||||
EditorSceneManager.SetActiveScene(decoratorInfo.Scene);
|
||||
}
|
||||
}
|
||||
|
||||
static void ValidateParentChildMatch(
|
||||
LoadedSceneInfo parentSceneInfo, LoadedSceneInfo sceneInfo)
|
||||
{
|
||||
var parentIndex = GetSceneIndex(parentSceneInfo.Scene);
|
||||
var childIndex = GetSceneIndex(sceneInfo.Scene);
|
||||
var activeIndex = GetSceneIndex(EditorSceneManager.GetActiveScene());
|
||||
|
||||
Assert.That(parentIndex < childIndex,
|
||||
"Parent scene '{0}' must be loaded before child scene '{1}'. Please drag it to be placed above its child in the scene hierarchy.", parentSceneInfo.Scene.name, sceneInfo.Scene.name);
|
||||
|
||||
if (activeIndex > parentIndex)
|
||||
{
|
||||
EditorSceneManager.SetActiveScene(parentSceneInfo.Scene);
|
||||
}
|
||||
}
|
||||
|
||||
static int GetSceneIndex(Scene scene)
|
||||
{
|
||||
for (int i = 0; i < EditorSceneManager.sceneCount; i++)
|
||||
{
|
||||
if (EditorSceneManager.GetSceneAt(i) == scene)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw Assert.CreateException();
|
||||
}
|
||||
|
||||
static Dictionary<string, string> LoadDefaultContractsMap()
|
||||
{
|
||||
var configs = Resources.LoadAll<DefaultSceneContractConfig>(DefaultSceneContractConfig.ResourcePath);
|
||||
|
||||
var map = new Dictionary<string, string>();
|
||||
|
||||
foreach (var config in configs)
|
||||
{
|
||||
foreach (var info in config.DefaultContracts)
|
||||
{
|
||||
if (info.ContractName.Trim().IsEmpty())
|
||||
{
|
||||
Log.Warn("Found empty contract name in default scene contract config at path '{0}'", AssetDatabase.GetAssetPath(config));
|
||||
continue;
|
||||
}
|
||||
|
||||
Assert.That(!map.ContainsKey(info.ContractName),
|
||||
"Found duplicate contract '{0}' in default scene contract config at '{1}'! Default contract already specified", info.ContractName, AssetDatabase.GetAssetPath(config));
|
||||
|
||||
map.Add(info.ContractName, AssetDatabase.GetAssetPath(info.Scene));
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static LoadedSceneInfo CreateLoadedSceneInfo(Scene scene)
|
||||
{
|
||||
var info = TryCreateLoadedSceneInfo(scene);
|
||||
Assert.IsNotNull(info, "Expected scene '{0}' to be a zenject scene", scene.name);
|
||||
return info;
|
||||
}
|
||||
|
||||
static LoadedSceneInfo TryCreateLoadedSceneInfo(Scene scene)
|
||||
{
|
||||
var sceneContext = ZenUnityEditorUtil.TryGetSceneContextForScene(scene);
|
||||
var decoratorContext = ZenUnityEditorUtil.TryGetDecoratorContextForScene(scene);
|
||||
|
||||
if (sceneContext == null && decoratorContext == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var info = new LoadedSceneInfo
|
||||
{
|
||||
Scene = scene
|
||||
};
|
||||
|
||||
if (sceneContext != null)
|
||||
{
|
||||
Assert.IsNull(decoratorContext,
|
||||
"Found both SceneContext and SceneDecoratorContext in scene '{0}'", scene.name);
|
||||
|
||||
info.SceneContext = sceneContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNotNull(decoratorContext);
|
||||
|
||||
info.DecoratorContext = decoratorContext;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static List<LoadedSceneInfo> GetLoadedZenjectSceneInfos()
|
||||
{
|
||||
var result = new List<LoadedSceneInfo>();
|
||||
|
||||
for (int i = 0; i < EditorSceneManager.sceneCount; i++)
|
||||
{
|
||||
var scene = EditorSceneManager.GetSceneAt(i);
|
||||
var info = TryCreateLoadedSceneInfo(scene);
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
result.Add(info);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void AddToContractMap(
|
||||
Dictionary<string, LoadedSceneInfo> contractMap, LoadedSceneInfo info)
|
||||
{
|
||||
if (info.SceneContext == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var contractName in info.SceneContext.ContractNames)
|
||||
{
|
||||
LoadedSceneInfo currentInfo;
|
||||
|
||||
if (contractMap.TryGetValue(contractName, out currentInfo))
|
||||
{
|
||||
throw Assert.CreateException(
|
||||
"Found multiple scene contracts with name '{0}'. Scene '{1}' and scene '{2}'",
|
||||
contractName, currentInfo.Scene.name, info.Scene.name);
|
||||
}
|
||||
|
||||
contractMap.Add(contractName, info);
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadedSceneInfo
|
||||
{
|
||||
public SceneContext SceneContext;
|
||||
public SceneDecoratorContext DecoratorContext;
|
||||
public Scene Scene;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9f09e0752f64214ba3413d7fdc47736
|
||||
timeCreated: 1520771371
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,93 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public abstract class UnityInspectorListEditor : Editor
|
||||
{
|
||||
List<ReorderableList> _installersLists;
|
||||
List<SerializedProperty> _installersProperties;
|
||||
|
||||
protected abstract string[] PropertyDisplayNames
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
protected abstract string[] PropertyNames
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
protected abstract string[] PropertyDescriptions
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
_installersProperties = new List<SerializedProperty>();
|
||||
_installersLists = new List<ReorderableList>();
|
||||
|
||||
var descriptions = PropertyDescriptions;
|
||||
var names = PropertyNames;
|
||||
var displayNames = PropertyDisplayNames;
|
||||
|
||||
Assert.IsEqual(descriptions.Length, names.Length);
|
||||
|
||||
var infos = Enumerable.Range(0, names.Length).Select(i => new { Name = names[i], DisplayName = displayNames[i], Description = descriptions[i] }).ToList();
|
||||
|
||||
foreach (var info in infos)
|
||||
{
|
||||
var installersProperty = serializedObject.FindProperty(info.Name);
|
||||
_installersProperties.Add(installersProperty);
|
||||
|
||||
ReorderableList installersList = new ReorderableList(serializedObject, installersProperty, true, true, true, true);
|
||||
_installersLists.Add(installersList);
|
||||
|
||||
var closedName = info.DisplayName;
|
||||
var closedDesc = info.Description;
|
||||
|
||||
installersList.drawHeaderCallback += rect =>
|
||||
{
|
||||
GUI.Label(rect,
|
||||
new GUIContent(closedName, closedDesc));
|
||||
};
|
||||
installersList.drawElementCallback += (rect, index, active, focused) =>
|
||||
{
|
||||
rect.width -= 40;
|
||||
rect.x += 20;
|
||||
EditorGUI.PropertyField(rect, installersProperty.GetArrayElementAtIndex(index), GUIContent.none, true);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public sealed override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
OnGui();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
protected virtual void OnGui()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
GUI.enabled = false;
|
||||
}
|
||||
|
||||
foreach (var list in _installersLists)
|
||||
{
|
||||
list.DoLayoutList();
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06d16f2f9107265428d41710db4cbb14
|
||||
timeCreated: 1461708048
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,349 @@
|
||||
#if !NOT_UNITY3D
|
||||
|
||||
using System.IO;
|
||||
using ModestTree;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Zenject.Internal
|
||||
{
|
||||
public static class ZenMenuItems
|
||||
{
|
||||
[MenuItem("Edit/Zenject/Validate Current Scenes #&v")]
|
||||
public static void ValidateCurrentScene()
|
||||
{
|
||||
ValidateCurrentSceneInternal();
|
||||
}
|
||||
|
||||
[MenuItem("Edit/Zenject/Validate Then Run #&r")]
|
||||
public static void ValidateCurrentSceneThenRun()
|
||||
{
|
||||
if (ValidateCurrentSceneInternal())
|
||||
{
|
||||
EditorApplication.isPlaying = true;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Edit/Zenject/Help...")]
|
||||
public static void OpenDocumentation()
|
||||
{
|
||||
Application.OpenURL("https://github.com/svermeulen/zenject");
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/Zenject/Scene Context", false, 9)]
|
||||
public static void CreateSceneContext(MenuCommand menuCommand)
|
||||
{
|
||||
var root = new GameObject("SceneContext").AddComponent<SceneContext>();
|
||||
Selection.activeGameObject = root.gameObject;
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/Zenject/Decorator Context", false, 9)]
|
||||
public static void CreateDecoratorContext(MenuCommand menuCommand)
|
||||
{
|
||||
var root = new GameObject("DecoratorContext").AddComponent<SceneDecoratorContext>();
|
||||
Selection.activeGameObject = root.gameObject;
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/Zenject/Game Object Context", false, 9)]
|
||||
public static void CreateGameObjectContext(MenuCommand menuCommand)
|
||||
{
|
||||
var root = new GameObject("GameObjectContext").AddComponent<GameObjectContext>();
|
||||
Selection.activeGameObject = root.gameObject;
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
}
|
||||
|
||||
[MenuItem("Edit/Zenject/Create Project Context")]
|
||||
public static void CreateProjectContextInDefaultLocation()
|
||||
{
|
||||
var fullDirPath = Path.Combine(Application.dataPath, "Resources");
|
||||
|
||||
if (!Directory.Exists(fullDirPath))
|
||||
{
|
||||
Directory.CreateDirectory(fullDirPath);
|
||||
}
|
||||
|
||||
CreateProjectContextInternal("Assets/Resources");
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Default Scene Contract Config", false, 80)]
|
||||
public static void CreateDefaultSceneContractConfig()
|
||||
{
|
||||
var folderPath = ZenUnityEditorUtil.GetCurrentDirectoryAssetPathFromSelection();
|
||||
|
||||
if (!folderPath.EndsWith("/Resources"))
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error",
|
||||
"ZenjectDefaultSceneContractConfig objects must be placed directly underneath a folder named 'Resources'. Please try again.", "Ok");
|
||||
return;
|
||||
}
|
||||
|
||||
var config = ScriptableObject.CreateInstance<DefaultSceneContractConfig>();
|
||||
|
||||
ZenUnityEditorUtil.SaveScriptableObjectAsset(
|
||||
Path.Combine(folderPath, DefaultSceneContractConfig.ResourcePath + ".asset"), config);
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Scriptable Object Installer", false, 1)]
|
||||
public static void CreateScriptableObjectInstaller()
|
||||
{
|
||||
AddCSharpClassTemplate("Scriptable Object Installer", "UntitledInstaller",
|
||||
"using UnityEngine;"
|
||||
+ "\nusing Zenject;"
|
||||
+ "\n"
|
||||
+ "\n[CreateAssetMenu(fileName = \"CLASS_NAME\", menuName = \"Installers/CLASS_NAME\")]"
|
||||
+ "\npublic class CLASS_NAME : ScriptableObjectInstaller<CLASS_NAME>"
|
||||
+ "\n{"
|
||||
+ "\n public override void InstallBindings()"
|
||||
+ "\n {"
|
||||
+ "\n }"
|
||||
+ "\n}");
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Mono Installer", false, 1)]
|
||||
public static void CreateMonoInstaller()
|
||||
{
|
||||
AddCSharpClassTemplate("Mono Installer", "UntitledInstaller",
|
||||
"using UnityEngine;"
|
||||
+ "\nusing Zenject;"
|
||||
+ "\n"
|
||||
+ "\npublic class CLASS_NAME : MonoInstaller"
|
||||
+ "\n{"
|
||||
+ "\n public override void InstallBindings()"
|
||||
+ "\n {"
|
||||
+ "\n }"
|
||||
+ "\n}");
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Installer", false, 1)]
|
||||
public static void CreateInstaller()
|
||||
{
|
||||
AddCSharpClassTemplate("Installer", "UntitledInstaller",
|
||||
"using UnityEngine;"
|
||||
+ "\nusing Zenject;"
|
||||
+ "\n"
|
||||
+ "\npublic class CLASS_NAME : Installer<CLASS_NAME>"
|
||||
+ "\n{"
|
||||
+ "\n public override void InstallBindings()"
|
||||
+ "\n {"
|
||||
+ "\n }"
|
||||
+ "\n}");
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Editor Window", false, 20)]
|
||||
public static void CreateEditorWindow()
|
||||
{
|
||||
AddCSharpClassTemplate("Editor Window", "UntitledEditorWindow",
|
||||
"using UnityEngine;"
|
||||
+ "\nusing UnityEditor;"
|
||||
+ "\nusing Zenject;"
|
||||
+ "\n"
|
||||
+ "\npublic class CLASS_NAME : ZenjectEditorWindow"
|
||||
+ "\n{"
|
||||
+ "\n [MenuItem(\"Window/CLASS_NAME\")]"
|
||||
+ "\n public static CLASS_NAME GetOrCreateWindow()"
|
||||
+ "\n {"
|
||||
+ "\n var window = EditorWindow.GetWindow<CLASS_NAME>();"
|
||||
+ "\n window.titleContent = new GUIContent(\"CLASS_NAME\");"
|
||||
+ "\n return window;"
|
||||
+ "\n }"
|
||||
+ "\n"
|
||||
+ "\n public override void InstallBindings()"
|
||||
+ "\n {"
|
||||
+ "\n // TODO"
|
||||
+ "\n }"
|
||||
+ "\n}");
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Project Context", false, 40)]
|
||||
public static void CreateProjectContext()
|
||||
{
|
||||
var absoluteDir = ZenUnityEditorUtil.TryGetSelectedFolderPathInProjectsTab();
|
||||
|
||||
if (absoluteDir == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error",
|
||||
"Could not find directory to place the '{0}.prefab' asset. Please try again by right clicking in the desired folder within the projects pane."
|
||||
.Fmt(ProjectContext.ProjectContextResourcePath), "Ok");
|
||||
return;
|
||||
}
|
||||
|
||||
var parentFolderName = Path.GetFileName(absoluteDir);
|
||||
|
||||
if (parentFolderName != "Resources")
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error",
|
||||
"'{0}.prefab' must be placed inside a directory named 'Resources'. Please try again by right clicking within the Project pane in a valid Resources folder."
|
||||
.Fmt(ProjectContext.ProjectContextResourcePath), "Ok");
|
||||
return;
|
||||
}
|
||||
|
||||
CreateProjectContextInternal(absoluteDir);
|
||||
}
|
||||
|
||||
static void CreateProjectContextInternal(string absoluteDir)
|
||||
{
|
||||
var assetPath = ZenUnityEditorUtil.ConvertFullAbsolutePathToAssetPath(absoluteDir);
|
||||
var prefabPath = (Path.Combine(assetPath, ProjectContext.ProjectContextResourcePath) + ".prefab").Replace("\\", "/");
|
||||
|
||||
var gameObject = new GameObject();
|
||||
|
||||
try
|
||||
{
|
||||
gameObject.AddComponent<ProjectContext>();
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
var prefabObj = PrefabUtility.SaveAsPrefabAsset(gameObject, prefabPath);
|
||||
#else
|
||||
var prefabObj = PrefabUtility.ReplacePrefab(gameObject, PrefabUtility.CreateEmptyPrefab(prefabPath));
|
||||
#endif
|
||||
|
||||
Selection.activeObject = prefabObj;
|
||||
}
|
||||
finally
|
||||
{
|
||||
GameObject.DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
Debug.Log("Created new ProjectContext at '{0}'".Fmt(prefabPath));
|
||||
}
|
||||
|
||||
public static string AddCSharpClassTemplate(
|
||||
string friendlyName, string defaultFileName, string templateStr)
|
||||
{
|
||||
return AddCSharpClassTemplate(
|
||||
friendlyName, defaultFileName, templateStr, ZenUnityEditorUtil.GetCurrentDirectoryAssetPathFromSelection());
|
||||
}
|
||||
|
||||
public static string AddCSharpClassTemplate(
|
||||
string friendlyName, string defaultFileName,
|
||||
string templateStr, string folderPath)
|
||||
{
|
||||
var absolutePath = EditorUtility.SaveFilePanel(
|
||||
"Choose name for " + friendlyName,
|
||||
folderPath,
|
||||
defaultFileName + ".cs",
|
||||
"cs");
|
||||
|
||||
if (absolutePath == "")
|
||||
{
|
||||
// Dialog was cancelled
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!absolutePath.ToLower().EndsWith(".cs"))
|
||||
{
|
||||
absolutePath += ".cs";
|
||||
}
|
||||
|
||||
var className = Path.GetFileNameWithoutExtension(absolutePath);
|
||||
File.WriteAllText(absolutePath, templateStr.Replace("CLASS_NAME", className));
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
var assetPath = ZenUnityEditorUtil.ConvertFullAbsolutePathToAssetPath(absolutePath);
|
||||
|
||||
EditorUtility.FocusProjectWindow();
|
||||
Selection.activeObject = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
|
||||
|
||||
return assetPath;
|
||||
}
|
||||
|
||||
[MenuItem("Edit/Zenject/Validate All Active Scenes")]
|
||||
public static void ValidateAllActiveScenes()
|
||||
{
|
||||
ZenUnityEditorUtil.SaveThenRunPreserveSceneSetup(() =>
|
||||
{
|
||||
var numValidated = ZenUnityEditorUtil.ValidateAllActiveScenes();
|
||||
Log.Info("Validated all '{0}' active scenes successfully", numValidated);
|
||||
});
|
||||
}
|
||||
|
||||
static bool ValidateCurrentSceneInternal()
|
||||
{
|
||||
return ZenUnityEditorUtil.SaveThenRunPreserveSceneSetup(() =>
|
||||
{
|
||||
SceneParentAutomaticLoader.ValidateMultiSceneSetupAndLoadDefaultSceneParents();
|
||||
ZenUnityEditorUtil.ValidateCurrentSceneSetup();
|
||||
Log.Info("All scenes validated successfully");
|
||||
});
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Unit Test", false, 60)]
|
||||
public static void CreateUnitTest()
|
||||
{
|
||||
AddCSharpClassTemplate("Unit Test", "UntitledUnitTest",
|
||||
"using Zenject;"
|
||||
+ "\nusing NUnit.Framework;"
|
||||
+ "\n"
|
||||
+ "\n[TestFixture]"
|
||||
+ "\npublic class CLASS_NAME : ZenjectUnitTestFixture"
|
||||
+ "\n{"
|
||||
+ "\n [Test]"
|
||||
+ "\n public void RunTest1()"
|
||||
+ "\n {"
|
||||
+ "\n // TODO"
|
||||
+ "\n }"
|
||||
+ "\n}");
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Integration Test", false, 60)]
|
||||
public static void CreateIntegrationTest()
|
||||
{
|
||||
AddCSharpClassTemplate("Integration Test", "UntitledIntegrationTest",
|
||||
"using Zenject;"
|
||||
+ "\nusing System.Collections;"
|
||||
+ "\nusing UnityEngine.TestTools;"
|
||||
+ "\n"
|
||||
+ "\npublic class CLASS_NAME : ZenjectIntegrationTestFixture"
|
||||
+ "\n{"
|
||||
+ "\n [UnityTest]"
|
||||
+ "\n public IEnumerator RunTest1()"
|
||||
+ "\n {"
|
||||
+ "\n // Setup initial state by creating game objects from scratch, loading prefabs/scenes, etc"
|
||||
+ "\n"
|
||||
+ "\n PreInstall();"
|
||||
+ "\n"
|
||||
+ "\n // Call Container.Bind methods"
|
||||
+ "\n"
|
||||
+ "\n PostInstall();"
|
||||
+ "\n"
|
||||
+ "\n // Add test assertions for expected state"
|
||||
+ "\n // Using Container.Resolve or [Inject] fields"
|
||||
+ "\n yield break;"
|
||||
+ "\n }"
|
||||
+ "\n}");
|
||||
}
|
||||
|
||||
[MenuItem("Assets/Create/Zenject/Scene Test", false, 60)]
|
||||
public static void CreateSceneTest()
|
||||
{
|
||||
AddCSharpClassTemplate("Scene Test Fixture", "UntitledSceneTest",
|
||||
"using Zenject;"
|
||||
+ "\nusing System.Collections;"
|
||||
+ "\nusing UnityEngine;"
|
||||
+ "\nusing UnityEngine.TestTools;"
|
||||
+ "\n"
|
||||
+ "\npublic class CLASS_NAME : SceneTestFixture"
|
||||
+ "\n{"
|
||||
+ "\n [UnityTest]"
|
||||
+ "\n public IEnumerator TestScene()"
|
||||
+ "\n {"
|
||||
+ "\n yield return LoadScene(\"InsertSceneNameHere\");"
|
||||
+ "\n"
|
||||
+ "\n // TODO: Add assertions here now that the scene has started"
|
||||
+ "\n // Or you can just uncomment to simply wait some time to make sure the scene plays without errors"
|
||||
+ "\n //yield return new WaitForSeconds(1.0f);"
|
||||
+ "\n"
|
||||
+ "\n // Note that you can use SceneContainer.Resolve to look up objects that you need for assertions"
|
||||
+ "\n }"
|
||||
+ "\n}");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d45338750ad0b4f4b90ed09091927b46
|
||||
timeCreated: 1461708053
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,352 @@
|
||||
#if !NOT_UNITY3D
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Zenject.Internal
|
||||
{
|
||||
public static class ZenUnityEditorUtil
|
||||
{
|
||||
// Returns true if succeeds without errors
|
||||
public static bool SaveThenRunPreserveSceneSetup(Action action)
|
||||
{
|
||||
if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
{
|
||||
var originalSceneSetup = EditorSceneManager.GetSceneManagerSetup();
|
||||
|
||||
try
|
||||
{
|
||||
action();
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.ErrorException(e);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorSceneManager.RestoreSceneManagerSetup(originalSceneSetup);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Feel free to call this method from an editor script, or a unit test, etc.
|
||||
// An exception will be thrown if any validation errors are encountered
|
||||
public static void ValidateCurrentSceneSetup()
|
||||
{
|
||||
bool encounteredError = false;
|
||||
|
||||
Application.LogCallback logCallback = (condition, stackTrace, type) =>
|
||||
{
|
||||
if (type == LogType.Error || type == LogType.Assert
|
||||
|| type == LogType.Exception)
|
||||
{
|
||||
encounteredError = true;
|
||||
}
|
||||
};
|
||||
|
||||
Application.logMessageReceived += logCallback;
|
||||
|
||||
try
|
||||
{
|
||||
Assert.That(!ProjectContext.HasInstance);
|
||||
ProjectContext.ValidateOnNextRun = true;
|
||||
|
||||
foreach (var sceneContext in GetAllSceneContexts())
|
||||
{
|
||||
sceneContext.Validate();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.ErrorException(e);
|
||||
encounteredError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Application.logMessageReceived -= logCallback;
|
||||
}
|
||||
|
||||
if (encounteredError)
|
||||
{
|
||||
throw new ZenjectException("Zenject Validation Failed! See errors below for details.");
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: An exception will be thrown if any validation errors are encountered
|
||||
// Returns the number of scenes that successfully validated
|
||||
public static int ValidateAllActiveScenes()
|
||||
{
|
||||
var activeScenePaths = EditorBuildSettings.scenes.Where(x => x.enabled)
|
||||
.Select(x => x.path).ToList();
|
||||
|
||||
foreach (var scenePath in activeScenePaths)
|
||||
{
|
||||
EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
|
||||
ValidateCurrentSceneSetup();
|
||||
}
|
||||
|
||||
return activeScenePaths.Count;
|
||||
}
|
||||
|
||||
// Don't use this
|
||||
public static void RunCurrentSceneSetup()
|
||||
{
|
||||
Assert.That(!ProjectContext.HasInstance);
|
||||
|
||||
foreach (var sceneContext in GetAllSceneContexts())
|
||||
{
|
||||
try
|
||||
{
|
||||
sceneContext.Run();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Add a bit more context
|
||||
throw new ZenjectException(
|
||||
"Scene '{0}' Failed To Start!".Fmt(sceneContext.gameObject.scene.name), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SceneContext GetSceneContextForScene(Scene scene)
|
||||
{
|
||||
var sceneContext = TryGetSceneContextForScene(scene);
|
||||
|
||||
Assert.IsNotNull(sceneContext,
|
||||
"Could not find scene context for scene '{0}'", scene.name);
|
||||
|
||||
return sceneContext;
|
||||
}
|
||||
|
||||
public static SceneContext TryGetSceneContextForScene(Scene scene)
|
||||
{
|
||||
if (!scene.isLoaded)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var sceneContexts = scene.GetRootGameObjects()
|
||||
.SelectMany(x => x.GetComponentsInChildren<SceneContext>()).ToList();
|
||||
|
||||
if (sceneContexts.IsEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.That(sceneContexts.Count == 1,
|
||||
"Found multiple SceneContexts in scene '{0}'. Expected a maximum of one.", scene.name);
|
||||
|
||||
return sceneContexts[0];
|
||||
}
|
||||
|
||||
public static SceneDecoratorContext GetDecoratorContextForScene(Scene scene)
|
||||
{
|
||||
var decoratorContext = TryGetDecoratorContextForScene(scene);
|
||||
|
||||
Assert.IsNotNull(decoratorContext,
|
||||
"Could not find decorator context for scene '{0}'", scene.name);
|
||||
|
||||
return decoratorContext;
|
||||
}
|
||||
|
||||
public static SceneDecoratorContext TryGetDecoratorContextForScene(Scene scene)
|
||||
{
|
||||
if (!scene.isLoaded)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var decoratorContexts = scene.GetRootGameObjects()
|
||||
.SelectMany(x => x.GetComponentsInChildren<SceneDecoratorContext>()).ToList();
|
||||
|
||||
if (decoratorContexts.IsEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.That(decoratorContexts.Count == 1,
|
||||
"Found multiple DecoratorContexts in scene '{0}'. Expected a maximum of one.", scene.name);
|
||||
|
||||
return decoratorContexts[0];
|
||||
}
|
||||
|
||||
static IEnumerable<SceneContext> GetAllSceneContexts()
|
||||
{
|
||||
var decoratedSceneNames = new List<string>();
|
||||
|
||||
for (int i = 0; i < EditorSceneManager.sceneCount; i++)
|
||||
{
|
||||
var scene = EditorSceneManager.GetSceneAt(i);
|
||||
|
||||
var sceneContext = TryGetSceneContextForScene(scene);
|
||||
var decoratorContext = TryGetDecoratorContextForScene(scene);
|
||||
|
||||
if (sceneContext != null)
|
||||
{
|
||||
Assert.That(decoratorContext == null,
|
||||
"Found both SceneDecoratorContext and SceneContext in the same scene '{0}'. This is not allowed", scene.name);
|
||||
|
||||
decoratedSceneNames.RemoveAll(x => sceneContext.ContractNames.Contains(x));
|
||||
|
||||
yield return sceneContext;
|
||||
}
|
||||
else if (decoratorContext != null)
|
||||
{
|
||||
Assert.That(!string.IsNullOrEmpty(decoratorContext.DecoratedContractName),
|
||||
"Missing Decorated Contract Name on SceneDecoratorContext in scene '{0}'", scene.name);
|
||||
|
||||
decoratedSceneNames.Add(decoratorContext.DecoratedContractName);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.That(decoratedSceneNames.IsEmpty(),
|
||||
"Found decorator scenes without a corresponding scene to decorator. Missing scene contracts: {0}", decoratedSceneNames.Join(", "));
|
||||
}
|
||||
|
||||
public static string ConvertAssetPathToAbsolutePath(string assetPath)
|
||||
{
|
||||
return Path.Combine(
|
||||
Path.Combine(Path.GetFullPath(Application.dataPath), ".."), assetPath);
|
||||
}
|
||||
|
||||
public static string ConvertFullAbsolutePathToAssetPath(string fullPath)
|
||||
{
|
||||
fullPath = Path.GetFullPath(fullPath);
|
||||
|
||||
var assetFolderFullPath = Path.GetFullPath(Application.dataPath);
|
||||
|
||||
if (fullPath.Length == assetFolderFullPath.Length)
|
||||
{
|
||||
Assert.IsEqual(fullPath, assetFolderFullPath);
|
||||
return "Assets";
|
||||
}
|
||||
|
||||
var assetPath = fullPath.Remove(0, assetFolderFullPath.Length + 1).Replace("\\", "/");
|
||||
return "Assets/" + assetPath;
|
||||
}
|
||||
|
||||
public static string GetCurrentDirectoryAssetPathFromSelection()
|
||||
{
|
||||
return ConvertFullAbsolutePathToAssetPath(
|
||||
GetCurrentDirectoryAbsolutePathFromSelection());
|
||||
}
|
||||
|
||||
public static string GetCurrentDirectoryAbsolutePathFromSelection()
|
||||
{
|
||||
var folderPath = TryGetSelectedFolderPathInProjectsTab();
|
||||
|
||||
if (folderPath != null)
|
||||
{
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
var filePath = TryGetSelectedFilePathInProjectsTab();
|
||||
|
||||
if (filePath != null)
|
||||
{
|
||||
return Path.GetDirectoryName(filePath);
|
||||
}
|
||||
|
||||
return Application.dataPath;
|
||||
}
|
||||
|
||||
public static string TryGetSelectedFilePathInProjectsTab()
|
||||
{
|
||||
return GetSelectedFilePathsInProjectsTab().OnlyOrDefault();
|
||||
}
|
||||
|
||||
public static List<string> GetSelectedFilePathsInProjectsTab()
|
||||
{
|
||||
return GetSelectedPathsInProjectsTab()
|
||||
.Where(x => File.Exists(x)).ToList();
|
||||
}
|
||||
|
||||
public static List<string> GetSelectedAssetPathsInProjectsTab()
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
UnityEngine.Object[] selectedAssets = Selection.GetFiltered(
|
||||
typeof(UnityEngine.Object), SelectionMode.Assets);
|
||||
|
||||
foreach (var item in selectedAssets)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(item);
|
||||
|
||||
if (!string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
paths.Add(assetPath);
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
public static List<string> GetSelectedPathsInProjectsTab()
|
||||
{
|
||||
var paths = new List<string>();
|
||||
|
||||
UnityEngine.Object[] selectedAssets = Selection.GetFiltered(
|
||||
typeof(UnityEngine.Object), SelectionMode.Assets);
|
||||
|
||||
foreach (var item in selectedAssets)
|
||||
{
|
||||
var relativePath = AssetDatabase.GetAssetPath(item);
|
||||
|
||||
if (!string.IsNullOrEmpty(relativePath))
|
||||
{
|
||||
var fullPath = Path.GetFullPath(Path.Combine(
|
||||
Application.dataPath, Path.Combine("..", relativePath)));
|
||||
|
||||
paths.Add(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
// Taken from http://wiki.unity3d.com/index.php?title=CreateScriptableObjectAsset
|
||||
public static void SaveScriptableObjectAsset(
|
||||
string path, ScriptableObject asset)
|
||||
{
|
||||
Assert.That(path.EndsWith(".asset"));
|
||||
|
||||
string assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(path);
|
||||
|
||||
AssetDatabase.CreateAsset(asset, assetPathAndName);
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
EditorUtility.FocusProjectWindow();
|
||||
Selection.activeObject = asset;
|
||||
}
|
||||
|
||||
// Note that the path is relative to the Assets folder
|
||||
public static List<string> GetSelectedFolderPathsInProjectsTab()
|
||||
{
|
||||
return GetSelectedPathsInProjectsTab()
|
||||
.Where(x => Directory.Exists(x)).ToList();
|
||||
}
|
||||
|
||||
// Returns the best guess directory in projects pane
|
||||
// Useful when adding to Assets -> Create context menu
|
||||
// Returns null if it can't find one
|
||||
// Note that the path is relative to the Assets folder for use in AssetDatabase.GenerateUniqueAssetPath etc.
|
||||
public static string TryGetSelectedFolderPathInProjectsTab()
|
||||
{
|
||||
return GetSelectedFolderPathsInProjectsTab().OnlyOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f798e3a2f0079b840804c0516d265f03
|
||||
timeCreated: 1461710838
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Zenject-Editor",
|
||||
"references": [
|
||||
"Zenject"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": []
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0acddb179989574c8355991596bd3e6
|
||||
timeCreated: 1531030222
|
||||
licenseType: Free
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user