/// <summary> /// Loads the Resource from the specified <see cref="Stream"/>. You shouldn't need this method in almost all cases. /// Only use it when you know exactly what you're doing. Consider requesting the Resource from the <see cref="ContentProvider"/> instead. /// </summary> /// <typeparam name="T"> /// Desired Type of the returned reference. Does not affect the loaded Resource in any way - it is simply returned as T. /// Results in returning null if the loaded Resource's Type isn't assignable to T. /// </typeparam> /// <param name="formatter"></param> /// <param name="resPath">The path that is assumed as the loaded Resource's origin.</param> /// <param name="loadCallback">An optional callback that is invoked right after loading the Resource, but before initializing it.</param> /// <param name="initResource"> /// Specifies whether or not the Resource is initialized by calling <see cref="Resource.OnLoaded"/>. Never attempt to use /// uninitialized Resources or register them in the <see cref="ContentProvider"/>. /// </param> /// <returns>The Resource that has been loaded.</returns> public static T Load <T>(Serializer formatter, string resPath = null, Action <T> loadCallback = null, bool initResource = true) where T : Resource { T newContent = null; try { Resource res = formatter.ReadObject <Resource>(); if (res == null) { throw new Exception("Deserializing Resource failed."); } res.initState = InitState.Initializing; res.path = resPath; if (loadCallback != null) { loadCallback(res as T); // Callback before initializing. } if (initResource) { Init(res); } newContent = res as T; } catch (Exception e) { Logs.Core.WriteError("Can't load {0} from '{1}', because an error occurred: {3}{2}", LogFormat.Type(typeof(T)), resPath ?? formatter.ToString(), LogFormat.Exception(e), Environment.NewLine); } return(newContent); }
/// <summary> /// Returns a string that can be used for representing a <see cref="System.Reflection.TypeInfo"/> in log entries. /// </summary> /// <param name="type"></param> public static string Type(TypeInfo type) { if (type == null) { return("null"); } return(LogFormat.Type(type.AsType())); }
private static void CleanEventBindings(Assembly invalidAssembly) { // Note that this method is only a countermeasure against common mistakes. It doesn't guarantee // full error safety in all cases. Event bindings inbetween different plugins aren't checked, // for example. string warningText = string.Format( "Found leaked event bindings to invalid Assembly '{0}' from {1}. " + "This is a common problem when registering global events from within a CorePlugin " + "without properly unregistering them later. Please make sure that all events are " + "unregistered in CorePlugin::OnDisposePlugin().", invalidAssembly.GetShortAssemblyName(), "{0}"); if (ReflectionHelper.CleanEventBindings(typeof(DualityApp), invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(DualityApp))); } if (ReflectionHelper.CleanEventBindings(typeof(Scene), invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(Scene))); } if (ReflectionHelper.CleanEventBindings(typeof(Resource), invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(Resource))); } if (ReflectionHelper.CleanEventBindings(typeof(ContentProvider), invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(ContentProvider))); } if (ReflectionHelper.CleanEventBindings(DualityApp.Keyboard, invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(DualityApp)) + ".Keyboard"); } if (ReflectionHelper.CleanEventBindings(DualityApp.Mouse, invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(DualityApp)) + ".Mouse"); } foreach (JoystickInput joystick in DualityApp.Joysticks) { if (ReflectionHelper.CleanEventBindings(joystick, invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(DualityApp)) + ".Joysticks"); } } foreach (GamepadInput gamepad in DualityApp.Gamepads) { if (ReflectionHelper.CleanEventBindings(gamepad, invalidAssembly)) { Logs.Core.WriteWarning(warningText, LogFormat.Type(typeof(DualityApp)) + ".Gamepads"); } } }
private static FieldInfo GetField(Type type, string name) { FieldInfo result = type.GetRuntimeFields().FirstOrDefault(m => !m.IsStatic && m.Name == name); if (result == null) { Logs.Core.WriteError( "Unable to retrieve field '{0}' of type '{1}'.", name, LogFormat.Type(type)); } return(result); }
private static PropertyInfo GetProperty(Type type, string name) { PropertyInfo result = type.GetRuntimeProperties().FirstOrDefault(m => !m.IsStatic() && m.Name == name); if (result == null) { Logs.Core.WriteError( "Unable to retrieve property '{0}' of type '{1}'.", name, LogFormat.Type(type)); } return(result); }
public override string ToString() { if (this.SkipIfExists > 0) { return(string.Format("Skip {0} if {1} exists", this.SkipIfExists, LogFormat.Type(this.RequiredType))); } else { return(string.Format("Require {0} or create {1}", LogFormat.Type(this.RequiredType), LogFormat.Type(this.CreateType))); } }
/// <summary> /// Adds an already loaded plugin Assembly to the internal Duality T registry. /// You shouldn't need to call this method in general, since Duality manages its plugins /// automatically. /// </summary> /// <remarks> /// This method can be useful in certain cases when it is necessary to treat an Assembly as a /// Duality plugin, even though it isn't located in the Plugins folder, or is not available /// as a file at all. A typical case for this is Unit Testing where the testing Assembly may /// specify additional Duality types such as Components, Resources, etc. /// </remarks> /// <param name="pluginAssembly"></param> /// <param name="pluginFilePath"></param> /// <returns></returns> public T LoadPlugin(Assembly pluginAssembly, string pluginFilePath) { this.disposedPlugins.Remove(pluginAssembly); string asmName = pluginAssembly.GetShortAssemblyName(); T plugin = this.pluginRegistry.Values.FirstOrDefault(p => p.AssemblyName == asmName); if (plugin != null) { return(plugin); } try { TypeInfo pluginType = pluginAssembly.ExportedTypes .Select(t => t.GetTypeInfo()) .FirstOrDefault(t => typeof(T).GetTypeInfo().IsAssignableFrom(t)); if (pluginType == null) { throw new Exception(string.Format( "Plugin does not contain a public {0} class.", typeof(T).Name)); } plugin = (T)pluginType.CreateInstanceOf(); if (plugin == null) { throw new Exception(string.Format( "Failed to instantiate {0} class.", LogFormat.Type(pluginType.GetType()))); } plugin.FilePath = pluginFilePath; plugin.FileHash = this.assemblyLoader.GetAssemblyHash(pluginFilePath); this.pluginRegistry.Add(plugin.AssemblyName, plugin); } catch (Exception e) { this.pluginLog.WriteError("Error loading plugin: {0}", LogFormat.Exception(e)); this.disposedPlugins.Add(pluginAssembly); plugin = null; } return(plugin); }
public void EnsureCreationChain(ComponentRequirementMap map) { if (this.initCreationChain == RecursiveInit.Initialized) { return; } if (this.initCreationChain == RecursiveInit.InProgress) { Logs.Core.WriteWarning( "Detected a cyclic Component requirement in {0}. Requirements can not be ensured for cyclic dependencies.", LogFormat.Type(this.Component)); return; } this.initCreationChain = RecursiveInit.InProgress; this.InitCreationChain(map); this.initCreationChain = RecursiveInit.Initialized; }
/// <summary> /// Clears the specified constraint graph of all loops. /// </summary> /// <param name="graph"></param> private static void ResolveConstraintLoops(Dictionary <Type, List <OrderConstraint> > graph) { while (true) { List <OrderConstraint> loop = FindConstraintLoop(graph); if (loop == null) { return; } // Found a loop? Find the weakest link in it OrderConstraint weakestLink = loop[0]; for (int i = 1; i < loop.Count; i++) { OrderConstraint link = loop[i]; if ((int)link.Priority < (int)weakestLink.Priority) { weakestLink = link; } } // If the loops weakest link was an explicit constraint, log a warning if ((int)weakestLink.Priority >= (int)ConstraintPriority.ExplicitWeak) { Logs.Core.WriteWarning( "Found a loop in the component execution order constraint graph. Ignoring the weakest constraint " + "({0} must be executed before {1}). Please check your ExecutionOrder attributes.", LogFormat.Type(weakestLink.FirstType), LogFormat.Type(weakestLink.LastType)); } // Remove the weakest link List <OrderConstraint> links = graph[weakestLink.FirstType]; links.Remove(weakestLink); if (links.Count == 0) { graph.Remove(weakestLink.FirstType); } } }
public void AddComponent(ComponentCopy newComp) { Type type = newComp.GetType(); // Consistency checks. Don't fail silently when we can't do what was intended. if (newComp.gameobj != null) { throw new ArgumentException(string.Format( "Specified Component '{0}' is already part of another GameObject '{1}'", LogFormat.Type(type), newComp.gameobj.FullName)); } if (this.compMap.ContainsKey(type)) { throw new InvalidOperationException(string.Format( "GameObject '{0}' already has a Component of type '{1}'.", this, LogFormat.Type(type))); } this.AddComponent(newComp, type); }
private static void CleanInputSources(Assembly invalidAssembly) { string warningText = string.Format( "Found leaked input source '{1}' defined in invalid Assembly '{0}'. " + "This is a common problem when registering input sources from within a CorePlugin " + "without properly unregistering them later. Please make sure that all sources are " + "unregistered in CorePlugin::OnDisposePlugin() or sooner.", invalidAssembly.GetShortAssemblyName(), "{0}"); if (DualityApp.Mouse.Source != null && DualityApp.Mouse.Source.GetType().GetTypeInfo().Assembly == invalidAssembly) { Logs.Core.WriteWarning(warningText, LogFormat.Type(DualityApp.Mouse.Source.GetType())); DualityApp.Mouse.Source = null; } if (DualityApp.Keyboard.Source != null && DualityApp.Keyboard.Source.GetType().GetTypeInfo().Assembly == invalidAssembly) { Logs.Core.WriteWarning(warningText, LogFormat.Type(DualityApp.Keyboard.Source.GetType())); DualityApp.Keyboard.Source = null; } foreach (JoystickInput joystick in DualityApp.Joysticks.ToArray()) { if (joystick.Source != null && joystick.Source.GetType().GetTypeInfo().Assembly == invalidAssembly) { Logs.Core.WriteWarning(warningText, LogFormat.Type(joystick.Source.GetType())); DualityApp.Joysticks.RemoveSource(joystick.Source); } } foreach (GamepadInput gamepad in DualityApp.Gamepads.ToArray()) { if (gamepad.Source != null && gamepad.Source.GetType().GetTypeInfo().Assembly == invalidAssembly) { Logs.Core.WriteWarning(warningText, LogFormat.Type(gamepad.Source.GetType())); DualityApp.Gamepads.RemoveSource(gamepad.Source); } } }
internal static void InitBackend <T>(out T target, Func <Type, IEnumerable <TypeInfo> > typeFinder = null) where T : class, IDualityBackend { if (typeFinder == null) { typeFinder = GetAvailDualityTypes; } Logs.Core.Write("Initializing {0}...", LogFormat.Type(typeof(T))); Logs.Core.PushIndent(); // Generate a list of available backends for evaluation List <IDualityBackend> backends = new List <IDualityBackend>(); foreach (TypeInfo backendType in typeFinder(typeof(IDualityBackend))) { if (backendType.IsInterface) { continue; } if (backendType.IsAbstract) { continue; } if (!backendType.IsClass) { continue; } if (!typeof(T).GetTypeInfo().IsAssignableFrom(backendType)) { continue; } IDualityBackend backend = backendType.CreateInstanceOf() as IDualityBackend; if (backend == null) { Logs.Core.WriteWarning("Unable to create an instance of {0}. Skipping it.", backendType.FullName); continue; } backends.Add(backend); } // Sort backends from best to worst backends.StableSort((a, b) => b.Priority > a.Priority ? 1 : -1); // Try to initialize each one and select the first that works T selectedBackend = null; foreach (T backend in backends) { if (DualityApp.AppData.Instance?.SkipBackends != null && DualityApp.AppData.Instance.SkipBackends.Any(s => string.Equals(s, backend.Id, StringComparison.OrdinalIgnoreCase))) { Logs.Core.Write("Backend '{0}' skipped because of AppData settings.", backend.Name); continue; } bool available = false; try { available = backend.CheckAvailable(); if (!available) { Logs.Core.Write("Backend '{0}' reports to be unavailable. Skipping it.", backend.Name); } } catch (Exception e) { available = false; Logs.Core.WriteWarning("Backend '{0}' failed the availability check with an exception: {1}", backend.Name, LogFormat.Exception(e)); } if (!available) { continue; } Logs.Core.Write("{0}...", backend.Name); Logs.Core.PushIndent(); { try { backend.Init(); selectedBackend = backend; } catch (Exception e) { Logs.Core.WriteError("Failed: {0}", LogFormat.Exception(e)); } } Logs.Core.PopIndent(); if (selectedBackend != null) { break; } } // If we found a proper backend and initialized it, add it to the list of active backends if (selectedBackend != null) { target = selectedBackend; TypeInfo selectedBackendType = selectedBackend.GetType().GetTypeInfo(); pluginManager.LockPlugin(selectedBackendType.Assembly); } else { target = null; } Logs.Core.PopIndent(); }
/// <summary> /// Returns an existing <see cref="ProfileCounter"/> with the specified name. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name">The <see cref="ProfileCounter"/> name to use for this measurement. For nested measurements, use path strings, e.g. "ParentCounter\ChildCounter"</param> public static T GetCounter <T>(string name) where T : ProfileCounter { if (name == null) { return(null); } ProfileCounter c; if (!counterMap.TryGetValue(name, out c)) { return(null); } T cc = c as T; if (cc == null) { throw new InvalidOperationException(string.Format("The specified performance counter '{0}' is not a {1}.", name, LogFormat.Type(typeof(T)))); } return(cc); }
private static CreateMethod CreateObjectActivator(TypeInfo typeInfo, out object firstResult) { Exception lastError = null; CreateMethod activator; firstResult = null; // Filter out non-instantiatable Types if (typeInfo.IsAbstract || typeInfo.IsInterface || typeInfo.IsGenericTypeDefinition) { activator = nullObjectActivator; } // If the caller wants a string, just return an empty one else if (typeInfo.AsType() == typeof(string)) { activator = () => ""; } // If the caller wants an array, create an empty one else if (typeInfo.IsArray && typeInfo.GetArrayRank() == 1) { activator = () => Array.CreateInstance(typeInfo.GetElementType(), 0); } // For structs, boxing a default(T) is sufficient else if (typeInfo.IsValueType) { var lambda = Expression.Lambda <CreateMethod>(Expression.Convert(Expression.Default(typeInfo.AsType()), typeof(object))); activator = lambda.Compile(); } else { activator = nullObjectActivator; // Retrieve constructors, sorted from trivial to parameter-rich ConstructorInfo[] constructors = typeInfo.DeclaredConstructors .Where(c => !c.IsStatic) .Select(c => new { Info = c, ParamCount = c.GetParameters().Length }) .OrderBy(s => s.ParamCount) .Select(s => s.Info) .ToArray(); foreach (ConstructorInfo con in constructors) { // Prepare constructor argument values - just use default(T) for all of them. ParameterInfo[] conParams = con.GetParameters(); Expression[] args = new Expression[conParams.Length]; for (int i = 0; i < args.Length; i++) { Type paramType = conParams[i].ParameterType; args[i] = Expression.Default(paramType); } // Compile a lambda method invoking the constructor var lambda = Expression.Lambda <CreateMethod>(Expression.New(con, args)); activator = lambda.Compile(); // Does it work? firstResult = CheckActivator(activator, out lastError); if (firstResult != null) { break; } } // If there were no suitable constructors, log a generic warning. if (constructors.Length == 0) { Logs.Core.WriteWarning( "Failed to create object of Type {0}. Make sure there is a trivial constructor.", LogFormat.Type(typeInfo)); } } // Test whether our activation method really works, replace with dummy if not if (firstResult == null) { // If we didn't yet try to create an object instance or value, do it now. if (lastError == null) { firstResult = CheckActivator(activator, out lastError); } // If there was an error / Exception thrown while creating the object, inform someone. if (lastError != null) { // If it's a problem in a static constructor, get the inner exception to know what's actually wrong. if (lastError is TypeInitializationException) { Logs.Core.WriteError("Failed to initialize Type {0}: {1}", LogFormat.Type(typeInfo), LogFormat.Exception(lastError.InnerException)); } // Otherwise, just do a regular error log. else { Logs.Core.WriteError("Failed to create object of Type {0}: {1}", LogFormat.Type(typeInfo), LogFormat.Exception(lastError)); } } } // If we still don't have anything, just use a dummy. if (firstResult == null) { activator = nullObjectActivator; } return(activator); }