public static (string[], string) GetDefaultTexturesAndActive(Imported model, string defFromVisibleMesh)
        {
            string[] textures = new string[model.materialMappings.Length];
            SKAnimatorToolsProxy.IncrementEnd(textures.Length);

            for (int index = 0; index < model.materialMappings.Length; index++)
            {
                MaterialMapping mapping = model.materialMappings[index];
                ConfigReference texRef  = (ConfigReference)mapping.material.getArguments().getOrDefault("Texture", null);
                if (texRef != null)
                {
                    string file = (string)texRef.getArguments().getOrDefault("File", null);
                    if (file != null)
                    {
                        textures[index] = file;
                        if (mapping.texture == defFromVisibleMesh)
                        {
                            defFromVisibleMesh = new FileInfo(file).Name;
                        }
                    }
                }
                SKAnimatorToolsProxy.IncrementProgress();
            }

            return(textures, defFromVisibleMesh);
        }
Пример #2
0
        /// <summary>
        /// Sets the arguments of the given <see cref="ConfigReference"/>.
        /// </summary>
        /// <param name="cfgRef">The ConfigReference to alter.</param>
        /// <param name="newArgMap">The new ArgumentMap that this ConfigReference will use.</param>
        /// <exception cref="ArgumentNullException">If args is null</exception>
        public static void SetArguments(this ConfigReference cfgRef, ArgumentMap newArgMap)
        {
            if (newArgMap == null)
            {
                throw new ArgumentNullException("newArgMap");
            }
            ArgumentMap currentArgs = cfgRef.getArguments();

            currentArgs.clear();
            object[] keys = newArgMap.keySet().toArray();
            foreach (object key in keys)
            {
                currentArgs.put(key, newArgMap.get(key));
            }
        }
Пример #3
0
        /// <summary>
        /// Attempts to resolve this <see cref="ConfigReference"/>, which is expected to point to a file, and returns the Clyde object that it points to.<para/>
        /// This is intended for use in cases where data must absolutely be loaded in-line. Most cases are better suited for <see cref="ConfigReferenceUtil"/> and its methods.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cfgRef"></param>
        /// <returns></returns>
        public static T ResolveFile <T>(this ConfigReference cfgRef) where T : class
        {
            if (!cfgRef.IsFileReference())
            {
                throw new InvalidOperationException("Cannot resolve this ConfigReference as a file because the file it points to does not exist (or it references an actual config object)!");
            }
            object clydeObject = ClydeFileHandler.GetRaw(new FileInfo(ResourceDirectoryGrabber.ResourceDirectoryPath + cfgRef.getName()));

            if (clydeObject == null)
            {
                throw new NullReferenceException("Failed to load Clyde file!");
            }

            // Apply any arguments.
            if (clydeObject is ParameterizedConfig paramCfg)
            {
                paramCfg.ApplyArguments(cfgRef.getArguments() ?? new ArgumentMap());
            }
            return(clydeObject as T);
        }
Пример #4
0
        /// <summary>
        /// Using the information in this <see cref="ConfigReference"/>, the object this reference points to will be resolved and returned. This <see cref="ConfigReference"/> must point to an actual configuration. If it points to a file, an <see cref="InvalidOperationException"/> will be thrown.<para/>
        /// This will automatically populate the arguments in the referenced config if applicable, making usage of the returned object relatively straightforward.
        /// </summary>
        /// <param name="cfgRef">The ConfigReference to resolve the reference to.</param>
        /// <typeparam name="T">The destination type for the new ManagedConfig</typeparam>
        /// <returns>The ManagedConfig the given ConfigReference is pointing to.</returns>
        /// <exception cref="InvalidOperationException">If IsFileReference() returns true on this ConfigReference.</exception>
        public static T Resolve <T>(this ConfigReference cfgRef) where T : ManagedConfig
        {
            if (cfgRef.IsFileReference())
            {
                throw new InvalidOperationException("Cannot resolve the path to a non-config reference (this ConfigReference points to a file!)");
            }
            T mgCfg = ConfigReferenceBootstrapper.ConfigReferences.TryGetReferenceFromName(cfgRef.getName())?.CloneAs <T>();

            // Populate the values of the referenced object if possible.
            if (mgCfg is ParameterizedConfig paramCfg)
            {
                // This can store arguments.
                paramCfg.ApplyArguments(cfgRef.getArguments());
                return(paramCfg as T);
            }
            // It's gotta stay as a ManagedConfig
            // Can't make use of this to apply arguments to. How do I handle this?
            // For now: Return the object without any changes.
            return(mgCfg);
        }
Пример #5
0
        /// <summary>
        /// Takes the <see cref="ArgumentMap"/> within this <see cref="ConfigReference"/> and translates it into the dictionary format used by TRS's extra data containers.
        /// </summary>
        /// <param name="cfgRef">The ConfigReference to get the data from.</param>
        /// <param name="createSubDict">If true, the returned dictionary has a single key called "DirectArgs" which contains the arguments. If false, the arguments are returned as the dictionary itself.</param>
        /// <returns>A dictionary containing the arguments for the directs on the given destination object.</returns>
        public static Dictionary <string, dynamic> ArgumentsToExtraData(this ConfigReference cfgRef, bool createSubDict = true)
        {
            Dictionary <string, dynamic> dict = new Dictionary <string, dynamic>();
            ArgumentMap args = cfgRef.getArguments();

            object[] keys = args.keySet().toArray();
            foreach (object key in keys)
            {
                dict[key.ToString()] = args.get(key);
            }
            if (createSubDict)
            {
                return(new Dictionary <string, dynamic> {
                    ["DirectArgs"] = dict
                });
            }
            else
            {
                return(dict);
            }
        }
Пример #6
0
        /// <summary>
        /// Given a <see cref="ParameterizedConfig"/> and a path from a direct as well as a target value, this will modify the <see cref="ParameterizedConfig"/> so that its fields reflect the given value.<para/>
        /// If this data cannot be set due to it being on a direct chain (the end value is a <see cref="ConfigReference"/>), that <see cref="ConfigReference"/> will be returned
        /// </summary>
        /// <param name="config"></param>
        /// <param name="path"></param>
        /// <param name="argValue"></param>
        /// <param name="setToNull">If true, and if argValue is null, the property will actually be set to null (if this is false, it will skip applying it)</param>
        public static ConfigReference SetDataOn(ParameterizedConfig config, string path, object argValue, bool setToNull = false)
        {
            if (argValue == null && !setToNull)
            {
                return(null);
            }
            // implementation.material_mappings[0].material["Texture"]["File"]

            // A bit of a hack to make splitting this path easier:
            path = path.Replace("[", ".[");

            // The latest object stored when traversing this direct's path.
            object latestObject   = config;
            string previousIndex  = null;
            object previousObject = null;

            // Split it by the segments of this path, and get rid of the implementation word at the start if needed.
            string[] pathSegments = path.Split('.');
            if (pathSegments[0] == "implementation")
            {
                latestObject = ReflectionHelper.Get(latestObject, "implementation");
                pathSegments = pathSegments.Skip(1).ToArray();
            }

            for (int idx = 0; idx < pathSegments.Length; idx++)
            {
                string currentIndex    = pathSegments[idx].SnakeToCamel();
                string betweenBrackets = currentIndex.BetweenBrackets();
                if (betweenBrackets != null)
                {
                    // This is either an array index, or a reference to a config.
                    // The simple way to test this is that if it's a numeric index, it's an array index.
                    if (int.TryParse(betweenBrackets, out int arrayIndex))
                    {
                        // Access this array index. It is a number in brackets like [0]
                        previousObject = latestObject;
                        latestObject   = ReflectionHelper.GetArray(latestObject, arrayIndex);
                    }
                    else
                    {
                        // Access the config reference. This is branching from a config reference and accesses a parameter ["Parameter Name"]
                        ConfigReference latestAsCfg   = (ConfigReference)latestObject;
                        string          parameterName = betweenBrackets.Substring(1, betweenBrackets.Length - 2);

                        // First things first: Resolve the config reference.
                        string configRefPath = latestAsCfg.getName();

                        // cloning this is super important as the tryget method will return a template object.
                        // Do not edit the template!
                        if (!latestAsCfg.IsRealReference())
                        {
                            // Catch case: This isn't actually pointing to a *configuration*, rather a direct object reference.
                            latestAsCfg.getArguments().put(parameterName, argValue);
                            return(null);
                        }
                        ParameterizedConfig referencedConfig = ConfigReferenceBootstrapper.ConfigReferences.TryGetReferenceFromName(configRefPath)?.CloneAs <ParameterizedConfig>();
                        if (referencedConfig == null)
                        {
                            XanLogger.WriteLine("Something failed to reference a ConfigReference (It tried to search for \"" + configRefPath + "\", which doesn't exist). Some information on this model may not load properly!", XanLogger.DEBUG, System.Drawing.Color.DarkGoldenrod);
                            return(null);
                        }

                        // So there's our reference. Now we need to get a parameter from it.
                        Parameter referencedParam = referencedConfig.getParameter(parameterName);
                        if (referencedParam is Parameter.Direct referencedDirect)
                        {
                            ConfigReference[] chainRefs = SetDataOn(referencedConfig, referencedDirect.paths, argValue);
                            if (chainRefs != null)
                            {
                                // We're pointing to other ConfigReferences which means that this is a direct chain. Oh brother.
                                foreach (ConfigReference reference in chainRefs)
                                {
                                    if (reference != null)
                                    {
                                        if (File.Exists(ResourceDirectoryGrabber.ResourceDirectoryPath + configRefPath))
                                        {
                                            // Catch case: This isn't actually pointing to a *configuration*, rather a direct object reference.
                                            latestAsCfg.getArguments().put(parameterName, argValue);
                                        }
                                        else
                                        {
                                            ParameterizedConfig forwardRefConfig = reference.Resolve <ParameterizedConfig>();
                                            // Using as because it might be null.
                                            if (forwardRefConfig != null)
                                            {
                                                foreach (Parameter subRefParam in forwardRefConfig.parameters)
                                                {
                                                    if (subRefParam is Parameter.Direct subRefDirect)
                                                    {
                                                        WrappedDirect wrappedSubRefDir = new WrappedDirect(forwardRefConfig, subRefDirect);
                                                        wrappedSubRefDir.SetValue(argValue);
                                                    }
                                                }

                                                latestAsCfg.getArguments().put(parameterName, ConfigReferenceConstructor.MakeConfigReferenceTo(forwardRefConfig));
                                            }
                                            else
                                            {
                                                XanLogger.WriteLine("ALERT: Model attempted to set value of Direct [" + currentIndex + "] but it failed because the target object was not a ParameterizedConfig! Some information may be incorrect on this model.", XanLogger.DEBUG, System.Drawing.Color.DarkGoldenrod);
                                                return(null);
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // This is by far one of the most hacky methods I've ever done in OOO stuff.
                                // So basically, a model has a property for something like say, materials.
                                // This property is a ConfigReference to a material object, and that ConfigReference has arguments in it
                                //    that tell the referenced material what it should be.
                                // Rather than trying to traverse that ConfigReference and set the data on the remote object (PAINFUL), I
                                //    instead decided to write a system that can wrap any ParameterizedConfig into a ConfigReference and just
                                //    call it a day.
                                ReflectionHelper.Set(previousObject, previousIndex, ConfigReferenceConstructor.MakeConfigReferenceTo(referencedConfig));
                            }
                        }
                        else
                        {
                            //throw new NotImplementedException("Cannot set data on referenced parameters that are not Directs (yet).");
                            XanLogger.WriteLine("Feature Not Implemented: Cannot set data on referenced parameters that aren't directs (e.g. parameters that are choices)", XanLogger.STANDARD, System.Drawing.Color.Orange);
                            return(null);
                        }
                        return(null);
                    }
                }
                else
                {
                    // This is referencing a property.
                    // But wait: If this is the second to last object, then we gotta modify it.
                    if (idx == pathSegments.Length - 1)
                    {
                        // Second to last object. latestObject will contain the property that we want to set.
                        // Let's manually find that field and set it
                        if (currentIndex.BetweenBrackets() == null)
                        {
                            // We're good here.
                            if (argValue is ConfigReference argValueCfg)
                            {
                                // There's some cases when a variant wants to set a config reference.
                                // In these cases, we need to make sure the property is also a config reference so we know it's safe to set.
                                // ... But before that, catch case: Not actually a config.
                                if (argValueCfg.IsRealReference())
                                {
                                    object ptr = ReflectionHelper.Get(previousObject, previousIndex);
                                    if (ptr is ConfigReference)
                                    {
                                        ReflectionHelper.Set(previousObject, previousIndex, argValueCfg);
                                    }
                                    else
                                    {
                                        if (ReflectionHelper.GetTypeOfField(latestObject, currentIndex) == argValueCfg.GetType())
                                        {
                                            ReflectionHelper.Set(latestObject, currentIndex, argValueCfg);
                                            return(null);
                                        }
                                        else
                                        {
                                            XanLogger.WriteLine("ALERT: Model attempted to set value of Direct [" + currentIndex + "] but it failed due to a type mismatch! Certain data on this model might be incorrect.", XanLogger.DEBUG, System.Drawing.Color.DarkGoldenrod);
                                            return(null);
                                        }
                                    }
                                }
                                else
                                {
                                    if (ReflectionHelper.GetTypeOfField(latestObject, currentIndex) == argValueCfg.GetType())
                                    {
                                        ReflectionHelper.Set(latestObject, currentIndex, argValueCfg);
                                        return(null);
                                    }
                                    else
                                    {
                                        XanLogger.WriteLine("ALERT: Model attempted to set value of Direct [" + currentIndex + "] but it failed due to a type mismatch! Certain data on this model might be incorrect.", XanLogger.DEBUG, System.Drawing.Color.DarkGoldenrod);
                                        return(null);
                                    }
                                }
                            }
                            else
                            {
                                // Contrary to the oddball case above, if the result value at the end of this direct is a ConfigReference
                                // then we need to return it so that whatever called this knows that it has more to traverse.
                                // Ideally, this is only returned in the nested call above.
                                string targetIndex = previousIndex;

                                /*if (int.TryParse(previousIndex.BetweenBrackets(), out int _)) {
                                 *      // The previous index was an array accessor. This means we want to actually reference the CURRENT index
                                 *      // on the PREVIOUS object. A bit odd but it's intentional.
                                 *      // This is done because the previous object will be the result of that indexer, which is identical
                                 *      // to the current object. As such, we need to use the current index to reference it.
                                 *      targetIndex = currentIndex;
                                 * }*/
                                if (previousObject == null || targetIndex == null)
                                {
                                    return(null);
                                }
                                object ptr = ReflectionHelper.Get(previousObject, targetIndex);
                                if (ptr is ConfigReference cfgRef)
                                {
                                    // Special handling. argValue goes to a property on the config reference
                                    return(cfgRef);
                                }

                                if (ptr.GetType() == argValue.GetType())
                                {
                                    ReflectionHelper.Set(previousObject, targetIndex, argValue);
                                }
                                else
                                {
                                    // In some cases, the object it's pointing to isn't the same time.
                                    // In cases where the previous index is used, this *might* mean we need to step forward like so:
                                    if (ReflectionHelper.GetTypeOfField(ptr, currentIndex) == argValue.GetType())
                                    {
                                        ReflectionHelper.Set(ptr, currentIndex, argValue);
                                    }
                                    else
                                    {
                                        // But in other cases, it's not pointing to a prop up ahead.
                                        if (ReflectionHelper.Get(ptr, currentIndex) is ConfigReference cfgRefLow)
                                        {
                                            return(cfgRefLow);
                                        }
                                        else
                                        {
                                            XanLogger.WriteLine("ALERT: Model attempted to set value of Direct [" + currentIndex + "] but it failed due to a type mismatch! Certain data on this model might be incorrect.", XanLogger.DEBUG, System.Drawing.Color.DarkGoldenrod);
                                            return(null);
                                        }
                                    }
                                }
                                return(null);
                            }
                        }
                    }
                    if (previousIndex != null)
                    {
                        if (int.TryParse(previousIndex.BetweenBrackets(), out int _) && idx == pathSegments.Length - 1)
                        {
                            if (currentIndex.BetweenBrackets() == null)
                            {
                                // We're good here.
                                ReflectionHelper.Set(previousObject, previousIndex, argValue);
                                return(null);
                            }
                        }
                    }
                    previousObject = latestObject;
                    latestObject   = ReflectionHelper.Get(latestObject, currentIndex);
                    if (previousObject == null || latestObject == null)
                    {
                        return(null);                                                                    // Failed to traverse.
                    }
                }
                previousIndex = currentIndex;
            }
            return(null);
        }
Пример #7
0
        /// <summary>
        /// Given a full path from a <see cref="Parameter.Direct"/>, this will traverse it and acquire the data at the end.<para/>
        /// This will stop if it runs into another direct and instantiate a new <see cref="WrappedDirect"/>. This will occur if there is a reference chain, for instance, in many textures it references material["Texture"] (a direct) followed by a second direct ["File"]. Since each may have multiple paths, it's best to reference a new <see cref="WrappedDirect"/>.
        /// </summary>
        /// <param name="path"></param>
        private void TraverseDirectPath(string path)
        {
            // implementation.material_mappings[0].material["Texture"]["File"]

            // A bit of a hack to make splitting this path easier:
            path = path.Replace("[", ".[");

            // The latest object stored when traversing this direct's path.
            object latestObject = Config;

            // Split it by the segments of this path, and get rid of the implementation word at the start if needed.
            string[] pathSegments = path.Split('.');
            if (pathSegments[0] == "implementation")
            {
                latestObject = ReflectionHelper.Get(latestObject, "implementation");
                pathSegments = pathSegments.Skip(1).ToArray();
            }

            for (int idx = 0; idx < pathSegments.Length; idx++)
            {
                string currentIndex    = pathSegments[idx].SnakeToCamel();
                string betweenBrackets = currentIndex.BetweenBrackets();
                if (betweenBrackets != null)
                {
                    // This is either an array index, or a reference to a config.
                    // The simple way to test this is that if it's a numeric index, it's an array index.
                    if (int.TryParse(betweenBrackets, out int arrayIndex))
                    {
                        // Access this array index. It is a number in brackets like [0]
                        latestObject = ReflectionHelper.GetArray(latestObject, arrayIndex);
                    }
                    else
                    {
                        // Access the config reference. This is branching from a config reference and accesses a parameter ["Parameter Name"]
                        ConfigReference latestAsCfg   = (ConfigReference)latestObject;
                        string          parameterName = betweenBrackets.Substring(1, betweenBrackets.Length - 2);

                        // First things first: Resolve the config reference (AND CLONE IT. Don't edit the template object!)
                        string configRefPath = latestAsCfg.getName();

                        if (!latestAsCfg.IsRealReference())
                        {
                            // Catch case: This isn't actually pointing to a *configuration*, rather a direct object reference.
                            _EndReferences.Add(new DirectEndReference(configRefPath));
                            return;
                        }

                        ParameterizedConfig referencedConfig = ConfigReferenceBootstrapper.ConfigReferences.TryGetReferenceFromName(configRefPath)?.CloneAs <ParameterizedConfig>();
                        if (referencedConfig == null)
                        {
                            XanLogger.WriteLine("Something failed to reference a ConfigReference (It tried to search for \"" + configRefPath + "\", which doesn't exist). Some information on this model may not load properly!", XanLogger.DEBUG, System.Drawing.Color.DarkGoldenrod);
                            return;
                        }

                        ArgumentMap args = latestAsCfg.getArguments();

                        // So there's our reference. Now we need to get a parameter from it.
                        ConfigReferenceContainerName = ConfigReferenceBootstrapper.ConfigReferences.GetCategoryFromEntryName(configRefPath);
                        Parameter referencedParam = referencedConfig.getParameter(parameterName);
                        if (referencedParam is Parameter.Direct referencedDirect)
                        {
                            _EndReferences.Add(new DirectEndReference(new WrappedDirect(referencedConfig, referencedDirect, null, args)));
                        }
                        else if (referencedParam is Parameter.Choice referencedChoice)
                        {
                            _EndReferences.Add(new DirectEndReference(new WrappedChoice(referencedConfig, referencedChoice, args)));
                        }
                        return;
                    }
                }
                else
                {
                    // This is referencing a property.
                    latestObject = ReflectionHelper.Get(latestObject, currentIndex);
                }
            }

            // Now here's something important: Does an argument override this?
            if (Arguments != null && Arguments.containsKey(Name) && latestObject != null)
            {
                // This direct is included as an argument...
                // And if we're down here, then we're not referencing another direct, we're referencing a property.
                // But as a final sanity check:
                if (latestObject.GetType() == Arguments.get(Name)?.GetType())
                {
                    // Yep! Our argument is the same type as the latestObject.
                    // Let's set latestObject to that argument.
                    latestObject = Arguments.get(Name);
                }
            }
            _EndReferences.Add(new DirectEndReference(latestObject));
        }
        /// <summary>
        /// Returns the currently active textures for each of the <see cref="MaterialMapping"/>s within this <see cref="ModelConfig"/>.<para/>
        /// This will only pull the textures actively in use by the model. Any other variants will not be acquired.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static string[] GetDefaultTextures(Imported model)
        {
            string[] textures = new string[model.materialMappings.Length];
            SKAnimatorToolsProxy.IncrementEnd(textures.Length);

            for (int index = 0; index < model.materialMappings.Length; index++)
            {
                MaterialMapping mapping = model.materialMappings[index];
                ConfigReference texRef  = (ConfigReference)mapping.material.getArguments().getOrDefault("Texture", null);
                if (texRef != null)
                {
                    string file = (string)texRef.getArguments().getOrDefault("File", null);
                    if (file != null)
                    {
                        textures[index] = file;
                    }
                }
                SKAnimatorToolsProxy.IncrementProgress();
            }

            /*
             * for (int index = 0; index < model.materialMappings.Length; index++) {
             *      MaterialMapping mapping = model.materialMappings[index];
             *      MaterialConfig material = mapping.material.ResolveAuto<MaterialConfig>();
             *      if (material != null) {
             *              while (material.implementation is MaterialConfig.Derived derivedMtl) {
             *                      material = derivedMtl.material.ResolveAuto<MaterialConfig>();
             *              }
             *
             *              if (material.implementation is MaterialConfig.Original originalMtl) {
             *                      foreach (TechniqueConfig technique in originalMtl.techniques) {
             *                              TechniqueConfig.Enqueuer enqueuer = technique.enqueuer;
             *                              if (enqueuer is TechniqueConfig.NormalEnqueuer normalEnq) {
             *                                      foreach (PassConfig pass in normalEnq.passes) {
             *                                              // Just find the first pass with a texture. It's not possible to have multiple textures right now in gltf
             *                                              // that is, on one model
             *                                              if (pass.textureState != null) {
             *                                                      TextureStateConfig texState = pass.textureState;
             *                                                      if (texState.units.Length > 0) {
             *                                                              TextureConfig texture = texState.units[0].texture.ResolveAuto<TextureConfig>();
             *                                                              while (texture.implementation is TextureConfig.Derived derivedTexture) {
             *                                                                      texture = derivedTexture.texture.ResolveAuto<TextureConfig>();
             *                                                              }
             *
             *                                                              if (texture.implementation is TextureConfig.Original2D tex2d) {
             *                                                                      TextureConfig.Original2D.Contents contents = tex2d.contents;
             *                                                                      if (contents is TextureConfig.Original2D.ImageFile imageFile) {
             *                                                                              textures[index] = imageFile.file;
             *                                                                      } else {
             *                                                                              // Blank.
             *                                                                              textures[index] = null;
             *                                                                      }
             *                                                              } else {
             *                                                                      XanLogger.WriteLine("Unsupported texture type " + texture.GetType().Name);
             *                                                              }
             *                                                      }
             *                                              }
             *                                      }
             *                              }
             *                      }
             *              }
             *      }
             *
             *      SKAnimatorToolsProxy.IncrementProgress();
             * }
             */
            return(textures);
        }