I haven't find so far any good and update script for manage the Microsoft Spatial Azure Anchors, could you please review this code and tell me more or less if i am in the right way or not ? Actually I am trying to minimize the code for having the pure functionality, but i am stack and i can't even find an understandable guideline
hope the code is readable and well documented.
thanks in advance.
Andrea
using Microsoft.Azure;
using Microsoft.Azure.SpatialAnchors;
using Microsoft.Azure.SpatialAnchors.Unity;
using Microsoft.MixedReality.OpenXR;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.XR.WSA;
using UnityEngine.XR.WSA.Input;
public class AnchorsManager : MonoBehaviour
{
/// <summary>
/// Input
/// </summary>
private GameObject localAnchor;
/// <summary>
/// AZURE settings AccountId
/// </summary>
private string AccountId = "00886172-b41a-....";
/// <summary>
/// AZURE settings AccountKey
/// </summary>
private string AccountKey = "09c3eddc-....";
/// <summary>
/// AZURE settings AccountDomain
/// </summary>
private string AccountDomain = "northeurope.mixedreality.azure.com";
/// <summary>
/// Azure session
/// </summary>
private CloudSpatialAnchorSession cloudSession;
/// <summary>
/// For Storing the object Ids
/// </summary>
private AnchorLocateCriteria criteria = new AnchorLocateCriteria();
protected List<string> anchorIdsToLocate = new List<string>();
void Start()
{
InitializeSession();
}
/// <summary>
/// Only when the user drag an object we can save the anchor with the latest position
/// </summary>
void onMouseObjectDown(GameObject prefab)
{
this.localAnchor = prefab;
this.cloudSession.Start();
}
/// <summary>
/// Inizialize the cloudSpatialAnchorSession.
/// </summary>
void InitializeSession()
{
try {
this.cloudSession = new CloudSpatialAnchorSession();
this.cloudSession.Configuration.AccountId = this.AccountId;
this.cloudSession.Configuration.AccountKey = this.AccountKey;
this.cloudSession.Configuration.AccountDomain = this.AccountDomain;
this.cloudSession.SessionUpdated += (sender, args) =>
{
if (args.Status.RecommendedForCreateProgress != 0)
{
this.CreateAnchor();
}
};
//WATCHERS
this.cloudSession.CreateWatcher(criteria);
this.cloudSession.AnchorLocated += (object sender, AnchorLocatedEventArgs args) =>
{
switch (args.Status)
{
case LocateAnchorStatus.Located:
CloudSpatialAnchor foundAnchor = args.Anchor;
Debug.Log("ASA Info: Anchor located! Identifier: " + args.Identifier);
break;
case LocateAnchorStatus.AlreadyTracked:
Debug.Log("This anchor has already been reported and is being tracked" + args.Identifier);
break;
case LocateAnchorStatus.NotLocated:
Debug.Log("ASA Info: Anchor not located. Identifier: " + args.Identifier);
break;
case LocateAnchorStatus.NotLocatedAnchorDoesNotExist:
Debug.LogError("ASA Error: Anchor not located does not exist. Identifier: " + args.Identifier);
break;
}
};
}
catch (Exception ex) {
Debug.LogError("Error on initialize the session: " + ex.Message);
}
}
/// <summary>
/// CreateAnchor
/// </summary>
async void CreateAnchor()
{
// Create Anchor in local;
localAnchor.AddComponent<CloudNativeAnchor>();
CloudNativeAnchor cloudNativeAnchor = localAnchor.GetComponent<CloudNativeAnchor>();
if (cloudNativeAnchor.CloudAnchor == null) { await cloudNativeAnchor.NativeToCloud(); }
// Add Anchor property;
CloudSpatialAnchor cloudAnchor = cloudNativeAnchor.CloudAnchor;
cloudAnchor.AppProperties[#"room"] = #"bagno";
cloudAnchor.AppProperties[#"product"] = #"saponetta";
cloudAnchor.Expiration = DateTimeOffset.Now.AddDays(7);
// Create Anchor
await cloudSession.CreateAnchorAsync(cloudAnchor);
Debug.Log("Cloud anchor created with ID = " + cloudAnchor.Identifier);
// Save Anchor ID
this.anchorIdsToLocate.Add(cloudAnchor.Identifier);
this.criteria.Identifiers = anchorIdsToLocate.ToArray();
Debug.Log("Anchor Id has been saved on the array");
}
}
Related
In unity I keep on getting this error that keeps on bugging me, I tried to remove packages to leave one of these errors and it kept on going on and on, i am developing a game right now using unity engine and the errors are a big pain for me, this is the code that someone asked for, i dont really have much else to write other than this, stackoverlow isnt letting me just post it because its too short
using System;
using System.IO;
using UnityEngine;
namespace UnityEditor.SettingsManagement
{
/// <inheritdoc />
/// <summary>
/// A settings repository that stores data local to a Unity project.
/// </summary>
[Serializable]
public sealed class PackageSettingsRepository : ISettingsRepository
{
const string k_PackageSettingsDirectory = "ProjectSettings/Packages";
const bool k_PrettyPrintJson = true;
bool m_Initialized;
[SerializeField]
string m_Name;
[SerializeField]
string m_Path;
[SerializeField]
SettingsDictionary m_Dictionary = new SettingsDictionary();
/// <summary>
/// Constructor sets the serialized data path.
/// </summary>
/// <param name="package">
/// The package name.
/// </param>
/// <param name="name">
/// A name for this settings file. Settings are saved in `ProjectSettings/Packages/{package}/{name}.json`.
/// </param>
public PackageSettingsRepository(string package, string name)
{
m_Name = name;
m_Path = GetSettingsPath(package, name);
m_Initialized = false;
AssemblyReloadEvents.beforeAssemblyReload += Save;
EditorApplication.quitting += Save;
}
void Init()
{
if (m_Initialized)
return;
m_Initialized = true;
if (File.Exists(path))
{
m_Dictionary = null;
var json = File.ReadAllText(path);
EditorJsonUtility.FromJsonOverwrite(json, this);
if(m_Dictionary == null)
m_Dictionary = new SettingsDictionary();
}
}
/// <value>
/// This repository implementation is relevant to the Project scope.
/// </value>
/// <inheritdoc cref="ISettingsRepository.scope"/>
public SettingsScope scope
{
get { return SettingsScope.Project; }
}
/// <value>
/// The full path to the settings file.
/// This corresponds to `Unity Project/Project Settings/Packages/com.unity.package/name`.
/// </value>
/// <inheritdoc cref="ISettingsRepository.path"/>
public string path
{
get { return m_Path; }
}
/// <summary>
/// The name of this settings file.
/// </summary>
public string name
{
get { return m_Name; }
}
// Cannot call FindFromAssembly from a constructor or field initializer
// static string CreateSettingsPath(Assembly assembly, string name)
// {
// var info = PackageManager.PackageInfo.FindForAssembly(assembly);
// return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, info.name, name);
// }
/// <summary>
/// Get a path for a settings file relative to the calling assembly package directory.
/// </summary>
/// <param name="packageName">The name of the package requesting this setting.</param>
/// <param name="name">An optional name for the settings file. Default is "Settings."</param>
/// <returns>A package-scoped path to the settings file within Project Settings.</returns>
public static string GetSettingsPath(string packageName, string name = "Settings")
{
return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, packageName, name);
}
/// <summary>
/// Save all settings to their serialized state.
/// </summary>
/// <inheritdoc cref="ISettingsRepository.Save"/>
public void Save()
{
Init();
if (!File.Exists(path))
{
var directory = Path.GetDirectoryName(path);
Directory.CreateDirectory(directory);
}
#if UNITY_2019_3_OR_NEWER
if (!AssetDatabase.IsOpenForEdit(path))
{
if (!AssetDatabase.MakeEditable(path))
{
Debug.LogWarning($"Could not save package settings to {path}");
return;
}
}
#endif
try
{
File.WriteAllText(path, EditorJsonUtility.ToJson(this, k_PrettyPrintJson));
}
catch (UnauthorizedAccessException)
{
Debug.LogWarning($"Could not save package settings to {path}");
}
}
/// <summary>
/// Set a value for key of type T.
/// </summary>
/// <param name="key">The settings key.</param>
/// <param name="value">The value to set. Must be serializable.</param>
/// <typeparam name="T">Type of value.</typeparam>
/// <inheritdoc cref="ISettingsRepository.Set{T}"/>
public void Set<T>(string key, T value)
{
Init();
m_Dictionary.Set<T>(key, value);
}
/// <summary>
/// Get a value with key of type T, or return the fallback value if no matching key is found.
/// </summary>
/// <param name="key">The settings key.</param>
/// <param name="fallback">If no key with a value of type T is found, this value is returned.</param>
/// <typeparam name="T">Type of value to search for.</typeparam>
/// <inheritdoc cref="ISettingsRepository.Get{T}"/>
public T Get<T>(string key, T fallback = default(T))
{
Init();
return m_Dictionary.Get<T>(key, fallback);
}
/// <summary>
/// Does the repository contain a setting with key and type.
/// </summary>
/// <param name="key">The settings key.</param>
/// <typeparam name="T">The type of value to search for.</typeparam>
/// <returns>True if a setting matching both key and type is found, false if no entry is found.</returns>
/// <inheritdoc cref="ISettingsRepository.ContainsKey{T}"/>
public bool ContainsKey<T>(string key)
{
Init();
return m_Dictionary.ContainsKey<T>(key);
}
/// <summary>
/// Remove a key value pair from the settings repository.
/// </summary>
/// <param name="key"></param>
/// <typeparam name="T"></typeparam>
/// <inheritdoc cref="ISettingsRepository.Remove{T}"/>
public void Remove<T>(string key)
{
Init();
m_Dictionary.Remove<T>(key);
By the definition of 'RequestScriptReload' :
"The Unity Editor reloads script assemblies asynchronously on the next frame. This resets the state of all the scripts, but Unity does not compile any code that has changed since the previous compilation."
That means that your problem is probably with something that you changed.
You can try:
Going back to the last time everything wored and go on from there.
Closing all of you unity and scripting applications and opening it again.
How should I create PropertyAttribute and PropertyDrawer to show ScriptableObjects in dropdown menu in Inspector for multi selecting ?
I've published a repository on Github which solve this problem. It is for multi selecting in dropdown menu in Inspector.
In Github links you have access to example folder and unitypackage in release page but if you don't want to go to the links or any problem happens to the links, you can follow this instruction:
ScriptableObjectMultiSelectDropdown:
ScriptableObjectMultiSelectDropdown is an attribute for the Unity Inspector.
It is used for showing ScriptableObjects which are created in your project, in dropdown menu and select multiple of them in Inspector.
Code:
ScriptableObjectReference.cs:
// Copyright (c) ATHellboy (Alireza Tarahomi) Limited. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root.
using System;
using UnityEngine;
namespace ScriptableObjectMultiSelectDropdown
{
/// <summary>
/// Because you can't make a PropertyDrawer for arrays or generic lists themselves,
/// I had to create parent class as an abstract layer.
/// </summary>
[Serializable]
public class ScriptableObjectReference
{
public ScriptableObject[] values;
}
}
ScriptableObjectMultiSelectDropdownAttribute.cs:
// Copyright (c) ATHellboy (Alireza Tarahomi) Limited. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root.
using System;
using UnityEngine;
namespace ScriptableObjectMultiSelectDropdown
{
/// <summary>
/// Indicates how selectable scriptableObjects should be collated in drop-down menu.
/// </summary>
public enum ScriptableObjectGrouping
{
/// <summary>
/// No grouping, just show type names in a list; for instance, "MainFolder > NestedFolder > SpecialScriptableObject".
/// </summary>
None,
/// <summary>
/// Group classes by namespace and show foldout menus for nested namespaces; for
/// instance, "MainFolder >> NestedFolder >> SpecialScriptableObject".
/// </summary>
ByFolder,
/// <summary>
/// Group scriptableObjects by folder; for instance, "MainFolder > NestedFolder >> SpecialScriptableObject".
/// </summary>
ByFolderFlat
}
/// <example>
/// <para>Usage Examples</para>
/// <code language="csharp"><![CDATA[
/// using UnityEngine;
/// using ScriptableObjectDropdown;
///
/// [CreateAssetMenu(menuName = "Create Block")]
/// public class Block : ScriptableObject
/// {
/// // Some fields
/// }
///
/// public class BlockManager : MonoBehaviour
/// {
/// [ScriptableObjectMultiSelectDropdown(typeof(Block))]
/// public ScriptableObjectReference firstTargetBlocks;
///
/// // or
///
/// [ScriptableObjectMultiSelectDropdown(typeof(Block), grouping = ScriptableObjectGrouping.ByFolder)]
/// public ScriptableObjectReference secondTargetBlocks;
/// }
///
/// // or
///
/// [CreateAssetMenu(menuName = "Create Block Manager Settings")]
/// public class BlockManagerSetting : ScriptableObject
/// {
/// [ScriptableObjectMultiSelectDropdown(typeof(Block))]
/// public ScriptableObjectReference firstTargetBlocks;
///
/// // or
///
/// [ScriptableObjectMultiSelectDropdown(typeof(Block), grouping = ScriptableObjectGrouping.ByFolderFlat)]
/// public ScriptableObjectReference secondTargetBlocks;
/// }
/// ]]></code>
/// </example>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class ScriptableObjectMultiSelectDropdownAttribute : PropertyAttribute
{
public ScriptableObjectGrouping grouping = ScriptableObjectGrouping.None;
private Type _baseType;
public Type BaseType
{
get { return _baseType; }
private set { _baseType = value; }
}
public ScriptableObjectMultiSelectDropdownAttribute(Type baseType)
{
_baseType = baseType;
}
}
}
Put this one in Editor folder:
ScriptableObjectMultiSelectionDropdownDrawer.cs:
// Copyright (c) ATHellboy (Alireza Tarahomi) Limited. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System.Linq;
namespace ScriptableObjectMultiSelectDropdown.Editor
{
// TODO: Mixed value (-) for selecting multi objects
[CustomPropertyDrawer(typeof(ScriptableObjectReference))]
[CustomPropertyDrawer(typeof(ScriptableObjectMultiSelectDropdownAttribute))]
public class ScriptableObjectMultiSelectionDropdownDrawer : PropertyDrawer
{
private static ScriptableObjectMultiSelectDropdownAttribute _attribute;
private static List<ScriptableObject> _scriptableObjects = new List<ScriptableObject>();
private static List<ScriptableObject> _selectedScriptableObjects = new List<ScriptableObject>();
private static readonly int _controlHint = typeof(ScriptableObjectMultiSelectDropdownAttribute).GetHashCode();
private static GUIContent _popupContent = new GUIContent();
private static int _selectionControlID;
private static readonly GenericMenu.MenuFunction2 _onSelectedScriptableObject = OnSelectedScriptableObject;
private static bool isChanged;
static ScriptableObjectMultiSelectionDropdownDrawer()
{
EditorApplication.projectChanged += ClearCache;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
ScriptableObjectMultiSelectDropdownAttribute castedAttribute = attribute as ScriptableObjectMultiSelectDropdownAttribute;
if (_scriptableObjects.Count == 0)
{
GetScriptableObjects(castedAttribute);
}
Draw(position, label, property, castedAttribute);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorStyles.popup.CalcHeight(GUIContent.none, 0);
}
/// <summary>
/// How you can get type of field which it uses PropertyAttribute
/// </summary>
private static Type GetPropertyType(SerializedProperty property)
{
Type parentType = property.serializedObject.targetObject.GetType();
FieldInfo fieldInfo = parentType.GetField(property.propertyPath);
if (fieldInfo != null)
{
return fieldInfo.FieldType;
}
return null;
}
private static bool ValidateProperty(SerializedProperty property)
{
Type propertyType = GetPropertyType(property);
if (propertyType == null)
{
return false;
}
if (propertyType != typeof(ScriptableObjectReference))
{
return false;
}
return true;
}
/// <summary>
/// When new ScriptableObject added to the project
/// </summary>
private static void ClearCache()
{
_scriptableObjects.Clear();
}
/// <summary>
/// Gets ScriptableObjects just when it is a first time or new ScriptableObject added to the project
/// </summary>
private static void GetScriptableObjects(ScriptableObjectMultiSelectDropdownAttribute attribute)
{
string[] guids = AssetDatabase.FindAssets(String.Format("t:{0}", attribute.BaseType));
for (int i = 0; i < guids.Length; i++)
{
_scriptableObjects.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[i]), attribute.BaseType) as ScriptableObject);
}
}
/// <summary>
/// Checks if the ScriptableObject is selected or not by checking if the list contains it.
/// </summary>
private static bool ResolveSelectedScriptableObject(ScriptableObject scriptableObject)
{
if (_selectedScriptableObjects == null)
{
return false;
}
return _selectedScriptableObjects.Contains(scriptableObject);
}
private static void Draw(Rect position, GUIContent label,
SerializedProperty property, ScriptableObjectMultiSelectDropdownAttribute attribute)
{
if (label != null && label != GUIContent.none)
position = EditorGUI.PrefixLabel(position, label);
if (ValidateProperty(property))
{
if (_scriptableObjects.Count != 0)
{
UpdateScriptableObjectSelectionControl(position, label, property.FindPropertyRelative("values"), attribute);
}
else
{
EditorGUI.LabelField(position, "There is no this type asset in the project");
}
}
else
{
EditorGUI.LabelField(position, "Use it with ScriptableObjectReference");
}
}
/// <summary>
/// Iterats through the property for finding selected ScriptableObjects
/// </summary>
private static ScriptableObject[] Read(SerializedProperty property)
{
List<ScriptableObject> selectedScriptableObjects = new List<ScriptableObject>();
SerializedProperty iterator = property.Copy();
SerializedProperty end = iterator.GetEndProperty();
while (!SerializedProperty.EqualContents(iterator, end) && iterator.Next(true))
{
if (iterator.propertyType == SerializedPropertyType.ObjectReference)
{
selectedScriptableObjects.Add(iterator.objectReferenceValue as ScriptableObject);
}
}
return selectedScriptableObjects.ToArray();
}
/// <summary>
/// Iterats through the property for storing selected ScriptableObjects
/// </summary>
private static void Write(SerializedProperty property, ScriptableObject[] scriptableObjects)
{
// Faster way
// var w = new System.Diagnostics.Stopwatch();
// w.Start();
int i = 0;
SerializedProperty iterator = property.Copy();
iterator.arraySize = scriptableObjects.Length;
SerializedProperty end = iterator.GetEndProperty();
while (!SerializedProperty.EqualContents(iterator, end) && iterator.Next(true))
{
if (iterator.propertyType == SerializedPropertyType.ObjectReference)
{
iterator.objectReferenceValue = scriptableObjects[i];
i++;
}
}
// w.Stop();
// long milliseconds = w.ElapsedMilliseconds;
// Debug.Log(w.Elapsed.TotalMilliseconds + " ms");
// Another way
// property.arraySize = scriptableObjects.Length;
// for (int i = 0; i < property.arraySize; i++)
// {
// property.GetArrayElementAtIndex(i).objectReferenceValue = scriptableObjects[i];
// }
}
private static void UpdateScriptableObjectSelectionControl(Rect position, GUIContent label,
SerializedProperty property, ScriptableObjectMultiSelectDropdownAttribute attribute)
{
ScriptableObject[] output = DrawScriptableObjectSelectionControl(position, label, Read(property), property, attribute);
if (isChanged)
{
isChanged = false;
Write(property, output);
}
}
private static ScriptableObject[] DrawScriptableObjectSelectionControl(Rect position, GUIContent label,
ScriptableObject[] scriptableObjects, SerializedProperty property, ScriptableObjectMultiSelectDropdownAttribute attribute)
{
bool triggerDropDown = false;
int controlID = GUIUtility.GetControlID(_controlHint, FocusType.Keyboard, position);
switch (Event.current.GetTypeForControl(controlID))
{
case EventType.ExecuteCommand:
if (Event.current.commandName == "ScriptableObjectReferenceUpdated")
{
if (_selectionControlID == controlID)
{
if (scriptableObjects != _selectedScriptableObjects.ToArray())
{
scriptableObjects = _selectedScriptableObjects.ToArray();
isChanged = true;
}
_selectionControlID = 0;
_selectedScriptableObjects = null;
}
}
break;
case EventType.MouseDown:
if (GUI.enabled && position.Contains(Event.current.mousePosition))
{
GUIUtility.keyboardControl = controlID;
triggerDropDown = true;
Event.current.Use();
}
break;
case EventType.KeyDown:
if (GUI.enabled && GUIUtility.keyboardControl == controlID)
{
if (Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.Space)
{
triggerDropDown = true;
Event.current.Use();
}
}
break;
case EventType.Repaint:
if (scriptableObjects.Length == 0)
{
_popupContent.text = "Nothing";
}
else if (scriptableObjects.Length == _scriptableObjects.Count)
{
_popupContent.text = "Everything";
}
else if (scriptableObjects.Length >= 2)
{
_popupContent.text = "Mixed ...";
}
else
{
_popupContent.text = scriptableObjects[0].name;
}
EditorStyles.popup.Draw(position, _popupContent, controlID);
break;
}
if (triggerDropDown)
{
_selectionControlID = controlID;
_selectedScriptableObjects = scriptableObjects.ToList();
DisplayDropDown(position, scriptableObjects, attribute.grouping);
}
return scriptableObjects;
}
private static void DisplayDropDown(Rect position, ScriptableObject[] selectedScriptableObject, ScriptableObjectGrouping grouping)
{
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Nothing"), selectedScriptableObject.Length == 0, _onSelectedScriptableObject, null);
menu.AddItem(new GUIContent("Everything"),
(_scriptableObjects.Count != 0 && selectedScriptableObject.Length == _scriptableObjects.Count),
_onSelectedScriptableObject, _scriptableObjects.ToArray());
for (int i = 0; i < _scriptableObjects.Count; ++i)
{
var scriptableObject = _scriptableObjects[i];
string menuLabel = MakeDropDownGroup(scriptableObject, grouping);
if (string.IsNullOrEmpty(menuLabel))
continue;
var content = new GUIContent(menuLabel);
menu.AddItem(content, ResolveSelectedScriptableObject(scriptableObject), _onSelectedScriptableObject, scriptableObject);
}
menu.DropDown(position);
}
private static void OnSelectedScriptableObject(object userData)
{
if (userData == null)
{
_selectedScriptableObjects.Clear();
}
else if (userData.GetType().IsArray)
{
_selectedScriptableObjects = (userData as ScriptableObject[]).ToList();
}
else
{
ScriptableObject scriptableObject = userData as ScriptableObject;
if (!ResolveSelectedScriptableObject(scriptableObject))
{
_selectedScriptableObjects.Add(scriptableObject);
}
else
{
_selectedScriptableObjects.Remove(scriptableObject);
}
}
var scriptableObjectReferenceUpdatedEvent = EditorGUIUtility.CommandEvent("ScriptableObjectReferenceUpdated");
EditorWindow.focusedWindow.SendEvent(scriptableObjectReferenceUpdatedEvent);
}
private static string FindScriptableObjectFolderPath(ScriptableObject scriptableObject)
{
string path = AssetDatabase.GetAssetPath(scriptableObject);
path = path.Replace("Assets/", "");
path = path.Replace(".asset", "");
return path;
}
private static string MakeDropDownGroup(ScriptableObject scriptableObject, ScriptableObjectGrouping grouping)
{
string path = FindScriptableObjectFolderPath(scriptableObject);
switch (grouping)
{
default:
case ScriptableObjectGrouping.None:
path = path.Replace("/", " > ");
return path;
case ScriptableObjectGrouping.ByFolder:
return path;
case ScriptableObjectGrouping.ByFolderFlat:
int last = path.LastIndexOf('/');
string part1 = path.Substring(0, last);
string part2 = path.Substring(last);
path = part1.Replace("/", " > ") + part2;
return path;
}
}
}
}
Usage Example:
Create ScriptableObject class which you want to create specified objects by that.
using UnityEngine;
[CreateAssetMenu(menuName = "Create Block")]
public class Block : ScriptableObject
{
// Some fields
}
Create ScriptableObjects in the project.
Use ScriptableObjectMultiSelectDropdown attribute by setting type of specified ScriptableObject derived class and optional grouping (Default grouping is None) like this in MonoBeahviour or ScriptableObject derived classes.
MonoBehavior:
using ScriptableObjectMultiSelectDropdown;
using UnityEngine;
public class BlockManager : MonoBehaviour
{
// Without grouping (default is None)
[ScriptableObjectMultiSelectDropdown(typeof(Block))]
public ScriptableObjectReference firstTargetBlocks;
// By grouping
[ScriptableObjectMultiSelectDropdown(typeof(Block), grouping = ScriptableObjectGrouping.ByFolder)]
public ScriptableObjectReference secondTargetBlocks;
}
ScriptableObject:
using UnityEngine;
using ScriptableObjectMultiSelectDropdown;
[CreateAssetMenu(menuName = "Create Block Manager Settings")]
public class BlockManagerSettings : ScriptableObject
{
// Without grouping (default is None)
[ScriptableObjectMultiSelectDropdown(typeof(Block))]
public ScriptableObjectReference firstTargetBlocks;
// By grouping
[ScriptableObjectMultiSelectDropdown(typeof(Block), grouping = ScriptableObjectGrouping.ByFolderFlat)]
public ScriptableObjectReference secondTargetBlocks;
}
thanks for taking a look at this. I'm new to Unity and struggling to understand how to fix this error.
Assets/Watson/Scripts/Logging/Logger.cs(115,53): error CS0311: The type IBM.Watson.DeveloperCloud.Logging.LogSystem' cannot be used as type parameter T in the generic type or method Singleton. There is no implicit reference conversion from IBM.Watson.DeveloperCloud.Logging.LogSystem' to `UnityEngine.MonoBehaviour
This is the line causing the error:
public static LogSystem Instance { get { return Singleton<LogSystem>.Instance; } }
And this is it in context:
/// <summary>
/// This singleton class maintains the of list of installed reactors and handles all LogRecord
/// objects. See the static class Log for functions the end user of this system should actually
/// be calling. This class is thread safe.
/// </summary>
public class LogSystem
{
#region Public Properties
/// <summary>
/// Returns the singleton instance of the Logger object.
/// </summary>
**public static LogSystem Instance { get { return Singleton<LogSystem>.Instance; } }**
#endregion
#region Private Data
private static bool sm_bInstalledDefaultReactors = false;
List<ILogReactor> m_Reactors = new List<ILogReactor>();
#endregion
#region Public Functions
public static List<ILogReactor> ReactorsInstalled
{
get
{
return LogSystem.Instance.m_Reactors;
}
}
/// <summary>
/// Install a default debug and file reactor.
/// </summary>
public static void InstallDefaultReactors(int logHistory = 2, LogLevel logLevelFileReactor = LogLevel.STATUS)
{
if (!sm_bInstalledDefaultReactors)
{
// install the default reactors...
sm_bInstalledDefaultReactors = true;
#if UNITY_EDITOR || UNITY_IOS || UNITY_ANDROID
LogSystem.Instance.InstallReactor(new DebugReactor());
#endif
if (!string.IsNullOrEmpty(Constants.Path.LOG_FOLDER) && !System.IO.Directory.Exists(Application.persistentDataPath + Constants.Path.LOG_FOLDER))
System.IO.Directory.CreateDirectory(Application.persistentDataPath + Constants.Path.LOG_FOLDER);
LogSystem.Instance.InstallReactor(new FileReactor(Application.persistentDataPath + Constants.Path.LOG_FOLDER + "/" + Application.productName + ".log", logLevelFileReactor, logHistory));
Application.logMessageReceived += UnityLogCallback;
}
}
static void UnityLogCallback(string condition, string stacktrace, LogType type)
{
if (type == LogType.Exception)
Log.Critical("Unity", "Unity Exception {0} : {1}", condition, stacktrace);
}
/// <summary>
/// Installs a reactor into this Logger.
/// </summary>
/// <param name="reactor">The reactor object.</param>
public void InstallReactor(ILogReactor reactor)
{
lock (m_Reactors)
{
m_Reactors.Add(reactor);
}
// set our default reactor flag to true if the user installs their own reactors.
sm_bInstalledDefaultReactors = true;
}
/// <summary>
/// Removes a reactor from this Logger.
/// </summary>
/// <param name="reactor">The reactor to remove.</param>
/// <returns>Returns true on success.</returns>
public bool RemoveReactor(ILogReactor reactor)
{
lock (m_Reactors)
{
return m_Reactors.Remove(reactor);
}
}
/// <summary>
/// Send the given LogRecord to all installed reactors.
/// </summary>
/// <param name="log">The LogRecord to pass to all reactors.</param>
public void ProcessLog(LogRecord log)
{
lock (m_Reactors)
{
foreach (var reactor in m_Reactors)
reactor.ProcessLog(log);
}
}
#endregion
}
public static LogSystem Instance
{
get
{
return instance;
}
}
private static LogSystem instance;
// Ctor of the class
public LogSystem()
{
if(instance == null) { instance = this;}
}
This is a very basic singleton pattern implementation. You can find more advanced ones online.
How can I be notified when ProgressBar's Value changes with .NET UIAutomation framework? I dont see such property in AutomationElement class.
I drew this sample directly from the MSDN documentation, changing only the property:
AutomationPropertyChangedEventHandler propChangeHandler;
/// <summary>
/// Adds a handler for property-changed event; in particular, a change in the value
/// </summary>
/// <param name="element">The UI Automation element whose state is being monitored.</param>
public void SubscribePropertyChange(AutomationElement element)
{
Automation.AddAutomationPropertyChangedEventHandler(element,
TreeScope.Element,
propChangeHandler = new AutomationPropertyChangedEventHandler(OnPropertyChange),
ValuePattern.ValueProperty);
}
/// <summary>
/// Handler for property changes.
/// </summary>
/// <param name="src">The source whose properties changed.</param>
/// <param name="e">Event arguments.</param>
private void OnPropertyChange(object src, AutomationPropertyChangedEventArgs e)
{
AutomationElement sourceElement = src as AutomationElement;
if (e.Property == ValuePattern.ValueProperty)
{
// TODO: Do something with the new value.
// The element that raised the event can be identified by its runtime ID property.
}
else
{
// TODO: Handle other property-changed events.
}
}
public void UnsubscribePropertyChange(AutomationElement element)
{
if (propChangeHandler != null)
{
Automation.RemoveAutomationPropertyChangedEventHandler(element, propChangeHandler);
}
}
I am trying to create a Prism (CAL) framework (this is my first forray into CAL) and am having difficulty devising a service for registering menu items for a region). Here is what I have come up with so far...
/// <summary>
/// Menu item service - allows any module to register menu items with any region
/// </summary>
public class MenuService : IMenuService
{
private IUnityContainer m_UnityContainer;
private IRegionManager m_RegionManager;
private Dictionary<string, IUnityContainer> m_MenuContainers = new Dictionary<string,IUnityContainer>();
/// <summary>
/// Injection ctor
/// </summary>
/// <param name="unityContainer"></param>
/// <param name="regionManager"></param>
public MenuService(IUnityContainer unityContainer, IRegionManager regionManager)
{
m_UnityContainer = unityContainer;
m_RegionManager = regionManager;
}
/// <summary>
/// Registers a menu item with the service
/// </summary>
/// <param name="topLevelName"></param>
/// <param name="regionIdentity"></param>
/// <param name="displayText"></param>
public void RegisterMenuItem(string topLevelName, string regionIdentity, string displayText)
{
IUnityContainer container = GetOrCreateUiIdentityContainer(regionIdentity);
if (string.IsNullOrEmpty(topLevelName))
container.RegisterInstance("MENUITEM" + displayText, new MenuItem { Header = displayText} );
else
{
MenuItem topLevel = container.Resolve<MenuItem>("MENUITEM" + topLevelName);
if (topLevel.Header == null)
{
topLevel = new MenuItem{ Header = topLevelName};
container.RegisterInstance<MenuItem>("MENUITEM" + topLevelName, topLevel);
}
MenuItem newItem = new MenuItem{Header = displayText};
topLevel.Items.Add(newItem);
container.RegisterInstance("MENUITEM" + topLevelName + "_" + displayText, newItem);
}
}
private IUnityContainer GetOrCreateUiIdentityContainer(string regionIdentity)
{
IUnityContainer container;
container = GetUnityContainer(regionIdentity);
if (container != null)
return container;
container = m_UnityContainer.CreateChildContainer();
m_MenuContainers.Add(regionIdentity, container);
return container;
}
private IUnityContainer GetUnityContainer(string regionIdentity)
{
IUnityContainer container;
m_MenuContainers.TryGetValue(regionIdentity, out container);
return container;
}
/// <summary>
/// Builds up the menu for a given region
/// </summary>
/// <param name="regionIdentity"></param>
public void BuildMenu(string regionIdentity)
{
IUnityContainer container;
container = GetUnityContainer(regionIdentity);
if (container == null)
return;
IRegion region = m_RegionManager.Regions[regionIdentity];
if (region == null)
return;
IEnumerable<MenuItem> menuItems = container.ResolveAll<MenuItem>();
foreach (MenuItem item in menuItems)
{
if (item.Role == MenuItemRole.SubmenuHeader )
region.Add(item);
}
}
}
Is there a better way to do what I am trying to do?
Cheers,
Jason
I've got a sample you can take a look at that does exactly this. Hopefully this will help you out a bit. If you have any specific questions after looking at it, let me know!
http://dl.getdropbox.com/u/376992/CAGMenus.zip
Hope this helps.