Example #1
0
        private DataTreeObjectProperty[] MakeModelTransformPair(ConfigReference model, Transform3D transform, BooleanExpression expr = null)
        {
            string mdlName = model?.getName() ?? "null";
            string trs     = transform?.toString() ?? "null";

            if (expr != null)
            {
                string state = "???";
                try {
                    state = expr.createEvaluator(new DummyScope()).evaluate().ToString();
                } catch { }
                return(new DataTreeObjectProperty[] {
                    new DataTreeObjectProperty("Condition: " + expr.toString() + " = " + state, SilkImage.Conditional),
                    new DataTreeObjectProperty("Model: " + mdlName, SilkImage.Reference),
                    new DataTreeObjectProperty("Transform: " + trs, SilkImage.Matrix)
                });
            }
            else
            {
                return(new DataTreeObjectProperty[] {
                    new DataTreeObjectProperty("Model: " + mdlName, SilkImage.Reference),
                    new DataTreeObjectProperty("Transform: " + trs, SilkImage.Matrix)
                });
            }
        }
        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);
        }
        /// <summary>
        /// Creates a new <see cref="ConfigReference"/> from the given name and <see cref="ArgumentMap"/><para/>
        /// For some reason, OOO doesn't offer a constructor to ConfigReference that takes in an <see cref="ArgumentMap"/>.<para/>
        /// ...And then they made all of the constructors that *can* populate args complete aids. I need to buy a punching bag.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static ConfigReference NewConfigReference(string name, ArgumentMap args)
        {
            ConfigReference newCfg = new ConfigReference(name);

            newCfg.SetArguments(args);
            return(newCfg);
        }
Example #4
0
#pragma warning disable CS0419 // Ambiguous reference in cref attribute
        /// <summary>
        /// A helper method for the two <see cref="Dereference"/> methods that takes in a Clyde object which is expected to be an animation of any type and resolves its refs.
        /// </summary>
        /// <param name="animationRef">A <see cref="ConfigReference"/> pointing to an animation.</param>
        /// <returns></returns>
        private static AnimationConfig.Implementation FinalDereference(ConfigReference animationRef)
        {
            object animationObj = animationRef.ResolveFile();

            if (animationObj is AnimationConfig animation)
            {
                AnimationConfig.Implementation impl = animation.implementation;
                if (impl is AnimationConfig.Derived newDerived)
                {
                    return(Dereference(newDerived));
                }
                else
                {
                    return(impl);
                }
            }
            else if (animationObj is AnimationConfig.ComponentAnimation newComponent)
            {
                return(Dereference(newComponent));
            }
            else
            {
                XanLogger.WriteLine(string.Format(ERR_IMPL_NOT_SUPPORTED, animationObj.GetType().Name), color: Color.DarkGoldenrod);
                return(null);
            }
        }
Example #5
0
        /// <summary>
        /// Directly copied from SK jar for now. Sets the given key to the given value on a clone of this config reference, then returns the clone.
        /// </summary>
        /// <param name="cfgRef"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static ConfigReference SetArgumentOnClone(this ConfigReference cfgRef, string key, object value)
        {
            ConfigReference configReference;

            (configReference = (ConfigReference)cfgRef.clone()).getArguments().put(key, value);
            return(configReference);
        }
Example #6
0
 /// <summary>
 /// Attempts to selectively call <see cref="Resolve(ConfigReference)"/> or <see cref="ResolveFile(ConfigReference)"/>.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="cfgRef"></param>
 /// <returns></returns>
 public static object ResolveAuto(this ConfigReference cfgRef)
 {
     if (cfgRef.IsFileReference())
     {
         return(ResolveFile(cfgRef));
     }
     else
     {
         return(Resolve(cfgRef));
     }
 }
Example #7
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));
            }
        }
Example #8
0
 /// <summary>
 /// Attempts to selectively call <see cref="Resolve{T}(ConfigReference)"/> or <see cref="ResolveFile{T}(ConfigReference)"/>.<para/>
 /// Unlike <see cref="ResolveAuto(ConfigReference)"/>, this may throw a <see cref="InvalidCastException"/> in the event that the config is not a file reference and <typeparamref name="T"/> is not a <see cref="ManagedConfig"/>.
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="cfgRef"></param>
 /// <returns></returns>
 public static T ResolveAuto <T>(this ConfigReference cfgRef) where T : class
 {
     if (cfgRef.IsFileReference())
     {
         return(ResolveFile <T>(cfgRef));
     }
     else
     {
         if (typeof(ManagedConfig).IsAssignableFrom(typeof(T)))
         {
             return(Resolve <ManagedConfig>(cfgRef) as T);
         }
         else
         {
             throw new InvalidCastException("ResolveAuto<T> for a ConfigReference failed because the reference points to configs and the desired type is not a ManagedConfig!");
         }
     }
 }
Example #9
0
        /// <summary>
        /// Takes in a <see cref="ConfigReference"/> and loads its data. It then returns the loaded model and all of its descendants as a list of <see cref="Model3D"/> instances.
        /// </summary>
        /// <param name="sourceFile">The original base-level file that contains the reference.</param>
        /// <param name="reference">The reference itself.</param>
        /// <param name="modelCollection">A list of every model that has been loaded recursively.</param>
        /// <param name="dataTreeParent">For cases where the GUI is used, this is the data tree representation.</param>
        /// <param name="globalTransform">The transformation to apply to all loaded models.</param>
        /// <param name="appendModelsToModelCollection">If true, the loaded models will be appended to <paramref name="modelCollection"/>.</param>
        /// <param name="extraData">Any extra data that should be included. This is mainly used by references (e.g. a reference is a <see cref="StaticSetConfig"/>, the target model in the set may be included as extra data)</param>
        public static List <Model3D> HandleConfigReference(FileInfo sourceFile, ConfigReference reference, List <Model3D> modelCollection, DataTreeObject dataTreeParent, Transform3D globalTransform, bool appendModelsToModelCollection = true, Dictionary <string, dynamic> extraData = null)
        {
            if (reference == null)
            {
                return(null);
            }
            string filePathRelativeToRsrc = reference.getName();

            if (extraData == null)
            {
                extraData = reference.ArgumentsToExtraData();
            }
            else
            {
                extraData = extraData.MergeWith(reference.ArgumentsToExtraData());
            }
            return(HandleConfigReferenceFromLiteralPath(sourceFile, filePathRelativeToRsrc, modelCollection, dataTreeParent, globalTransform, appendModelsToModelCollection, extraData));
        }
Example #10
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);
        }
Example #11
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);
        }
Example #12
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);
            }
        }
Example #13
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);
        }
Example #14
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));
        }
Example #15
0
 /// <summary>
 /// Returns <see langword="true"/> if this <see cref="ConfigReference"/> points to an actual config, and <see langword="false"/> if it does not (for instance, it points to a model file instead).
 /// </summary>
 /// <param name="cfgRef"></param>
 /// <returns>False if this ConfigReference points to a literal file (points to a .dat file in the rsrc directory), and true if it points to an actual configuration object (e.g. Texture/2D/Default for textures)</returns>
 public static bool IsRealReference(this ConfigReference cfgRef)
 {
     return(!File.Exists(ResourceDirectoryGrabber.ResourceDirectoryPath + cfgRef.getName()));
 }
        /// <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);
        }
Example #17
0
 /// <summary>
 /// Returns <see langword="true"/> if this <see cref="ConfigReference"/> points to a .dat file, and <see langword="false"/> if it does not (for instance, it's being used as an actual reference to a config object).
 /// </summary>
 /// <param name="cfgRef"></param>
 /// <returns>True if this ConfigReference points to a literal file (points to a .dat file in the rsrc directory), and false if it points to an actual configuration object (e.g. Texture/2D/Default for textures)</returns>
 public static bool IsFileReference(this ConfigReference cfgRef) => !IsRealReference(cfgRef);
        public void HandleModelConfig(FileInfo sourceFile, ModelConfig baseModel, List <Model3D> modelCollection, DataTreeObject dataTreeParent = null, Transform3D globalTransform = null, Dictionary <string, dynamic> extraData = null)
        {
            // ModelConfigHandler.SetupCosmeticInformation(baseModel, dataTreeParent);

            // ArticulatedConfig has a lot of steps.
            SKAnimatorToolsProxy.IncrementEnd(4);

            ArticulatedConfig model = (ArticulatedConfig)baseModel.implementation;

            SetupCosmeticInformation(model, dataTreeParent);

            MeshSet meshes = model.skin;

            VisibleMesh[] renderedMeshes = meshes.visible;
            Dictionary <string, Armature> allInstantiatedArmatures = new Dictionary <string, Armature>();

            List <Model3D> allModelsAndNodes = new List <Model3D>();

            // 1
            SKAnimatorToolsProxy.IncrementProgress();

            int    idx           = 0;
            string depth1Name    = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile);
            string fullDepthName = ResourceDirectoryGrabber.GetDirectoryDepth(sourceFile, -1);

            SKAnimatorToolsProxy.IncrementEnd(renderedMeshes.Length);
            foreach (VisibleMesh mesh in renderedMeshes)
            {
                string meshTitle = "-Skin-Mesh[" + idx + "]";

                Model3D meshToModel = GeometryConfigTranslator.GetGeometryInformation(mesh.geometry, fullDepthName + meshTitle, model.root);
                meshToModel.Name = depth1Name + meshTitle;
                if (globalTransform != null)
                {
                    meshToModel.Transform.composeLocal(globalTransform);
                }

                (List <string> textureFiles, string active) = ModelPropertyUtility.FindTexturesAndActiveFromDirects(baseModel, mesh.texture);
                meshToModel.Textures.SetFrom(textureFiles);
                meshToModel.ActiveTexture = active;

                if (meshToModel.Mesh.HasBoneData)
                {
                    XanLogger.WriteLine("Model has bone data, setting that up.", XanLogger.TRACE);
                    // meshToModel.Mesh.SetBones(model.root);
                    // ^ now called by GetGeometryInformation
                    foreach (KeyValuePair <string, Armature> boneNamesToBones in meshToModel.Mesh.AllBones)
                    {
                        allInstantiatedArmatures[boneNamesToBones.Key] = boneNamesToBones.Value;
                    }
                    allModelsAndNodes.Add(meshToModel);
                }
                modelCollection.Add(meshToModel);
                idx++;

                SKAnimatorToolsProxy.IncrementProgress();
            }
            // 2
            SKAnimatorToolsProxy.IncrementProgress();

            SKAnimatorToolsProxy.IncrementEnd(GetNodeCount(model.root));
            Dictionary <string, Model3D> nodeModels = new Dictionary <string, Model3D>();

            RecursivelyIterateNodes(baseModel, model, sourceFile, model.root, modelCollection, globalTransform, globalTransform, nodeModels, fullDepthName);
            allModelsAndNodes.AddRange(nodeModels.Values);

            SKAnimatorToolsProxy.SetProgressState(ProgressBarState.ExtraWork);
            SKAnimatorToolsProxy.IncrementEnd(model.attachments.Length);

            foreach (Attachment attachment in model.attachments)
            {
                List <Model3D> attachmentModels = ConfigReferenceUtil.HandleConfigReference(sourceFile, attachment.model, modelCollection, dataTreeParent, globalTransform);
                if (attachmentModels == null)
                {
                    SKAnimatorToolsProxy.IncrementProgress();
                    continue;                     // A lot of attachments have null models and I'm not sure why.
                }

                // NEW BEHAVIOR: Is the model root-less but rigged?
                // Set its root to *this* model
                foreach (Model3D mdl in attachmentModels)
                {
                    if (mdl.Mesh != null && mdl.Mesh.UsesExternalRoot)
                    {
                        mdl.Mesh.SetBones(model.root);
                    }
                }

                SKAnimatorToolsProxy.IncrementEnd(attachmentModels.Count);
                foreach (Model3D referencedModel in attachmentModels)
                {
                    referencedModel.Transform.composeLocal(attachment.transform);
                    if (allInstantiatedArmatures.ContainsKey(attachment.node ?? string.Empty))
                    {
                        referencedModel.AttachmentNode = allInstantiatedArmatures[attachment.node];
                        XanLogger.WriteLine("Attached [" + referencedModel.Name + "] to [" + attachment.node + "]", XanLogger.TRACE);
                    }
                    else
                    {
                        // New catch case: This might actually be the name of a model!
                        if (nodeModels.ContainsKey(attachment.node ?? string.Empty))
                        {
                            // Indeed it is!

                            referencedModel.AttachmentModel = nodeModels[attachment.node];
                            referencedModel.AttachmentModel.Transform.setScale(1f);                             // TODO: Is this okay?

                            if (referencedModel.Transform.getType() < Transform3D.AFFINE)
                            {
                                float scale = referencedModel.Transform.getScale();
                                referencedModel.Transform.set(new Transform3D(new Vector3f(), Quaternion.IDENTITY, scale));
                            }
                            else
                            {
                                Vector3f scale = referencedModel.Transform.extractScale();
                                referencedModel.Transform.set(new Transform3D(new Vector3f(), Quaternion.IDENTITY, scale));
                            }


                            XanLogger.WriteLine("Attached [" + referencedModel.Name + "] to [" + attachment.node + "]", XanLogger.TRACE);
                        }
                        else
                        {
                            XanLogger.WriteLine("Attachment wanted to attach to node or model [" + attachment.node + "] but it does not exist!");
                        }
                    }
                    SKAnimatorToolsProxy.IncrementProgress();
                }
                SKAnimatorToolsProxy.IncrementProgress();
            }

            SKAnimatorToolsProxy.SetProgressState(ProgressBarState.OK);
            // 3
            SKAnimatorToolsProxy.IncrementProgress();

            SKAnimatorToolsProxy.IncrementEnd(model.animationMappings.Length);
            foreach (AnimationMapping animationMapping in model.animationMappings)
            {
                ConfigReference animationRef = animationMapping.animation;
                if (animationRef.IsFileReference())
                {
                    object animationObj = animationRef.ResolveFile();
                    if (animationObj is AnimationConfig animation)
                    {
                        SKAnimatorToolsProxy.SetProgressState(ProgressBarState.ExtraWork);
                        AnimationConfigHandler.HandleAnimationImplementation(animationRef, animationMapping.name, animation, animation.implementation, allModelsAndNodes);
                        SKAnimatorToolsProxy.SetProgressState(ProgressBarState.OK);
                    }
                }
                SKAnimatorToolsProxy.IncrementProgress();
            }

            // 4
            SKAnimatorToolsProxy.IncrementProgress();
        }
Example #19
0
        // private const string ERR_PROC_NOT_YET_SUPPORTED = "This Procedural animation [{0}] cannot be loaded yet! Only certain instances of this type work right now.";

        /// <summary>
        /// Handles the given <see cref="AnimationConfig"/> and applies it to the already loaded <see cref="Model3D"/>s.
        /// </summary>
        /// <param name="srcConfig"></param>
        /// <param name="name"></param>
        /// <param name="original"></param>
        /// <param name="animationImplementation"></param>
        /// <param name="attachToModels"></param>
        public static void HandleAnimationImplementation(ConfigReference srcConfig, string name, AnimationConfig original, AnimationConfig.Implementation animationImplementation, List <Model3D> attachToModels)
        {
            // FileInfo srcFile = new FileInfo(ResourceDirectoryGrabber.ResourceDirectoryPath + srcConfig.getName());
            SKAnimatorToolsProxy.IncrementEnd();
            // Clear out any derived references all the way until we dig down to an original implementation.
            if (animationImplementation is AnimationConfig.Derived derived)
            {
                animationImplementation = Dereference(derived);
            }

            if (animationImplementation is AnimationConfig.Imported imported)
            {
                // As OOO says:
                // The transforms for each target, each frame.
                Transform3D[][] transforms = imported.transforms;

                // So presumably this means that...
                // ...It's backwards! First dimension is the frame number, second dimension is the transform for each target.
                // big brain time

                // ... I swear they must've been waiting for someone like me to come along. Purposely being confusing.
                float fps = imported.rate;

                Animation animation     = new Animation(name);
                int       numIterations = transforms.Length;
                if (imported.skipLastFrame)
                {
                    numIterations--;
                }

                SKAnimatorToolsProxy.IncrementEnd(numIterations);
                for (int frameIndex = 0; frameIndex < numIterations; frameIndex++)
                {
                    Transform3D[]      targetFrames = transforms[frameIndex];
                    Animation.Keyframe keyframe     = new Animation.Keyframe();
                    for (int targetIndex = 0; targetIndex < imported.targets.Length; targetIndex++)
                    {
                        string      target    = imported.targets[targetIndex];
                        Transform3D transform = targetFrames[targetIndex];

                        // Catch case: Might be null.
                        // Since I'm hellbent on doing things oddly for this part of the program, I'll manually interpolate lol
                        if (transform == null)
                        {
                            Transform3D nextTransform     = null;
                            Transform3D previousTransform = null;
                            int         prevIndex         = 0;
                            int         nextIndex         = 0;
                            // Start at 1 because if there's a single frame gap, then the result of ^ will be 2
                            // And then this will count as frame 1 instead of 0, causing 1/2 or 0.5.
                            for (int aheadIndex = 0; aheadIndex < numIterations; aheadIndex++)
                            {
                                if (aheadIndex > frameIndex)
                                {
                                    nextTransform = transforms[aheadIndex][targetIndex];
                                    if (nextTransform != null)
                                    {
                                        nextIndex = aheadIndex;
                                    }
                                }
                                else
                                {
                                    Transform3D prev = transforms[aheadIndex][targetIndex];
                                    if (prev != null)
                                    {
                                        previousTransform = prev;
                                        prevIndex         = aheadIndex;
                                    }
                                }
                            }

                            int max = nextIndex - prevIndex;
                            for (float progress = 0; progress < max; progress++)
                            {
                                int trsIndex = prevIndex + (int)progress + 1;
                                transforms[trsIndex][targetIndex] = previousTransform.lerp(nextTransform, progress / max);
                            }
                        }

                        keyframe.Keys.Add(new Animation.Key {
                            Node      = target,
                            Transform = transform
                        });
                        keyframe.Time = frameIndex / fps;
                    }
                    animation.Keyframes.Add(keyframe);
                    SKAnimatorToolsProxy.IncrementProgress();
                }

                foreach (Model3D model in attachToModels)
                {
                    model.Animations.Add(animation);
                }
            }
            else if (animationImplementation is AnimationConfig.Sequential sequential)
            {
                //AnimationConfig.Implementation[] subs = new AnimationConfig.Implementation[sequential.animations.Length];

                SKAnimatorToolsProxy.IncrementEnd(sequential.animations.Length);
                for (int index = 0; index < sequential.animations.Length; index++)
                {
                    AnimationConfig.ComponentAnimation component = sequential.animations[index];
                    HandleAnimationImplementation(srcConfig, name, original, Dereference(component), attachToModels);
                    SKAnimatorToolsProxy.IncrementProgress();
                }

                /*
                 * } else if (animationImplementation is AnimationConfig.Procedural proc) {
                 *
                 *      if (srcFile.Name.StartsWith("rotate_")) {
                 *              // Rotation animation
                 *              // The first transform's first target is the node it attaches to.
                 *
                 *              string axis = srcFile.Name.Substring(7, 1);
                 *              if (axis == "x") {
                 *                      object speed = srcConfig.getArguments().get("Speed");
                 *                      string onNode = (string)srcConfig.getArguments().get("Node");
                 *                      // Big thing: Speed is probably a JAVA float, not a C# float
                 *                      if (speed is java.lang.Float jfloat) speed = jfloat.floatValue();
                 *
                 *                      Animation anim = HardcodedAnimations.CreateRotateX(onNode, (float)(speed ?? 1f));
                 *
                 *                      IEnumerable<Model3D> targetModels = attachToModels.Where(model => model.RawName == onNode);
                 *                      foreach (Model3D model in targetModels) {
                 *                              model.Animations.Add(anim);
                 *                      }
                 *
                 *              } else if (axis == "y") {
                 *                      object speed = srcConfig.getArguments().get("Speed");
                 *                      string onNode = (string)srcConfig.getArguments().get("Node");
                 *                      if (speed is java.lang.Float jfloat) speed = jfloat.floatValue();
                 *
                 *                      Animation anim = HardcodedAnimations.CreateRotateY(onNode,(float)(speed ?? 1f));
                 *                      IEnumerable<Model3D> targetModels = attachToModels.Where(model => model.RawName == onNode);
                 *                      foreach (Model3D model in targetModels) {
                 *                              model.Animations.Add(anim);
                 *                      }
                 *
                 *              } else if (axis == "z") {
                 *                      object speed = srcConfig.getArguments().get("Speed");
                 *                      string onNode = (string)srcConfig.getArguments().get("Node");
                 *                      if (speed is java.lang.Float jfloat) speed = jfloat.floatValue();
                 *
                 *                      Animation anim = HardcodedAnimations.CreateRotateZ(onNode, (float)(speed ?? 1f));
                 *                      IEnumerable<Model3D> targetModels = attachToModels.Where(model => model.RawName == onNode);
                 *                      foreach (Model3D model in targetModels) {
                 *                              model.Animations.Add(anim);
                 *                      }
                 *
                 *              } else {
                 *                      XanLogger.WriteLine(string.Format(ERR_PROC_NOT_YET_SUPPORTED, srcFile.Name), color: Color.DarkGoldenrod);
                 *              }
                 *      } else if (srcFile.Name == "gear_rotation.dat") {
                 *              // same as rotate y but it has an extra value
                 *              object speed = srcConfig.getArguments().get("Speed");
                 *              object sizeRatio = srcConfig.getArguments().get("Size Ratio");
                 *              string onNode = (string)srcConfig.getArguments().get("Node");
                 *              if (speed is java.lang.Float jfloat) speed = jfloat.floatValue();
                 *              if (sizeRatio is java.lang.Float jfloat2) sizeRatio = jfloat2.floatValue();
                 *
                 *              float overallSpeed = (float)(speed ?? 1f) * (float)(sizeRatio ?? 1f);
                 *
                 *              Animation anim = HardcodedAnimations.CreateRotateY(onNode, overallSpeed);
                 *              IEnumerable<Model3D> targetModels = attachToModels.Where(model => model.RawName == onNode);
                 *              foreach (Model3D model in targetModels) {
                 *                      model.Animations.Add(anim);
                 *              }
                 *
                 *      } else {
                 *              XanLogger.WriteLine(string.Format(ERR_PROC_NOT_YET_SUPPORTED, srcFile.Name), color: Color.DarkGoldenrod);
                 *      }
                 */

                /*
                 *      // Something's wrong with directs that I gotta fix.
                 *
                 * } else if (animationImplementation is AnimationConfig.Procedural proc) {
                 *      AnimationConfig.TargetTransform[] targets = proc.transforms;
                 *
                 *
                 *      Animation animation = new Animation(name);
                 *      float timeIncrement = proc.duration / targets.Length;
                 *      int currentFrame = 0;
                 *      foreach (AnimationConfig.TargetTransform targetTrs in targets) {
                 *              Transform3DExpression expr = targetTrs.expression;
                 *              Transform3D transform = (Transform3D)expr.createEvaluator(null).evaluate();
                 *
                 *              Animation.Keyframe keyframe = new Animation.Keyframe();
                 *              for (int targetIndex = 0; targetIndex < targetTrs.targets.Length; targetIndex++) {
                 *
                 *                      string target = targetTrs.targets[targetIndex];
                 *                      XanLogger.WriteLine(target, color: Color.Blue);
                 *                      keyframe.Keys.Add(new Animation.Key {
                 *                              Node = target,
                 *                              Transform = transform
                 *                      });
                 *                      keyframe.Time = currentFrame * timeIncrement;
                 *              }
                 *              animation.Keyframes.Add(keyframe);
                 *              currentFrame++;
                 *      }
                 *
                 *      foreach (Model3D model in attachToModels) {
                 *              model.Animations.Add(animation);
                 *      }
                 */
            }
            else
            {
                XanLogger.WriteLine(string.Format(ERR_IMPL_NOT_SUPPORTED, animationImplementation.GetType().Name), color: Color.DarkGoldenrod);
            }

            SKAnimatorToolsProxy.IncrementProgress();
        }