// Initialize this animation controller from given object builder. // param forceReloadMwm: (Re)load MWM files even if they are in cache. // Returns true on success. public static bool InitFromDefinition(this VRage.Game.Components.MyAnimationControllerComponent thisController, MyAnimationControllerDefinition animControllerDefinition, bool forceReloadMwm = false) { bool result = true; thisController.Clear(); thisController.SourceId = animControllerDefinition.Id; foreach (var objBuilderLayer in animControllerDefinition.Layers) { var layer = thisController.Controller.CreateLayer(objBuilderLayer.Name); if (layer == null) { continue; } switch (objBuilderLayer.Mode) { case VRage.Game.ObjectBuilders.MyObjectBuilder_AnimationLayer.MyLayerMode.Add: layer.Mode = VRageRender.Animations.MyAnimationStateMachine.MyBlendingMode.Add; break; case VRage.Game.ObjectBuilders.MyObjectBuilder_AnimationLayer.MyLayerMode.Replace: layer.Mode = VRageRender.Animations.MyAnimationStateMachine.MyBlendingMode.Replace; break; default: Debug.Fail("Unknown layer mode."); layer.Mode = VRageRender.Animations.MyAnimationStateMachine.MyBlendingMode.Replace; break; } if (objBuilderLayer.BoneMask != null) { string[] boneMaskArray = objBuilderLayer.BoneMask.Split(m_boneListSeparators); foreach (string s in boneMaskArray) layer.BoneMaskStrIds.Add(MyStringId.GetOrCompute(s)); } else { layer.BoneMaskStrIds.Clear(); } layer.BoneMask = null; // this will build itself in animation controller when we know all character bones MyAnimationVirtualNodes virtualNodes = new MyAnimationVirtualNodes(); result = InitLayerNodes(layer, objBuilderLayer.StateMachine, animControllerDefinition, thisController.Controller, layer.Name + "/", virtualNodes, forceReloadMwm) && result; layer.SetState(layer.Name + "/" + objBuilderLayer.InitialSMNode); layer.SortTransitions(); } foreach (var footIkChain in animControllerDefinition.FootIkChains) thisController.InverseKinematics.RegisterFootBone(footIkChain.FootBone, footIkChain.ChainLength, footIkChain.AlignBoneWithTerrain); foreach (var ignoredBone in animControllerDefinition.IkIgnoredBones) thisController.InverseKinematics.RegisterIgnoredBone(ignoredBone); if (result) thisController.MarkAsValid(); return result; }
// Initialize this animation controller from given object builder. // Returns true on success. public static bool InitFromDefinition(this VRage.Game.Components.MyAnimationControllerComponent thisController, MyAnimationControllerDefinition animControllerDefinition) { bool result = true; thisController.Clear(); foreach (var objBuilderLayer in animControllerDefinition.Layers) { var layer = thisController.Controller.CreateLayer(objBuilderLayer.Name); if (layer == null) { continue; } switch (objBuilderLayer.Mode) { case VRage.Game.ObjectBuilders.MyObjectBuilder_AnimationLayer.MyLayerMode.Add: layer.Mode = VRage.Animations.MyAnimationStateMachine.MyBlendingMode.Add; break; case VRage.Game.ObjectBuilders.MyObjectBuilder_AnimationLayer.MyLayerMode.Replace: layer.Mode = VRage.Animations.MyAnimationStateMachine.MyBlendingMode.Replace; break; default: Debug.Fail("Unknown layer mode."); layer.Mode = VRage.Animations.MyAnimationStateMachine.MyBlendingMode.Replace; break; } if (objBuilderLayer.BoneMask != null) { string[] boneMaskArray = objBuilderLayer.BoneMask.Split(m_boneListSeparators); foreach (string s in boneMaskArray) layer.BoneMaskStrIds.Add(MyStringId.GetOrCompute(s)); } else { layer.BoneMaskStrIds.Clear(); } layer.BoneMask = null; // this will build itself in animation controller when we know all character bones result = InitLayerNodes(layer, objBuilderLayer.StateMachine, animControllerDefinition, thisController.Controller) && result; layer.SetState(objBuilderLayer.InitialSMNode); // todo: bone mask } return result; }
public override void AfterLoaded(ref Bundle definitions) { foreach (var def in definitions.Definitions) { MyAnimationControllerDefinition animationController = def.Value as MyAnimationControllerDefinition; if (animationController == null || animationController.StateMachines == null || def.Value.Context.IsBaseGame || def.Value.Context == null || def.Value.Context.ModPath == null) { continue; } foreach (var sm in animationController.StateMachines) { foreach (var node in sm.Nodes) { if (node.AnimationTree != null && node.AnimationTree.Child != null) { ResolveMwmPaths(def.Value.Context, node.AnimationTree.Child); } } } } }
// Initialize state machine of one layer. private static bool InitLayerNodes(MyAnimationStateMachine layer, string stateMachineName, MyAnimationControllerDefinition animControllerDefinition, MyAnimationController animationController, string currentNodeNamePrefix, MyAnimationVirtualNodes virtualNodes, bool forceReloadMwm) { var objBuilderStateMachine = animControllerDefinition.StateMachines.FirstOrDefault(x => x.Name == stateMachineName); if (objBuilderStateMachine == null) { Debug.Fail("Animation state machine " + stateMachineName + " was not found."); return false; } bool result = true; // 1st step: generate nodes if (objBuilderStateMachine.Nodes != null) foreach (var objBuilderNode in objBuilderStateMachine.Nodes) { string absoluteNodeName = currentNodeNamePrefix + objBuilderNode.Name; if (objBuilderNode.StateMachineName != null) { // embedded state machine, copy its nodes if (!InitLayerNodes(layer, objBuilderNode.StateMachineName, animControllerDefinition, animationController, absoluteNodeName + "/", virtualNodes, forceReloadMwm)) result = false; } else { var smNode = new VRageRender.Animations.MyAnimationStateMachineNode(absoluteNodeName); if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.PassThrough || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget) { smNode.PassThrough = true; } else { smNode.PassThrough = false; } if (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.Any || objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget) { virtualNodes.NodesAny.Add(absoluteNodeName, new MyAnimationVirtualNodeData() { AnyNodePrefix = currentNodeNamePrefix, ExceptTarget = (objBuilderNode.Type == MyObjectBuilder_AnimationSMNode.MySMNodeType.AnyExceptTarget) }); } layer.AddNode(smNode); if (objBuilderNode.AnimationTree != null) { var smNodeAnimTree = InitNodeAnimationTree(objBuilderNode.AnimationTree.Child, forceReloadMwm); smNode.RootAnimationNode = smNodeAnimTree; } else { smNode.RootAnimationNode = new MyAnimationTreeNodeDummy(); } } } // 2nd step: generate transitions if (objBuilderStateMachine.Transitions != null) foreach (var objBuilderTransition in objBuilderStateMachine.Transitions) { string absoluteNameNodeFrom = currentNodeNamePrefix + objBuilderTransition.From; string absoluteNameNodeTo = currentNodeNamePrefix + objBuilderTransition.To; MyAnimationVirtualNodeData virtualNodeData; if (virtualNodes.NodesAny.TryGetValue(absoluteNameNodeFrom, out virtualNodeData)) { // nodes of type "any": // "any" node is source: we create transitions directly from all nodes // "any" node is target: we will use "any" node as pass through foreach (var nodeFromCandidate in layer.AllNodes) { if (nodeFromCandidate.Key.StartsWith(virtualNodeData.AnyNodePrefix) // select nodes in the same SM && nodeFromCandidate.Key != absoluteNameNodeFrom) // disallow from "any" to the same "any" { // create transition if target is different from source or when we don't care about it if (!virtualNodeData.ExceptTarget || absoluteNameNodeTo != nodeFromCandidate.Key) CreateTransition(layer, animationController, nodeFromCandidate.Key, absoluteNameNodeTo, objBuilderTransition); } } } CreateTransition(layer, animationController, absoluteNameNodeFrom, absoluteNameNodeTo, objBuilderTransition); } return result; }
public override void OverrideBy(ref Bundle currentDefinitions, ref Bundle overrideBySet) { foreach (var def in overrideBySet.Definitions) { MyAnimationControllerDefinition modifyingAnimationController = def.Value as MyAnimationControllerDefinition; if (def.Value.Enabled && modifyingAnimationController != null) { bool justCopy = true; if (currentDefinitions.Definitions.ContainsKey(def.Key)) { MyAnimationControllerDefinition originalAnimationController = currentDefinitions.Definitions[def.Key] as MyAnimationControllerDefinition; if (originalAnimationController != null) { foreach (var sm in modifyingAnimationController.StateMachines) { bool found = false; foreach (var smOrig in originalAnimationController.StateMachines) { if (sm.Name == smOrig.Name) { smOrig.Nodes = sm.Nodes; smOrig.Transitions = sm.Transitions; found = true; break; } } if (!found) { originalAnimationController.StateMachines.Add(sm); } } foreach (var layer in modifyingAnimationController.Layers) { bool found = false; foreach (var layerOrig in originalAnimationController.Layers) { if (layer.Name == layerOrig.Name) { layerOrig.Name = layer.Name; layerOrig.BoneMask = layer.BoneMask; layerOrig.InitialSMNode = layer.InitialSMNode; layerOrig.StateMachine = layer.StateMachine; layerOrig.Mode = layer.Mode; found = true; } } if (!found) { originalAnimationController.Layers.Add(layer); } } // TODO: IK? justCopy = false; } } if (justCopy) { currentDefinitions.Definitions[def.Key] = def.Value; } } } }
// receiving messages private void LiveDebugging_ReceivedMessageHandler(MyExternalDebugStructures.CommonMsgHeader messageHeader, IntPtr messageData) { MyExternalDebugStructures.ACReloadInGameMsg msgReload; if (MyExternalDebugStructures.ReadMessageFromPtr(ref messageHeader, messageData, out msgReload)) { try { string acContentPath = msgReload.ACContentAddress; string acAddress = msgReload.ACAddress; string acName = msgReload.ACName; MyObjectBuilder_Definitions allDefinitions; // = null; // load animation controller definition from SBC file if (MyObjectBuilderSerializer.DeserializeXML(acAddress, out allDefinitions) && allDefinitions.Definitions != null && allDefinitions.Definitions.Length > 0) { var firstDef = allDefinitions.Definitions[0]; MyModContext context = new MyModContext(); context.Init("AnimationControllerDefinition", acAddress, acContentPath); MyAnimationControllerDefinition animationControllerDefinition = new MyAnimationControllerDefinition(); animationControllerDefinition.Init(firstDef, context); MyStringHash animSubtypeNameHash = MyStringHash.GetOrCompute(acName); // post process and update in def. manager MyAnimationControllerDefinition originalAnimationControllerDefinition = MyDefinitionManagerBase.Static.GetDefinition<MyAnimationControllerDefinition>( animSubtypeNameHash); var postprocessor = MyDefinitionManagerBase.GetPostProcessor(typeof(MyObjectBuilder_AnimationControllerDefinition)); if (postprocessor != null) { MyDefinitionPostprocessor.Bundle originalBundle = new MyDefinitionPostprocessor.Bundle { Context = MyModContext.BaseGame, Definitions = new Dictionary<MyStringHash, MyDefinitionBase> { {animSubtypeNameHash, originalAnimationControllerDefinition} }, Set = new MyDefinitionSet() }; originalBundle.Set.AddDefinition(originalAnimationControllerDefinition); MyDefinitionPostprocessor.Bundle overridingBundle = new MyDefinitionPostprocessor.Bundle { Context = context, Definitions = new Dictionary<MyStringHash, MyDefinitionBase> { {animSubtypeNameHash, animationControllerDefinition} }, Set = new MyDefinitionSet() }; overridingBundle.Set.AddDefinition(animationControllerDefinition); // postprocess -> override existing definition in memory postprocessor.AfterLoaded(ref overridingBundle); postprocessor.OverrideBy(ref originalBundle, ref overridingBundle); } // swap animation controller for each entity foreach (var component in m_skinnedEntityComponents) { if (component != null && component.SourceId.SubtypeName == acName) { component.Clear(); component.InitFromDefinition(originalAnimationControllerDefinition, forceReloadMwm: true); // reload from original def that was modified by postprocessor if (component.ReloadBonesNeeded != null) component.ReloadBonesNeeded(); } } } } catch (Exception e) { MyLog.Default.WriteLine(e); } } }
// Initialize state machine of one layer. private static bool InitLayerNodes(VRage.Animations.MyAnimationStateMachine layer, string stateMachineName, MyAnimationControllerDefinition animControllerDefinition, VRage.Animations.MyAnimationController animationController, string currentNodeNamePrefix = "") { var objBuilderStateMachine = animControllerDefinition.StateMachines.FirstOrDefault(x => x.Name == stateMachineName); if (objBuilderStateMachine == null) { Debug.Fail("Animation state machine " + stateMachineName + " was not found."); return false; } bool result = true; // 1st step: generate nodes if (objBuilderStateMachine.Nodes != null) foreach (var objBuilderNode in objBuilderStateMachine.Nodes) { string absoluteNodeName = currentNodeNamePrefix + objBuilderNode.Name; if (objBuilderNode.StateMachineName != null) { // embedded state machine, copy its nodes if (!InitLayerNodes(layer, objBuilderNode.StateMachineName, animControllerDefinition, animationController, absoluteNodeName + "/")) result = false; } else { if (objBuilderNode.AnimationTree == null) { // no animation tree, just skip continue; } var smNode = new VRage.Animations.MyAnimationStateMachineNode(absoluteNodeName); layer.AddNode(smNode); var smNodeAnimTree = InitNodeAnimationTree(objBuilderNode.AnimationTree.Child); smNode.RootAnimationNode = smNodeAnimTree; } } // 2nd step: generate transitions if (objBuilderStateMachine.Transitions != null) foreach (var objBuilderTransition in objBuilderStateMachine.Transitions) { int conditionConjunctionIndex = 0; do { // generate transition for each condition conjunction var transition = layer.AddTransition(objBuilderTransition.From, objBuilderTransition.To, new VRage.Animations.MyAnimationStateMachineTransition()) as VRage.Animations.MyAnimationStateMachineTransition; // if ok, fill in conditions if (transition != null) { transition.Name = MyStringId.GetOrCompute(objBuilderTransition.Name); transition.TransitionTimeInSec = objBuilderTransition.TimeInSec; transition.Sync = objBuilderTransition.Sync; if (objBuilderTransition.Conditions != null && objBuilderTransition.Conditions[conditionConjunctionIndex] != null) { var conjunctionOfConditions = objBuilderTransition.Conditions[conditionConjunctionIndex].Conditions; foreach (var objBuilderCondition in conjunctionOfConditions) { var condition = ParseOneCondition(animationController, objBuilderCondition); if (condition != null) transition.Conditions.Add(condition); } } } conditionConjunctionIndex++; } while (objBuilderTransition.Conditions != null && conditionConjunctionIndex < objBuilderTransition.Conditions.Length); } return result; }