Example #1
0
 /// <inheritdoc/>
 public virtual bool LinkToTarget(ILinkTarget target)
 {
     if (!linkStateMachine.CheckCanSwitchTo(LinkState.Linked))
     {
         if (linkActor == LinkActorType.Player)
         {
             ShowStatusMessage(SourceIsNotAvailableForLinkMsg, isError: true);
         }
         HostedDebugLog.Error(this, "Cannot link in state: {0}", linkState);
         return(false);
     }
     if (!CheckCanLinkTo(target, reportToGui: linkActor == LinkActorType.Player))
     {
         return(false);
     }
     if (coupleMode == CoupleMode.AlwaysCoupled ||
         coupleNode != null && coupleNode.attachedPart != null)
     {
         linkJoint.SetCoupleOnLinkMode(true);
     }
     else if (coupleMode == CoupleMode.NeverCouple)
     {
         linkJoint.SetCoupleOnLinkMode(false);
     }
     LogicalLink(target);
     PhysicalLink();
     return(true);
 }
Example #2
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);
 }
Example #3
0
 /// <inheritdoc/>
 public override void OnLoad(ConfigNode node)
 {
     // The locked connector with a part attached is get docked. So we require docking mode here.
     // TODO(ihsoft): Allow non-docking mode.
     if (!allowCoupling)
     {
         HostedDebugLog.Error(this, "The coupling must be allowed for this part to work. Overriding"
                              + " allowCoupling settings to true.");
         allowCoupling = true; // A bad approach, but better than not having the attach node.
     }
     base.OnLoad(node);
     if (connectorMass > part.mass)
     {
         HostedDebugLog.Error(this,
                              "Connector mass is greater than the part's mass: {0} > {1}", connectorMass, part.mass);
         connectorMass = 0.1f * part.mass; // A fail safe value.
     }
     LoadOrCreateConnectorModel();
     if (!persistedIsConnectorLocked)
     {
         // In case of the connector is not locked to either the winch or the target part, adjust its
         // model position and rotation. The rest of the state will be restored in the state machine.
         if (persistedConnectorPosAndRot != null)
         {
             var world = gameObject.transform.TransformPosAndRot(persistedConnectorPosAndRot);
             connectorModelObj.position = world.pos;
             connectorModelObj.rotation = world.rot;
         }
     }
 }
Example #4
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);
            }
        }
Example #5
0
 /// <inheritdoc/>
 protected override void CheckSettingsConsistency()
 {
     if (!allowCoupling)
     {
         // Connector docking mode is required!
         // TODO(ihsoft): Allow non-docking mode.
         allowCoupling = true;
         HostedDebugLog.Warning(
             this, "Inconsistent setting fixed: allowCoupling => {0}, due to it's required by physical"
             + " source", allowCoupling);
     }
     base.CheckSettingsConsistency();
     if (connectorMass > part.mass)
     {
         connectorMass = 0.1f * part.mass; // A fail safe value.
         HostedDebugLog.Warning(
             this, "Inconsistent setting fixed: connectorMass => {0}, due to partMass={1}",
             connectorMass, part.mass);
     }
     if (linkJoint != null && cableJoint == null)
     {
         HostedDebugLog.Error(
             this, "Cannot fix inconsistent setting: jointName={0} is not cable joint", jointName);
     }
 }
Example #6
0
        /// <summary>Sets up a sound FX group with an audio clip .</summary>
        /// <param name="obj">The game object to attach sound to.</param>
        /// <param name="sndPath">The URL to the audio clip.</param>
        /// <param name="loop">Specifies if the clip playback shold be looped.</param>
        /// <param name="maxDistance">The maximum distance at which the sound is hearable.</param>
        /// <returns>An audio source object attached to the <paramref name="obj"/>.</returns>
        public static AudioSource Create3dSound(GameObject obj, string sndPath,
                                                bool loop = false, float maxDistance = 30f)
        {
            if (HighLogic.LoadedScene == GameScenes.LOADING ||
                HighLogic.LoadedScene == GameScenes.LOADINGBUFFER)
            {
                // Resources are not avaialble during game load.
                return(null);
            }
            if (!GameDatabase.Instance.ExistsAudioClip(sndPath))
            {
                HostedDebugLog.Error(obj.transform, "Sound file not found: {0}", sndPath);
            }
            var audio = obj.AddComponent <AudioSource>();

            audio.volume       = GameSettings.SHIP_VOLUME;
            audio.rolloffMode  = AudioRolloffMode.Linear;
            audio.dopplerLevel = 0f;
            audio.spatialBlend = 1f; // Set as 2D audiosource
            audio.maxDistance  = maxDistance;
            audio.loop         = loop;
            audio.playOnAwake  = false;
            audio.clip         = GameDatabase.Instance.GetAudioClip(sndPath);
            return(audio);
        }
Example #7
0
 /// <inheritdoc/>
 protected override void InitModuleSettings()
 {
     base.InitModuleSettings();
     _attachBoneTransform = Hierarchy.FindTransformByPath(part.transform, equipBoneName);
     if (_attachBoneTransform == null)
     {
         HostedDebugLog.Error(this, "Cannot find bone for: {0}", equipBoneName);
     }
 }
Example #8
0
 /// <inheritdoc/>
 public virtual void BreakCurrentLink(LinkActorType actorType)
 {
     if (!isLinked)
     {
         HostedDebugLog.Error(this, "Cannot break link in state: {0}", linkState);
         return;
     }
     PhysicalUnlink();
     LogicalUnlink(actorType);
 }
Example #9
0
            /// <summary>
            /// Finds and returns the requested child model, or the main model if the child is not found.
            /// </summary>
            /// <param name="name">Name of the child object to find.</param>
            /// <returns>Object or node's model itself if the child is not found.</returns>
            protected Transform GetTransformByName(string name)
            {
                var res = model.Find(name);

                if (res == null)
                {
                    HostedDebugLog.Error(model, "Cannot find transform: {0}", name);
                    res = model; // Fallback.
                }
                return(res);
            }
Example #10
0
        /// <summary>Applies a setup function on a KSP part module field.</summary>
        /// <param name="fieldName">The fields name.</param>
        /// <param name="setupFn">The function to apply to the field if the one is found.</param>
        protected void SetupField(string fieldName, Action <BaseField> setupFn)
        {
            var kspField = Fields[fieldName];

            if (kspField == null)
            {
                HostedDebugLog.Error(this, "Cannot find field: {0}", fieldName);
                return;
            }
            setupFn.Invoke(kspField);
        }
Example #11
0
        /// <summary>Applies a setup function on a KSP part module event.</summary>
        /// <param name="eventFn">The event's method signature.</param>
        /// <param name="setupFn">The function to apply to the event if the one is found.</param>
        protected void SetupEvent(Action eventFn, Action <BaseEvent> setupFn)
        {
            var moduleEvent = Events[eventFn.Method.Name];

            if (moduleEvent == null)
            {
                HostedDebugLog.Error(this, "Cannot find event: {0}", eventFn.Method.Name);
                return;
            }
            setupFn.Invoke(moduleEvent);
        }
Example #12
0
        /// <summary>Finds model by path or logs&amp;throws.</summary>
        /// <remarks>Just a convenience method to avoid unclear NREs.</remarks>
        /// <returns>The model. It's never <c>null</c>.</returns>
        /// <exception cref="ArgumentException">If model cannot be retrieved.</exception>
        protected Transform FindModelOrThrow(Transform root, string path)
        {
            var res = Hierarchy.FindTransformByPath(root, path);

            if (res == null)
            {
                HostedDebugLog.Error(this, "Cannot find model: path={0}, parent={1}", path, root);
                throw new ArgumentException("Model not found: " + path);
            }
            return(res);
        }
Example #13
0
        /// <summary>Returns an anchor for the physical joint at the target part.</summary>
        /// <remarks>
        /// The anchor will be calculated in the source's part scale, and the target's model scale will
        /// be ignored.
        /// </remarks>
        /// <param name="source">The source of the link.</param>
        /// <param name="target">The target of the link.</param>
        /// <returns>The position in the world coordinates.</returns>
        protected Vector3 GetTargetPhysicalAnchor(ILinkSource source, ILinkTarget target)
        {
            var scale = source.nodeTransform.lossyScale;

            if (Mathf.Abs(scale.x - scale.y) > 1e-05 || Mathf.Abs(scale.x - scale.z) > 1e-05)
            {
                HostedDebugLog.Error(this, "Uneven scale on the source part is not supported: {0}",
                                     DbgFormatter.Vector(scale));
            }
            return(target.nodeTransform.position
                   + target.nodeTransform.rotation * (anchorAtTarget * scale.x));
        }
Example #14
0
        /// <summary>Applies a setup function on a KSP part module action.</summary>
        /// <param name="partModule">The module to find the action in.</param>
        /// <param name="actionFn">The actions's method signature.</param>
        /// <param name="setupFn">The function to apply to the action if the one is found.</param>
        /// <returns>
        /// <c>true</c> if the action was found and the function was applied, <c>false</c> otherwise.
        /// </returns>
        /// <seealso cref="GetAction"/>
        public static bool SetupAction(
            PartModule partModule, Action <KSPActionParam> actionFn, Action <BaseAction> setupFn)
        {
            var moduleEvent = partModule.Actions[actionFn.Method.Name];

            if (moduleEvent == null)
            {
                HostedDebugLog.Error(partModule, "Cannot find action: {0}", actionFn.Method.Name);
                return(false);
            }
            setupFn.Invoke(moduleEvent);
            return(true);
        }
Example #15
0
        /// <summary>Applies a setup function on a KSP part module event.</summary>
        /// <param name="partModule">The module to find the event in.</param>
        /// <param name="eventFn">The event's method signature.</param>
        /// <param name="setupFn">The function to apply to the event if the one is found.</param>
        /// <returns>
        /// <c>true</c> if the event was found and the function was applied, <c>false</c> otherwise.
        /// </returns>
        /// <seealso cref="GetEvent"/>
        /// <example><code source="Examples/PartUtils/PartModuleUtils-Examples.cs" region="PartModuleUtils_SetupEvent"/></example>
        public static bool SetupEvent(
            PartModule partModule, Action eventFn, Action <BaseEvent> setupFn)
        {
            var moduleEvent = partModule.Events[eventFn.Method.Name];

            if (moduleEvent == null)
            {
                HostedDebugLog.Error(partModule, "Cannot find event: {0}", eventFn.Method.Name);
                return(false);
            }
            setupFn.Invoke(moduleEvent);
            return(true);
        }
 /// <inheritdoc/>
 public override void OnLoad(ConfigNode node)
 {
     base.OnLoad(node);
     if (animationState)
     {
         UpdateAnimationState();
     }
     else
     {
         HostedDebugLog.Error(
             this, "Bad model or config in part {0}. Cannot find animation: {1}", part, animationName);
     }
 }
Example #17
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);
                }
            }
        }
Example #18
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.
     }
 }
Example #19
0
        /// <inheritdoc/>
        public virtual void StartPhysicalHead(ILinkSource source, Transform headObjAnchor)
        {
            headRb = headObjAnchor.GetComponentInParent <Rigidbody>();
            if (isHeadStarted || isLinked || headRb == null)
            {
                HostedDebugLog.Error(this,
                                     "Bad link state for the physical head start: isLinked={0}, isHeadStarted={1}, hasRb={2}",
                                     isLinked, isHeadStarted, headRb != null);
                return;
            }
            headSource = source;

            // Attach the head to the source.
            CreateDistanceJoint(source, headRb, headObjAnchor.position);
            SetOriginalLength(deployedCableLength);
        }
Example #20
0
        /// <inheritdoc/>
        public override void OnStart(PartModule.StartState state)
        {
            base.OnStart(state);

            linkJoint = part.Modules.OfType <ILinkJoint>()
                        .FirstOrDefault(x => x.cfgJointName == jointName);
            if (linkJoint == null)
            {
                HostedDebugLog.Error(this, "KAS part misses a joint module. It won't work properly");
            }
            linkRenderer = part.Modules.OfType <ILinkRenderer>()
                           .FirstOrDefault(x => x.cfgRendererName == linkRendererName);
            if (linkRenderer == null)
            {
                HostedDebugLog.Error(this, "KAS part misses a renderer module. It won't work properly");
            }
        }
Example #21
0
 /// <summary>
 /// Decouples the source and the target parts turning them into the separate vessels.
 /// </summary>
 /// <seealso cref="CoupleParts"/>
 void DecoupleParts()
 {
     if (!isCoupled)
     {
         HostedDebugLog.Error(this, "Cannot decouple - bad link/part state");
         return;
     }
     selfDecoupledAction = true; // Protect the action to not let the link auto-broken.
     KASAPI.LinkUtils.DecoupleParts(
         linkSource.part, linkTarget.part,
         vesselInfo1: persistedSrcVesselInfo, vesselInfo2: persistedTgtVesselInfo);
     selfDecoupledAction    = false;
     persistedSrcVesselInfo = null;
     persistedTgtVesselInfo = null;
     DelegateCouplingRole(linkTarget.part);
     SetCustomJoints(null);
 }
Example #22
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);
            }
        }
        /// <summary>Get the module's model shader.</summary>
        /// <remarks>Implements a fallback logic to not crash if the shader is not found.</remarks>
        /// <param name="overrideShaderName">
        /// The alternative name of the shader to prefer. If set, then the module's shader name is ignored
        /// in favor of the one provided.
        /// </param>
        /// <returns>The requested shader, or a fallback share. It's never <c>null</c>.</returns>
        protected Shader GetShader(string overrideShaderName = null)
        {
            var shaderToFind = overrideShaderName ?? shaderName;
            var shader       = Shader.Find(shaderToFind);

            if (shader == null)
            {
                // Fallback if the shader cannot be found.
                HostedDebugLog.Error(this, "Cannot find shader: {0}. Using default.", shaderToFind);
                shader = Shader.Find(FallbackShaderName);
                Preconditions.NotNull(
                    shader,
                    message: "Failed to create a fallback shader: " + FallbackShaderName,
                    context: this);
            }
            return(shader);
        }
Example #24
0
        /// <inheritdoc/>
        public virtual void StartPhysicalHead(ILinkSource source, Transform headObjAnchor)
        {
            //FIXME: add the physical head module here.
            headRb = headObjAnchor.GetComponentInParent <Rigidbody>();
            if (isHeadStarted || isLinked || headRb == null)
            {
                HostedDebugLog.Error(this,
                                     "Bad link state for the physical head start: isLinked={0}, isHeadStarted={1}, hasRb=[2}",
                                     isLinked, isHeadStarted, headRb != null);
                return;
            }
            headSource         = source;
            headPhysicalAnchor = headObjAnchor;

            // Attach the head to the source.
            CreateDistanceJoint(source, headRb, headObjAnchor.position);
        }
Example #25
0
 /// <inheritdoc/>
 public override void OnLoad(ConfigNode node)
 {
     base.OnLoad(node);
     if (part.Resources.Count == 0)
     {
         HostedDebugLog.Error(this, "No resources on the canister! This won't work.");
         return;
     }
     if (part.Resources.Count > 1)
     {
         HostedDebugLog.Error(this, "Too many resources on the canister! The first one will be used.");
     }
     _mainResourceName = part.Resources[0].resourceName;
     if (_mainResourceName != StockResourceNames.EvaPropellant)
     {
         HostedDebugLog.Info(this, "Using a customized resource type: {0}", _mainResourceName);
     }
 }
Example #26
0
 /// <inheritdoc/>
 public virtual bool LinkToTarget(ILinkTarget target)
 {
     if (!linkStateMachine.CheckCanSwitchTo(LinkState.Linked))
     {
         if (linkActor == LinkActorType.Player)
         {
             ShowStatusMessage(SourceIsNotAvailableForLinkMsg, isError: true);
         }
         HostedDebugLog.Error(this, "Cannot link in state: {0}", linkState);
         return(false);
     }
     if (!CheckCanLinkTo(target, reportToGUI: linkActor == LinkActorType.Player))
     {
         return(false);
     }
     LogicalLink(target);
     PhysicaLink();
     return(true);
 }
Example #27
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);
 }
Example #28
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);
 }
Example #29
0
        /// <inheritdoc/>
        public string[] CheckColliderHits(Transform source, Transform target)
        {
            if (!pipeColliderIsPhysical)
            {
                return(new string[0]); // No need to check, the meshes will never collide.
            }
            // HACK: Start the renderer before getting the pipes.
            var oldStartState   = isStarted;
            var oldPhyscalState = isPhysicalCollider;

            if (!isStarted)
            {
                isPhysicalCollider = false;
                StartRenderer(source, target);
            }
            else if (sourceTransform != source || targetTransform != target)
            {
                HostedDebugLog.Error(this, "Cannot verify hits on a started renderer");
            }
            var points = GetPipePath(source, target);

            if (!oldStartState)
            {
                StopRenderer();
                isPhysicalCollider = oldPhyscalState;
            }

            var hitParts = new HashSet <Part>();

            for (var i = 0; i < points.Length - 1; i++)
            {
                CheckHitsForCapsule(points[i + 1], points[i], pipeDiameter, target, hitParts);
            }
            var hitMessages = new List <string>();

            foreach (var hitPart in hitParts)
            {
                hitMessages.Add(hitPart != null
          ? LinkCollidesWithObjectMsg.Format(hitPart)
          : LinkCollidesWithSurfaceMsg.Format());
            }
            return(hitMessages.ToArray());
        }
Example #30
0
        /// <inheritdoc/>
        public AttachNode ParseNodeFromString(Part ownerPart, string def, string nodeId)
        {
            ArgumentGuard.NotNull(ownerPart, "ownerPart");
            ArgumentGuard.NotNullOrEmpty(def, "def", context: ownerPart);
            ArgumentGuard.NotNullOrEmpty(nodeId, "nodeId", context: ownerPart);
            var array = def.Split(',');

            ArgumentGuard.InRange(array.Length, "def", 6, 10,
                                  message: "Unexpected number of components", context: ownerPart);
            try {
                // The logic is borrowed from PartLoader.ParsePart.
                var attachNode = new AttachNode {
                    owner = ownerPart,
                    id    = nodeId
                };
                var factor = ownerPart.rescaleFactor;
                attachNode.position = new Vector3(
                    float.Parse(array[0]), float.Parse(array[1]), float.Parse(array[2])) * factor;
                attachNode.orientation = new Vector3(
                    float.Parse(array[3]), float.Parse(array[4]), float.Parse(array[5])) * factor;
                attachNode.originalPosition    = attachNode.position;
                attachNode.originalOrientation = attachNode.orientation;
                attachNode.size         = array.Length >= 7 ? int.Parse(array[6]) : 1;
                attachNode.attachMethod = array.Length >= 8
          ? (AttachNodeMethod)int.Parse(array[7])
          : AttachNodeMethod.FIXED_JOINT;
                if (array.Length >= 9)
                {
                    attachNode.ResourceXFeed = int.Parse(array[8]) > 0;
                }
                if (array.Length >= 10)
                {
                    attachNode.rigid = int.Parse(array[9]) > 0;
                }
                attachNode.nodeType = AttachNode.NodeType.Stack;
                return(attachNode);
            }
            catch (Exception ex) {
                HostedDebugLog.Error(ownerPart, "Cannot parse node '{0}' from: {1}\nError: {2}",
                                     nodeId, def, ex.Message);
                return(null);
            }
        }