Пример #1
0
 /// <inheritdoc/>
 public override void AlignTo(Transform target)
 {
     if (target == null)
     {
         AlignTransforms.SnapAlign(model, pipeAttach, parkAt);
         model.gameObject.SetActive(true);
     }
     else
     {
         base.AlignTo(target);
     }
 }
Пример #2
0
 /// <summary>Aligns node against the target.</summary>
 /// <param name="target">
 /// The target object. Can be <c>null</c> in which case the node model will be hidden.
 /// </param>
 /// <include file="KSPDevUtilsAPI_HelpIndex.xml" path="//item[@name='M:KSPDev.AlignTransforms.SnapAlign']/*"/>
 public virtual void AlignTo(Transform target)
 {
     if (target != null)
     {
         AlignTransforms.SnapAlign(model, partAttach, target);
         model.gameObject.SetActive(true);
     }
     else
     {
         model.gameObject.SetActive(false);
     }
 }
Пример #3
0
 /// <inheritdoc/>
 protected override void RestoreOtherPeer()
 {
     base.RestoreOtherPeer();
     if (linkTarget != null)
     {
         // Do it before physics kicked-in to have the cable distance calculated correctly.
         AlignTransforms.SnapAlign(
             connectorModelObj, connectorPartAnchor, linkTarget.nodeTransform);
         // Only do it for the visual improvements of the vessel loading. The connector state machine
         // will handle it right, but it only happens when the physics is started.
         linkRenderer.StartRenderer(partCableAnchor, connectorCableAnchor);
     }
 }
Пример #4
0
 /// <summary>Updates the node's state to the target transform.</summary>
 /// <param name="target">
 /// The transfrom to align the node to. If <c>null</c>, then the model will be "parked".
 /// </param>
 /// <seealso cref="parkAttach"/>
 public void AlignToTransform(Transform target)
 {
     if (target != null)
     {
         rootModel.gameObject.SetActive(true);
         AlignTransforms.SnapAlign(rootModel, partAttach, target);
         rootModel.parent = target;
     }
     else
     {
         rootModel.parent = parkRootObject;
         if (parkAttach == null)
         {
             rootModel.gameObject.SetActive(false);
         }
         else
         {
             rootModel.gameObject.SetActive(true);
             AlignTransforms.SnapAlign(rootModel, pipeAttach, parkAttach);
         }
     }
 }
Пример #5
0
        /// <inheritdoc/>
        protected override void SetupStateMachine()
        {
            base.SetupStateMachine();
            linkStateMachine.onAfterTransition += (start, end) => UpdateContextMenu();
            linkStateMachine.AddStateHandlers(
                LinkState.Linked,
                enterHandler: oldState => {
                var module = linkTarget as PartModule;
                PartModuleUtils.InjectEvent(this, DetachConnectorEvent, module);
                PartModuleUtils.AddEvent(module, _grabConnectorEventInject);
            },
                leaveHandler: newState => {
                var module = linkTarget as PartModule;
                PartModuleUtils.WithdrawEvent(this, DetachConnectorEvent, module);
                PartModuleUtils.DropEvent(module, _grabConnectorEventInject);
            });
            linkStateMachine.AddStateHandlers(
                LinkState.NodeIsBlocked,
                enterHandler: oldState => {
                if (decoupleIncompatibleTargets &&
                    coupleNode != null && coupleNode.attachedPart != null)
                {
                    HostedDebugLog.Warning(this, "Decouple incompatible part from the node: {0}",
                                           coupleNode.FindOpposingNode().attachedPart);
                    UISoundPlayer.instance.Play(KASAPI.CommonConfig.sndPathBipWrong);
                    ShowStatusMessage(
                        CannotLinkToPreAttached.Format(coupleNode.attachedPart), isError: true);
                    KASAPI.LinkUtils.DecoupleParts(part, coupleNode.attachedPart);
                }
            },
                callOnShutdown: false);

            // The default state is "Locked". All the enter state handlers rely on it, and all the exit
            // state handlers reset the state back to the default.
            connectorStateMachine = new SimpleStateMachine <ConnectorState>();
            connectorStateMachine.onAfterTransition += (start, end) => {
                if (end != null) // Do nothing on state machine shutdown.
                {
                    persistedIsConnectorLocked = isConnectorLocked;
                    if (end == ConnectorState.Locked)
                    {
                        KASAPI.AttachNodesUtils.AddNode(part, coupleNode);
                    }
                    else if (coupleNode.attachedPart == null)
                    {
                        KASAPI.AttachNodesUtils.DropNode(part, coupleNode);
                    }
                    UpdateContextMenu();
                }
                HostedDebugLog.Info(this, "Connector state changed: {0} => {1}", start, end);
            };
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Docked,
                new[] {
                ConnectorState.Plugged,
                ConnectorState.Locked, // External detach.
            });
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Locked,
                new[] {
                ConnectorState.Deployed,
                ConnectorState.Plugged,
                ConnectorState.Docked, // External attach.
            });
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Deployed,
                new[] {
                ConnectorState.Locked,
                ConnectorState.Plugged,
            });
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Plugged,
                new[] {
                ConnectorState.Deployed,
                ConnectorState.Docked,
            });
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Locked,
                enterHandler: oldState => {
                SaveConnectorModelPosAndRot();
                if (oldState.HasValue) // Skip when restoring state.
                {
                    UISoundPlayer.instance.Play(sndPathLockConnector);
                }
            },
                leaveHandler: newState =>
                SaveConnectorModelPosAndRot(saveNonPhysical: newState == ConnectorState.Deployed),
                callOnShutdown: false);
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Docked,
                enterHandler: oldState => {
                SaveConnectorModelPosAndRot();
                cableJoint.SetLockedOnCouple(true);

                // Align the docking part to the nodes if it's a separate vessel.
                if (oldState.HasValue && linkTarget.part.vessel != vessel)
                {
                    AlignTransforms.SnapAlignNodes(linkTarget.coupleNode, coupleNode);
                    linkJoint.SetCoupleOnLinkMode(true);
                    UISoundPlayer.instance.Play(sndPathDockConnector);
                }
            },
                leaveHandler: newState => {
                cableJoint.SetLockedOnCouple(false);
                SaveConnectorModelPosAndRot(saveNonPhysical: newState == ConnectorState.Deployed);
                linkJoint.SetCoupleOnLinkMode(false);
            },
                callOnShutdown: false);
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Plugged,
                enterHandler: oldState => SaveConnectorModelPosAndRot(),
                leaveHandler: newState =>
                SaveConnectorModelPosAndRot(saveNonPhysical: newState == ConnectorState.Deployed),
                callOnShutdown: false);
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Deployed,
                enterHandler: oldState => StartPhysicsOnConnector(),
                leaveHandler: newState => StopPhysicsOnConnector(),
                callOnShutdown: false);
        }
Пример #6
0
        /// <summary>Intializes the connector model object and its anchors.</summary>
        /// <remarks>
        /// <para>
        /// If the connector model is not found then a stub object will be created. There will be no visual
        /// representation but the overall functionality of the winch should keep working.
        /// </para>
        /// <para>
        /// If the connector doesn't have the anchors then the missed ones will be created basing on the
        /// provided position/rotation. If the config file doesn't provide anything then the anchors will
        /// have a zero position and a random rotation.
        /// </para>
        /// </remarks>
        void LoadOrCreateConnectorModel()
        {
            var          ConnectorModelName      = "ConnectorModel" + part.Modules.IndexOf(this);
            var          ConnectorParkAnchorName = "ConnectorParkAnchor" + part.Modules.IndexOf(this);
            const string CableAnchorName         = "CableAnchor";
            const string PartAnchorName          = "PartAnchor";

            if (!PartLoader.Instance.IsReady())
            {
                // Make the missing models and set the proper hierarchy.
                connectorModelObj    = Hierarchy.FindPartModelByPath(part, connectorModel);
                connectorCableAnchor = connectorCableAttachAt != ""
          ? Hierarchy.FindPartModelByPath(part, connectorCableAttachAt) : null;
                connectorPartAnchor = connectorPartAttachAt != ""
          ? Hierarchy.FindPartModelByPath(part, connectorPartAttachAt) : null;

                if (connectorModelObj == null)
                {
                    HostedDebugLog.Error(this, "Cannot find a connector model: {0}", connectorModel);
                    // Fallback to not have the whole code to crash.
                    connectorModelObj = new GameObject().transform;
                }
                connectorModelObj.name   = ConnectorModelName;
                connectorModelObj.parent = nodeTransform;


                if (connectorCableAnchor == null)
                {
                    if (connectorCableAttachAt != "")
                    {
                        HostedDebugLog.Error(
                            this, "Cannot find cable anchor transform: {0}", connectorCableAttachAt);
                    }
                    connectorCableAnchor = new GameObject().transform;
                    var posAndRot = PosAndRot.FromString(connectorCableAttachAtPosAndRot);
                    Hierarchy.MoveToParent(connectorCableAnchor, connectorModelObj,
                                           newPosition: posAndRot.pos, newRotation: posAndRot.rot);
                }
                connectorCableAnchor.name   = CableAnchorName;
                connectorCableAnchor.parent = connectorModelObj;

                if (connectorPartAnchor == null)
                {
                    if (connectorPartAttachAt != "")
                    {
                        HostedDebugLog.Error(
                            this, "Cannot find part anchor transform: {0}", connectorPartAttachAt);
                    }
                    connectorPartAnchor = new GameObject().transform;
                    var posAndRot = PosAndRot.FromString(connectorPartAttachAtPosAndRot);
                    Hierarchy.MoveToParent(connectorPartAnchor, connectorModelObj,
                                           newPosition: posAndRot.pos, newRotation: posAndRot.rot);
                }
                connectorPartAnchor.name   = PartAnchorName;
                connectorPartAnchor.parent = connectorModelObj;

                partCableAnchor = new GameObject(ConnectorParkAnchorName).transform;
                Hierarchy.MoveToParent(
                    partCableAnchor, nodeTransform, newPosition: connectorParkPositionOffset);
            }
            else
            {
                connectorModelObj    = nodeTransform.Find(ConnectorModelName);
                connectorCableAnchor = connectorModelObj.Find(CableAnchorName);
                connectorPartAnchor  = connectorModelObj.Find(PartAnchorName);
                partCableAnchor      = nodeTransform.Find(ConnectorParkAnchorName);
            }
            AlignTransforms.SnapAlign(connectorModelObj, connectorCableAnchor, partCableAnchor);
        }
Пример #7
0
        /// <inheritdoc/>
        protected override void SetupStateMachine()
        {
            base.SetupStateMachine();
            linkStateMachine.onAfterTransition += (start, end) => UpdateContextMenu();
            linkStateMachine.AddStateHandlers(
                LinkState.Linked,
                enterHandler: oldState => {
                var module = linkTarget as PartModule;
                PartModuleUtils.InjectEvent(this, DetachConnectorEvent, module);
                PartModuleUtils.AddEvent(module, GrabConnectorEventInject);
            },
                leaveHandler: newState => {
                var module = linkTarget as PartModule;
                PartModuleUtils.WithdrawEvent(this, DetachConnectorEvent, module);
                PartModuleUtils.DropEvent(module, GrabConnectorEventInject);
            });

            // The default state is "Locked". All the enter state handlers rely on it, and all the exit
            // state handlers reset the state back to the default.
            connectorStateMachine = new SimpleStateMachine <ConnectorState>(strict: true);
            connectorStateMachine.onAfterTransition += (start, end) => {
                if (end != null) // Do nothing on state machine shutdown.
                {
                    persistedIsConnectorLocked = isConnectorLocked;
                    if (end == ConnectorState.Locked)
                    {
                        KASAPI.AttachNodesUtils.AddNode(part, coupleNode);
                    }
                    else if (coupleNode.attachedPart == null)
                    {
                        KASAPI.AttachNodesUtils.DropNode(part, coupleNode);
                    }
                    UpdateContextMenu();
                }
                HostedDebugLog.Info(this, "Connector state changed: {0} => {1}", start, end);
            };
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Docked,
                new[] {
                ConnectorState.Plugged,
                ConnectorState.Locked, // External detach.
            });
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Locked,
                new[] {
                ConnectorState.Deployed,
                ConnectorState.Plugged,
                ConnectorState.Docked, // External attach.
            });
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Deployed,
                new[] {
                ConnectorState.Locked,
                ConnectorState.Plugged,
            });
            connectorStateMachine.SetTransitionConstraint(
                ConnectorState.Plugged,
                new[] {
                ConnectorState.Deployed,
                ConnectorState.Docked,
            });
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Locked,
                enterHandler: oldState => {
                connectorModelObj.parent = nodeTransform;
                PartModel.UpdateHighlighters(part);
                connectorModelObj.GetComponentsInChildren <Renderer>().ToList()
                .ForEach(r => r.SetPropertyBlock(part.mpb));
                AlignTransforms.SnapAlign(connectorModelObj, connectorCableAnchor, partCableAnchor);
                SetCableLength(0);
                if (oldState.HasValue) // Skip when restoring state.
                {
                    UISoundPlayer.instance.Play(sndPathLockConnector);
                }
            },
                callOnShutdown: false);
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Docked,
                enterHandler: oldState => {
                connectorModelObj.parent = nodeTransform;
                AlignTransforms.SnapAlign(connectorModelObj, connectorCableAnchor, partCableAnchor);
                SetCableLength(0);

                // Align the docking part to the nodes if it's a separate vessel.
                if (oldState.HasValue && linkTarget.part.vessel != vessel)
                {
                    AlignTransforms.SnapAlignNodes(linkTarget.coupleNode, coupleNode);
                    linkJoint.SetCoupleOnLinkMode(true);
                    UISoundPlayer.instance.Play(sndPathDockConnector);
                }
            },
                leaveHandler: newState => linkJoint.SetCoupleOnLinkMode(false),
                callOnShutdown: false);
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Deployed,
                enterHandler: oldState => {
                TurnConnectorPhysics(true);
                connectorModelObj.parent = connectorModelObj;
                PartModel.UpdateHighlighters(part);
                linkRenderer.StartRenderer(partCableAnchor, connectorCableAnchor);
            },
                leaveHandler: newState => {
                TurnConnectorPhysics(false);
                linkRenderer.StopRenderer();
            },
                callOnShutdown: false);
            connectorStateMachine.AddStateHandlers(
                ConnectorState.Plugged,
                enterHandler: oldState => {
                // Destroy the previous highlighter if any, since it would interfere with the new owner.
                DestroyImmediate(connectorModelObj.GetComponent <Highlighter>());
                connectorModelObj.parent = linkTarget.nodeTransform;
                PartModel.UpdateHighlighters(part);
                PartModel.UpdateHighlighters(linkTarget.part);
                connectorModelObj.GetComponentsInChildren <Renderer>().ToList()
                .ForEach(r => r.SetPropertyBlock(linkTarget.part.mpb));
                AlignTransforms.SnapAlign(
                    connectorModelObj, connectorPartAnchor, linkTarget.nodeTransform);
                linkRenderer.StartRenderer(partCableAnchor, connectorCableAnchor);
            },
                leaveHandler: newState => {
                var oldParent = connectorModelObj.GetComponentInParent <Part>();
                var oldHigh   = oldParent.HighlightActive;
                if (oldHigh)
                {
                    // Disable the part highlight to restore the connector's renderer materials.
                    oldParent.SetHighlight(false, false);
                }
                connectorModelObj.parent = nodeTransform; // Back to the model.
                PartModel.UpdateHighlighters(part);
                PartModel.UpdateHighlighters(oldParent);
                if (oldHigh)
                {
                    oldParent.SetHighlight(true, false);
                }
                linkRenderer.StopRenderer();
            },
                callOnShutdown: false);
        }