Example #1
0
        /// <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);
        }
Example #2
0
 /// <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()));
 }
Example #3
0
        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");
                }
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
 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)));
     }
 }
Example #7
0
        /// <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);
        }
Example #8
0
            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;
            }
Example #9
0
        /// <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);
                }
            }
        }
Example #10
0
        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);
        }
Example #11
0
        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);
                }
            }
        }
Example #12
0
        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();
        }
Example #13
0
        /// <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);
        }
Example #14
0
        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);
        }