Exemple #1
0
        /// <summary>Removes items form the stack.</summary>
        /// <remarks>
        /// This method does its best. If it cannot remove the desired number of items, then it removes as
        /// many is there are avaiable in the slot.
        /// </remarks>
        /// <param name="qty">The number of items to remove.</param>
        /// <returns>The actual number of items removed.</returns>
        public int StackRemove(int qty)
        {
            if (qty <= 0)
            {
                return(0);
            }
            int removeQty;

            if (quantity - qty < 0)
            {
                removeQty = quantity;
                HostedDebugLog.Fine(inventory, "Exhausted item quantity: name={0}, removeExactly={1}",
                                    availablePart.name, removeQty);
            }
            else
            {
                removeQty = qty;
            }
            quantity -= removeQty;
            inventory.RefreshContents();
            if (quantity == 0)
            {
                Delete();
            }
            return(removeQty);
        }
Exemple #2
0
        /// <summary>
        /// Creates a distance joint between the source and an arbitrary physical object.
        /// </summary>
        /// <remarks>It sets the maximum cable length to the persisted value. Even if it's zero!</remarks>
        /// <param name="source">The source of the link.</param>
        /// <param name="tgtRb">The rigidbody of the physical object.</param>
        /// <param name="tgtAnchor">The anchor at the physical object in world coordinates.</param>
        void CreateDistanceJoint(ILinkSource source, Rigidbody tgtRb, Vector3 tgtAnchor)
        {
            var distanceLimit = originalLength
                                ?? Vector3.Distance(GetSourcePhysicalAnchor(source), tgtAnchor);
            var joint = source.part.gameObject.AddComponent <ConfigurableJoint>();

            KASAPI.JointUtils.ResetJoint(joint);
            if (distanceLimit < 0.001f)
            {
                // Reset the distance if it's below the KSP distance resolution.
                HostedDebugLog.Fine(this, "Reset joint to zero: distance={0}", distanceLimit);
                distanceLimit = 0;
            }

            KASAPI.JointUtils.SetupDistanceJoint(
                joint,
                springForce: cableSpringForce, springDamper: cableSpringDamper,
                maxDistance: distanceLimit);
            joint.autoConfigureConnectedAnchor = false;
            joint.anchor = source.part.Rigidbody.transform.InverseTransformPoint(
                GetSourcePhysicalAnchor(source));
            joint.connectedBody   = tgtRb;
            joint.connectedAnchor = tgtRb.transform.InverseTransformPoint(tgtAnchor);
            SetBreakForces(joint);
            SetCustomJoints(new[] { joint });
            cableJoint = joint;
        }
Exemple #3
0
 /// <summary>Couples the source and the target parts merging them into a single vessel.</summary>
 /// <remarks>
 /// It's OK to call this method if the parts are already coupled. It's a normal way to have the
 /// attach nodes created on the vessel load.
 /// </remarks>
 /// <seealso cref="DecoupleParts"/>
 void CoupleParts()
 {
     if (isCoupled)
     {
         // If the parts are already coupled, then refresh the state and update the joints.
         if (persistedSrcVesselInfo == null)
         {
             HostedDebugLog.Fine(this, "Update link source vessel info to: {0}", vessel);
             persistedSrcVesselInfo = GetVesselInfo(vessel);
         }
         if (persistedTgtVesselInfo == null)
         {
             HostedDebugLog.Fine(this, "Update link target vessel info to: {0}", vessel);
             persistedTgtVesselInfo = GetVesselInfo(vessel);
         }
         SetupPhysXJoints();
         return;
     }
     if (linkSource.part.vessel == linkTarget.part.vessel)
     {
         // If the parts belong to the same vessel, but are not coupled, then update the joints.
         HostedDebugLog.Fine(this, "Already coupled, skipping: {0} <=> {1}", linkSource, linkTarget);
         SetupPhysXJoints();
         return;
     }
     // Remember the vessel info to restore it on the decoupling. And do the couple!
     persistedSrcVesselInfo = GetVesselInfo(linkSource.part.vessel);
     persistedTgtVesselInfo = GetVesselInfo(linkTarget.part.vessel);
     KASAPI.LinkUtils.CoupleParts(
         linkSource.coupleNode, linkTarget.coupleNode, toDominantVessel: true);
     SetupPhysXJoints();
 }
Exemple #4
0
        /// <inheritdoc/>
        protected override void CheckCoupleNode()
        {
            base.CheckCoupleNode();
            if (linkState == LinkState.Available && parsedAttachNode.attachedPart != null)
            {
                var target = parsedAttachNode.attachedPart.Modules
                             .OfType <ILinkTarget>()
                             .FirstOrDefault(t => t.coupleNode != null && t.coupleNode.attachedPart == part &&
                                             CheckCanLinkTo(t, reportToLog: false));
                if (target != null)
                {
                    HostedDebugLog.Fine(this, "Linking with the preattached part: {0}", target);
                    LinkToTarget(LinkActorType.API, target);
                }
                if (!isLinked)
                {
                    HostedDebugLog.Warning(this, "Cannot link to the preattached part via {0}",
                                           KASAPI.AttachNodesUtils.NodeId(parsedAttachNode.FindOpposingNode()));
                    isNodeBlocked = true;
                }
            }
            else if (linkState == LinkState.NodeIsBlocked && parsedAttachNode.attachedPart == null)
            {
                isNodeBlocked = false;
            }

            // Restore the link state if not yet done.
            if (isLinked && !linkJoint.isLinked)
            {
                linkJoint.CreateJoint(this, linkTarget);
            }

            UpdateContextMenu(); // To update the dock/undock menu.
        }
Exemple #5
0
        /// <inheritdoc/>
        public override void OnLoad(ConfigNode node)
        {
            ConfigAccessor.ReadPartConfig(this, cfgNode: node);
            ConfigAccessor.ReadFieldsFromNode(node, GetType(), this, StdPersistentGroups.PartPersistant);
            base.OnLoad(node);

            parsedAttachNode = part.FindAttachNode(attachNodeName);
            isAutoAttachNode = parsedAttachNode == null;
            if (isAutoAttachNode)
            {
                parsedAttachNode = KASAPI.AttachNodesUtils.ParseNodeFromString(
                    part, attachNodeDef, attachNodeName);
                if (parsedAttachNode != null)
                {
                    HostedDebugLog.Fine(
                        this, "Created auto node: {0}", KASAPI.AttachNodesUtils.NodeId(parsedAttachNode));
                    if (coupleNode != null && (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor))
                    {
                        // Only pre-add the node in the scenes that assume restoring a vessel state.
                        // We'll drop it in the OnStartFinished if not used.
                        KASAPI.AttachNodesUtils.AddNode(part, coupleNode);
                    }
                }
                else
                {
                    HostedDebugLog.Error(this, "Cannot create auto node from: {0}", attachNodeDef);
                }
            }
            if (parsedAttachNode != null)
            {
                // HACK: Handle a KIS issue which causes the nodes to be owned by the prefab part.
                parsedAttachNode.owner = part;
                nodeTransform          = KASAPI.AttachNodesUtils.GetTransformForNode(part, parsedAttachNode);
            }
        }
Exemple #6
0
 /// <inheritdoc/>
 public virtual void OnPartUnpack()
 {
     // The check may want to establish a link, but this will only succeed if the physics has
     // started.
     HostedDebugLog.Fine(this, "Schedule coupling check from UNPACK...");
     AsyncCall.CallOnEndOfFrame(this, CheckCoupleNode);
 }
Exemple #7
0
        /// <inheritdoc/>
        protected override void SetupStateMachine()
        {
            base.SetupStateMachine();
            linkStateMachine.onAfterTransition += (start, end) => HostedDebugLog.Fine(
                this, "Target state changed: node={0}, state {1} => {2}", attachNodeName, start, end);
            linkStateMachine.SetTransitionConstraint(
                LinkState.Available,
                new[] { LinkState.AcceptingLinks, LinkState.NodeIsBlocked, LinkState.Locked });
            linkStateMachine.SetTransitionConstraint(
                LinkState.NodeIsBlocked,
                new[] { LinkState.Available });
            linkStateMachine.SetTransitionConstraint(
                LinkState.AcceptingLinks,
                new[] { LinkState.Available, LinkState.Linked });
            linkStateMachine.SetTransitionConstraint(
                LinkState.Linked,
                new[] { LinkState.Available });
            linkStateMachine.SetTransitionConstraint(
                LinkState.Locked,
                new[] { LinkState.Available });

            linkStateMachine.AddStateHandlers(
                LinkState.Available,
                enterHandler: x => KASAPI.KasEvents.OnStartLinking.Add(OnStartLinkingKASEvent),
                leaveHandler: x => KASAPI.KasEvents.OnStartLinking.Remove(OnStartLinkingKASEvent));
            linkStateMachine.AddStateHandlers(
                LinkState.AcceptingLinks,
                enterHandler: x => KASAPI.KasEvents.OnStopLinking.Add(OnStopLinkingKASEvent),
                leaveHandler: x => KASAPI.KasEvents.OnStopLinking.Remove(OnStopLinkingKASEvent));
            linkStateMachine.AddStateHandlers(
                LinkState.AcceptingLinks,
                enterHandler: x => SetEligiblePartHighlighting(true),
                leaveHandler: x => SetEligiblePartHighlighting(false),
                callOnShutdown: false);
        }
Exemple #8
0
 /// <inheritdoc/>
 public virtual bool SetCoupleOnLinkMode(bool isCoupleOnLink)
 {
     if (!isLinked)
     {
         coupleOnLinkMode = isCoupleOnLink;
         HostedDebugLog.Fine(
             this, "Coupling mode updated in a non-linked module: {0}", isCoupleOnLink);
         return(true);
     }
     if (isCoupleOnLink && (linkSource.coupleNode == null || linkTarget.coupleNode == null))
     {
         HostedDebugLog.Error(this, "Cannot couple due to source or target doesn't support it");
         coupleOnLinkMode = false;
         return(false);
     }
     if (isCoupleOnLink && linkSource.part.vessel != linkTarget.part.vessel)
     {
         // Couple the parts, and drop the other link(s).
         DetachParts();
         coupleOnLinkMode = isCoupleOnLink;
         CoupleParts();
     }
     else if (!isCoupleOnLink && isCoupled)
     {
         // Decouple the parts, and make the non-coupling link(s).
         DecoupleParts();
         coupleOnLinkMode = isCoupleOnLink;
         AttachParts();
     }
     else
     {
         coupleOnLinkMode = isCoupleOnLink; // Simply change the mode.
     }
     return(true);
 }
Exemple #9
0
 /// <summary>
 /// Goes thru the parts on the source and target vessels, and tries to restore the coupling
 /// between the parts.
 /// </summary>
 /// <remarks>
 /// Any linking module on the source or the target vessel, which is linked and in the docking
 /// mode, will be attempted to use to restore the vessels coupling. This work will be done at the
 /// end of frame to let the other logic to cleanup.
 /// </remarks>
 /// <param name="tgtPart">
 /// The former target part that was holding the coupling with this part.
 /// </param>
 void DelegateCouplingRole(Part tgtPart)
 {
     AsyncCall.CallOnEndOfFrame(this, () => {
         var candidates = new List <ILinkJoint>()
                          .Concat(vessel.parts
                                  .SelectMany(p => p.Modules.OfType <ILinkJoint>())
                                  .Where(j => !ReferenceEquals(j, this) && j.coupleOnLinkMode && j.isLinked &&
                                         j.linkTarget.part.vessel == tgtPart.vessel))
                          .Concat(tgtPart.vessel.parts
                                  .SelectMany(p => p.Modules.OfType <ILinkJoint>())
                                  .Where(j => j.coupleOnLinkMode && j.isLinked && j.linkTarget.part.vessel == vessel));
         foreach (var joint in candidates)
         {
             HostedDebugLog.Fine(this, "Trying to couple via: {0}", joint);
             if (joint.SetCoupleOnLinkMode(true))
             {
                 HostedDebugLog.Info(this, "The coupling role is delegated to: {0}", joint);
                 return;
             }
         }
         if (candidates.Any())
         {
             HostedDebugLog.Warning(this, "None of the found candidates took the coupling role");
         }
     });
 }
Exemple #10
0
 /// <inheritdoc/>
 public virtual void DecoupleAction(string nodeName, bool weDecouple)
 {
     if (nodeName == attachNodeName)
     {
         HostedDebugLog.Fine(this, "Schedule coupling check from DECOUPLE action...");
         AsyncCall.CallOnEndOfFrame(this, CheckCoupleNode);
     }
 }
Exemple #11
0
            /// <summary>Adds a custom part module and loads its fields from the config.</summary>
            T AddModule <T>(Part prefab, ConfigNode node) where T : PartModule
            {
                var module = prefab.AddModule(typeof(T).Name, forceAwake: true) as T;

                HostedDebugLog.Fine(module, "Add module and load config: type={0}", typeof(T));
                module.Fields.Load(node);
                return(module);
            }
Exemple #12
0
 /// <inheritdoc/>
 public virtual void CancelLinking()
 {
     if (!linkStateMachine.CheckCanSwitchTo(LinkState.Available))
     {
         HostedDebugLog.Fine(this, "Ignore linking mode cancel in state: {0}", linkState);
         return;
     }
     linkState = LinkState.Available;
 }
Exemple #13
0
 /// <summary>
 /// Creates a stock joint between the coupled parts, given there is none already created.
 /// </summary>
 /// <remarks>The created joint (if any) is populated to the hosting part.</remarks>
 void MaybeCreateStockJoint()
 {
     if (linkTarget.part.attachJoint == null)
     {
         HostedDebugLog.Fine(
             this, "Create a stock joint between: {0} <=> {1}", linkSource, linkTarget);
         linkTarget.part.CreateAttachJoint(AttachModes.STACK);
     }
 }
Exemple #14
0
        /// <summary>Creates a stock-aloke joint between the unrealted parts.</summary>
        /// <remarks>The physical joints will be controlled by the module.</remarks>
        void CreateCustomJoint()
        {
            HostedDebugLog.Fine(
                this, "Create a stock-alike joint between: {0} <=> {1}", linkSource, linkTarget);
            var stockJoint = PartJoint.Create(linkSource.part, linkTarget.part,
                                              linkSource.coupleNode, linkTarget.coupleNode,
                                              AttachModes.STACK);

            SetCustomJoints(stockJoint.joints.ToArray());
        }
Exemple #15
0
 /// <inheritdoc/>
 public virtual void CancelLinking()
 {
     if (!linkStateMachine.CheckCanSwitchTo(LinkState.Available))
     {
         HostedDebugLog.Fine(this, "Ignore linking mode cancel in state: {0}", linkState);
         return;
     }
     SetLinkState(LinkState.Available);
     KASAPI.KasEvents.OnStopLinking.Fire(this);
 }
Exemple #16
0
 /// <summary>Drops and cleans up all the PhysX joints between the rigid objects.</summary>
 /// <remarks>
 /// <para>
 /// The default implementation simply destroys the joints from the <see cref="customJoints"/>
 /// collection. In most cases it's enough to update the physics in the game. However, if module
 /// manages some other objects or components, then this method is the right place to do the
 /// cleanup.
 /// </para>
 /// <para>
 /// IMPORTANT! The <see cref="SetCustomJoints"/> method cleans up all the joints by invoking this
 /// method. If there are extra objects that the child class needs to cleanup, then they must
 /// <i>not</i> get initialized before the new joints are set. Otherwise, the newly created objects
 /// may get destroyed. The suggested way of cleaning up the Unity objects is adding them into the
 /// <see cref="customExtraObjects"/> collection.
 /// </para>
 /// </remarks>
 /// <seealso cref="customJoints"/>
 /// <seealso cref="customExtraObjects"/>
 protected virtual void CleanupPhysXJoints()
 {
     if (customJoints.Count > 0)
     {
         HostedDebugLog.Fine(this, "Drop {0} joint(s) to: {1}", customJoints.Count, linkTarget);
         customJoints.ForEach(Object.Destroy);
         customJoints.Clear();
         customExtraObjects.ForEach(Object.Destroy);
         customExtraObjects.Clear();
     }
 }
Exemple #17
0
 /// <summary>Calls renderer updates as long as the renderer is started.</summary>
 /// <seealso cref="linkUpdateCoroutine"/>
 /// <seealso cref="StartRenderer"/>
 IEnumerator UpdateLinkCoroutine()
 {
     HostedDebugLog.Fine(this, "Staring renderer updates...");
     while (isStarted)
     {
         UpdateLink();
         yield return(null);
     }
     // The coroitine is expected to be terminated explicitly!
     HostedDebugLog.Warning(this, "Terminate coroutine on renderer stop!");
 }
Exemple #18
0
 /// <summary>Reacts on a part de-coupling and adjusts its colliders as needed.</summary>
 /// <remarks>
 /// When a part is leaving the target vessel, the collsions between this part and the pipe meshes
 /// must be restored.
 /// </remarks>
 /// <param name="originator">The part that has decoupled.</param>
 void OnPartDeCoupleCompleteEvent(Part originator)
 {
     if (formerTargetVessel != null && originator.vessel != formerTargetVessel)
     {
         // It's either the traget part has decoupled from its vessel, or the owner vessel has
         // abandoned the target part.
         var leavingVessel = originator == targetPart ? formerTargetVessel : originator.vessel;
         HostedDebugLog.Fine(this, "Restore collision ignores on: {0}", leavingVessel);
         leavingVessel.parts
         .ForEach(p => SetCollisionIgnores(p, false));
     }
     formerTargetVessel = null;
 }
 /// <inheritdoc cref="IPartModule.OnStart" />
 public override void OnStart(StartState state)
 {
     base.OnStart(state);
     if (!_moduleSettingsLoaded)
     {
         _moduleSettingsLoaded = true;
         if (!HighLogic.LoadedSceneIsEditor)
         {
             HostedDebugLog.Fine(this, "Late load of module settings. Save file inconsistency?");
         }
         InitModuleSettings();
     }
 }
Exemple #20
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));
        }
Exemple #21
0
        /// <summary>Copies the custom part fields from the prefab into the instance.</summary>
        /// <remarks>
        /// The consumer code must call this method from the <c>OnAwake</c> method to ensure the custom
        /// fields are properly initialized.
        /// </remarks>
        /// <param name="tgtModule">The module to copy the fields into.</param>
        /// <seealso cref="ReadPartConfig"/>
        /// <example>
        /// <code source="Examples/ConfigUtils/ConfigAccessor-Examples.cs" region="ReadPartConfigExample"/>
        /// </example>
        public static void CopyPartConfigFromPrefab(PartModule tgtModule)
        {
            var part = tgtModule.part;

            if (PartLoader.Instance.IsReady())
            {
                var moduleIdx = part.Modules.IndexOf(tgtModule);
                if (moduleIdx == -1)
                {
                    // Modules in the unloaded parts awake before being added into part.
                    moduleIdx = part.Modules.Count;
                }
                if (moduleIdx >= part.partInfo.partPrefab.Modules.Count)
                {
                    HostedDebugLog.Error(
                        tgtModule, "The prefab part doesn't have the module at {0}", moduleIdx);
                    return;
                }
                var srcModule = part.partInfo.partPrefab.Modules[moduleIdx];
                if (srcModule.moduleName != tgtModule.moduleName)
                {
                    HostedDebugLog.Error(
                        tgtModule, "Mismatched module in prefab at {0}: expected={1}, found={2}",
                        moduleIdx, tgtModule.moduleName, srcModule.moduleName);
                    if (GameSettings.VERBOSE_DEBUG_LOG)
                    {
                        HostedDebugLog.Fine(
                            tgtModule, "*** DUMP OF AVAILABLE MODULES: infoName={0}, prefabName{1}",
                            part.partInfo.name, part.partInfo.partPrefab.name);
                        for (var i = 0; i < part.partInfo.partPrefab.Modules.Count; i++)
                        {
                            DebugEx.Fine("* name={0}, id=#{1}", part.partInfo.partPrefab.Modules[i].moduleName, i);
                        }
                    }
                    return;
                }
                var fields = PersistentFieldsFactory.GetPersistentFields(
                    tgtModule.GetType(), false /* needStatic */, true /* needInstance */,
                    StdPersistentGroups.PartConfigLoadGroup);
                foreach (var field in fields)
                {
                    // We need a copy, so get it thru the persistence.
                    var copyNode = new ConfigNode();
                    field.WriteToConfig(copyNode, srcModule);
                    field.ReadFromConfig(copyNode, tgtModule);
                }
            }
        }
Exemple #22
0
 /// <inheritdoc/>
 public void AddNode(Part part, AttachNode attachNode)
 {
     ArgumentGuard.NotNull(part, "part");
     ArgumentGuard.NotNull(attachNode, "attachNode", context: part);
     if (attachNode.owner != part)
     {
         HostedDebugLog.Warning(
             part, "Former owner of the attach node doesn't match the new one: {0}", attachNode.owner);
         attachNode.owner = part;
     }
     if (part.attachNodes.IndexOf(attachNode) == -1)
     {
         HostedDebugLog.Fine(part, "Adding node: {0}", NodeId(attachNode));
         part.attachNodes.Add(attachNode);
     }
 }
Exemple #23
0
 /// <inheritdoc/>
 public void DropNode(Part part, AttachNode attachNode)
 {
     ArgumentGuard.NotNull(part, "part");
     ArgumentGuard.NotNull(attachNode, "attachNode", context: part);
     if (attachNode.attachedPart != null)
     {
         HostedDebugLog.Error(part, "Not dropping an attached node: {0}", NodeId(attachNode));
         return;
     }
     if (part.attachNodes.IndexOf(attachNode) != -1)
     {
         HostedDebugLog.Fine(part, "Drop attach node: {0}", NodeId(attachNode));
         part.attachNodes.Remove(attachNode);
         attachNode.attachedPartId = 0; // Just in case.
     }
 }
Exemple #24
0
        /// <summary>Updates the item's resource.</summary>
        /// <param name="name">The new of the resource.</param>
        /// <param name="amount">The new amount or delta.</param>
        /// <param name="isAmountRelative">
        /// Tells if the amount must be added to the current item's amount instead of simply replacing it.
        /// </param>
        public void UpdateResource(string name, double amount, bool isAmountRelative = false)
        {
            var res = KISAPI.PartNodeUtils.UpdateResource(partNode, name, amount,
                                                          isAmountRelative: isAmountRelative);

            if (res.HasValue)
            {
                HostedDebugLog.Fine(
                    inventory, "Updated item resource: name={0}, newAmount={1}", name, res);
                inventory.RefreshContents();
            }
            else
            {
                HostedDebugLog.Error(
                    inventory, "Cannot find resource {0} in item for {1}", name, availablePart.name);
            }
        }
Exemple #25
0
 /// <inheritdoc/>
 protected override void SetupPhysXJoints()
 {
     if (isHeadStarted)
     {
         HostedDebugLog.Warning(this, "A physical head is running. Stop it before the link!");
         StopPhysicalHead();
     }
     CreateDistanceJoint(
         linkSource, linkTarget.part.Rigidbody, GetTargetPhysicalAnchor(linkSource, linkTarget));
     if (partJoint != null &&
         (!allowDockingAtZeroDistance || !Mathf.Approximately(deployedCableLength, 0)))
     {
         HostedDebugLog.Fine(this, "Dropping the stock joint to: {0}", partJoint.Child);
         partJoint.DestroyJoint();
         partJoint.Child.attachJoint = null;
     }
 }
Exemple #26
0
 /// <inheritdoc/>
 public void SetLockedOnCouple(bool mode)
 {
     if (isLinked)
     {
         if (isLockedWhenCoupled != mode)
         {
             isLockedWhenCoupled = mode;
             HostedDebugLog.Fine(this, "Change locked on coupled part: {0}", isLockedWhenCoupled);
             CleanupPhysXJoints();
             SetupPhysXJoints();
         }
     }
     else
     {
         isLockedWhenCoupled = mode;
         HostedDebugLog.Fine(this, "Set locked on couple mode in a non-linked module: {0}", mode);
     }
 }
Exemple #27
0
        /// <summary>Triggers coupled node check.</summary>
        void OnPartCoupleEvent(GameEvents.FromToAction <Part, Part> action)
        {
            AttachNode node = null;

            if (action.from == part)
            {
                node = action.from.FindPartThroughNodes(action.to);
            }
            else if (action.to == part)
            {
                node = action.to.FindPartThroughNodes(action.from);
            }
            if (node != null && node.id == attachNodeName)
            {
                HostedDebugLog.Fine(this, "Schedule coupling check on coupling event: from={0}, to={1}",
                                    action.from, action.to);
                AsyncCall.CallOnEndOfFrame(this, CheckCoupleNode);
            }
        }
Exemple #28
0
 /// <inheritdoc/>
 public override void OnStartFinished(PartModule.StartState state)
 {
     base.OnStartFinished(state);
     // Prevent the third-party logic on the auto node. See OnLoad.
     if ((HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor) &&
         isAutoAttachNode && coupleNode != null && coupleNode.attachedPart == null)
     {
         KASAPI.AttachNodesUtils.DropNode(part, coupleNode);
     }
     if (persistedLinkState == LinkState.Linked)
     {
         RestoreOtherPeer();
         if (otherPeer == null)
         {
             HostedDebugLog.Error(this, "Cannot restore the link's peer");
             persistedLinkState = LinkState.Available;
             if (coupleNode != null && coupleNode.attachedPart != null)
             {
                 // Decouple the coupled part if the link cannot be restored. It'll allow the player to
                 // restore the game status without hacking the save files.
                 AsyncCall.CallOnEndOfFrame(
                     this, () => {
                     if (coupleNode.attachedPart != null) // The part may get decoupled already.
                     {
                         KASAPI.LinkUtils.DecoupleParts(part, coupleNode.attachedPart);
                     }
                 });
             }
             // This may break a lot of logic, built on top of the KAS basic modules. However, it will
             // allow the main logic to work. Given it's a fallback, it's OK.
             part.Modules.OfType <AbstractLinkPeer>()
             .Where(p => p.isLinked && (p.cfgAttachNodeName == attachNodeName ||
                                        p.cfgDependentNodeNames.Contains(attachNodeName)))
             .ToList()
             .ForEach(m => SetLinkState(LinkState.Available));
         }
         else
         {
             HostedDebugLog.Fine(this, "Restored link to: {0}", otherPeer);
         }
     }
     SetLinkState(persistedLinkState);
 }
Exemple #29
0
        /// <inheritdoc/>
        public virtual void StopRenderer()
        {
            // Stop meshes updates.
            if (linkUpdateCoroutine != null)
            {
                HostedDebugLog.Fine(this, "Stopping renderer updates...");
                StopCoroutine(linkUpdateCoroutine);
                linkUpdateCoroutine = null;
            }

            // Sync the renderers settinsg to the source part to handle the highlights.
            if (isStarted)
            {
                sourceTransform.GetComponentsInChildren <Renderer>().ToList()
                .ForEach(r => r.SetPropertyBlock(part.mpb));
                targetTransform.GetComponentsInChildren <Renderer>().ToList()
                .ForEach(r => r.SetPropertyBlock(part.mpb));
            }

            DestroyPipeMesh();
            PartModel.UpdateHighlighters(part);

            // Update the target vessel relations (if any).
            if (targetPart != null)
            {
                PartModel.UpdateHighlighters(targetPart);
                if (targetPart.vessel != vessel)
                {
                    targetPart.vessel.parts
                    .Where(p => p != null) // It's a cleanup method.
                    .ToList()
                    .ForEach(p => SetCollisionIgnores(p, false));
                }
            }

            targetPart      = null;
            sourceTransform = null;
            targetTransform = null;

            GameEvents.onPartCoupleComplete.Remove(OnPartCoupleCompleteEvent);
            GameEvents.onPartDeCouple.Remove(OnPartDeCoupleEvent);
            GameEvents.onPartDeCoupleComplete.Remove(OnPartDeCoupleCompleteEvent);
        }
Exemple #30
0
 /// <inheritdoc/>
 public virtual bool CreateJoint(ILinkSource source, ILinkTarget target)
 {
     if (isLinked)
     {
         HostedDebugLog.Error(
             this, "Cannot link the joint which is already linked to: {0}", linkTarget);
         return(false);
     }
     if (!CheckCoupled(source, target))
     {
         var errors = CheckConstraints(source, target);
         if (errors.Length > 0)
         {
             HostedDebugLog.Error(this, "Cannot create joint:\n{0}", DbgFormatter.C2S(errors));
             return(false);
         }
     }
     else
     {
         HostedDebugLog.Fine(this, "The parts are coupled. Skip the constraints check");
     }
     linkSource = source;
     linkTarget = target;
     if (!originalLength.HasValue)
     {
         SetOrigianlLength(Vector3.Distance(
                               GetSourcePhysicalAnchor(source), GetTargetPhysicalAnchor(source, target)));
     }
     isLinked = true;
     // If the parts are already coupled at this moment, then the mode must be set as such.
     coupleOnLinkMode |= isCoupled;
     // Ensure the coupling can be done.
     coupleOnLinkMode &= linkSource.coupleNode != null && linkTarget.coupleNode != null;
     if (coupleOnLinkMode)
     {
         CoupleParts();
     }
     else
     {
         AttachParts();
     }
     return(true);
 }