Example #1
0
        /// <inheritdoc/>
        protected override void SetupStateMachine()
        {
            base.SetupStateMachine();
            linkStateMachine.onAfterTransition += (start, end) => HostedDebugLog.Fine(
                this, "Source state changed at {0}: {1} => {2}", attachNodeName, start, end);
            linkStateMachine.SetTransitionConstraint(
                LinkState.Available,
                new[] { LinkState.Linking, LinkState.RejectingLinks, LinkState.NodeIsBlocked });
            linkStateMachine.SetTransitionConstraint(
                LinkState.NodeIsBlocked,
                new[] { LinkState.Available });
            linkStateMachine.SetTransitionConstraint(
                LinkState.Linking,
                new[] { LinkState.Available, LinkState.Linked });
            linkStateMachine.SetTransitionConstraint(
                LinkState.Linked,
                new[] { LinkState.Available });
            linkStateMachine.SetTransitionConstraint(
                LinkState.Locked,
                new[] { LinkState.Available });
            linkStateMachine.SetTransitionConstraint(
                LinkState.RejectingLinks,
                new[] { LinkState.Available, LinkState.Locked });

            linkStateMachine.AddStateHandlers(
                LinkState.Available,
                enterHandler: x => KASAPI.KasEvents.OnStartLinking.Add(OnStartLinkingKASEvent),
                leaveHandler: x => KASAPI.KasEvents.OnStartLinking.Remove(OnStartLinkingKASEvent));
            linkStateMachine.AddStateHandlers(
                LinkState.RejectingLinks,
                enterHandler: x => KASAPI.KasEvents.OnStopLinking.Add(OnStopLinkingKASEvent),
                leaveHandler: x => KASAPI.KasEvents.OnStopLinking.Remove(OnStopLinkingKASEvent));
            linkStateMachine.AddStateHandlers(
                LinkState.Linked,
                enterHandler: x => {
                GameEvents.onVesselWillDestroy.Add(OnVesselWillDestroyGameEvent);
                var module = linkTarget as PartModule;
                PartModuleUtils.InjectEvent(this, ToggleVesselsDockModeEvent, module);
            },
                leaveHandler: x => {
                GameEvents.onVesselWillDestroy.Remove(OnVesselWillDestroyGameEvent);
                var module = linkTarget as PartModule;
                PartModuleUtils.WithdrawEvent(this, ToggleVesselsDockModeEvent, module);
            });
            linkStateMachine.AddStateHandlers(
                LinkState.Linking,
                enterHandler: x => KASAPI.KasEvents.OnStartLinking.Fire(this),
                leaveHandler: x => KASAPI.KasEvents.OnStopLinking.Fire(this));
        }
Example #2
0
 /// <inheritdoc/>
 protected override void SetupStateMachine()
 {
     base.SetupStateMachine();
     linkStateMachine.onAfterTransition += (start, end) => UpdateContextMenu();
     linkStateMachine.AddStateHandlers(
         LinkState.Linking,
         enterHandler: x => {
         InputLockManager.SetControlLock(
             ControlTypes.All & ~ControlTypes.CAMERACONTROLS, TotalControlLock);
         canAutoSaveState = HighLogic.CurrentGame.Parameters.Flight.CanAutoSave;
         HighLogic.CurrentGame.Parameters.Flight.CanAutoSave = false;
         linkRenderer.shaderNameOverride = InteractiveShaderName;
         linkRenderer.colorOverride      = BadLinkColor;
         linkRenderer.isPhysicalCollider = false;
     },
         leaveHandler: x => {
         linkRenderer.StopRenderer(); // This resets the pipe state.
         linkRenderer.shaderNameOverride = null;
         linkRenderer.colorOverride      = null;
         linkRenderer.isPhysicalCollider = true;
         ScreenMessages.RemoveMessage(statusScreenMessage);
         InputLockManager.RemoveControlLock(TotalControlLock);
         HighLogic.CurrentGame.Parameters.Flight.CanAutoSave = canAutoSaveState;
         lastHoveredPart = null;
     });
     linkStateMachine.AddStateHandlers(
         LinkState.Linked,
         enterHandler: x => {
         if (linkActor == LinkActorType.Player || linkActor == LinkActorType.Physics)
         {
             UISoundPlayer.instance.Play(linkJoint.coupleOnLinkMode ? sndPathDock : sndPathPlug);
         }
         var module = linkTarget as PartModule;
         PartModuleUtils.InjectEvent(this, BreakLinkContextMenuAction, module);
     },
         leaveHandler: x => {
         if (linkActor == LinkActorType.Player)
         {
             UISoundPlayer.instance.Play(linkJoint.coupleOnLinkMode ? sndPathUndock : sndPathUnplug);
         }
         else if (linkActor == LinkActorType.Physics)
         {
             UISoundPlayer.instance.Play(sndPathBroke);
         }
         var module = linkTarget as PartModule;
         PartModuleUtils.WithdrawEvent(this, BreakLinkContextMenuAction, module);
     });
 }
Example #3
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);
        }
Example #4
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);
        }