/// <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)); } }
/// <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!"); } } }
/// <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); }
/// <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); }
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(); }