public FeedWriter(IFeedDefinition <T> definition, ILinkSource <T> links, IUrlRegistry urls, IOutputWriter writer) { _definition = definition; _links = links; _urls = urls; _writer = writer; }
/// <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; }
/// <summary>Restores available state when connection mode is over.</summary> /// <remarks>It's only listened in state <see cref="LinkState.RejectingLinks"/>. /// <para>Event handler for <see cref="IKasEvents.OnStopLinking"/>.</para> /// </remarks> /// <param name="source">Source module that started the mode.</param> void OnStopLinkingKASEvent(ILinkSource source) { if (!isLocked) { SetLinkState(LinkState.Available); } }
/// <summary>Cancels the linking mode on this module.</summary> /// <remarks>KAS events listener.</remarks> /// <param name="connectionSource"></param> protected virtual void OnStopLinkingKASEvent(ILinkSource connectionSource) { if (!isLocked) { SetLinkState(LinkState.Available); } }
/// <summary>Creates an event info.</summary> /// <param name="source">The source that initiated the link.</param> /// <param name="target">The target that accepted the link.</param> /// <param name="actorType">The actor that did the change.</param> public KasLinkEventImpl(ILinkSource source, ILinkTarget target, LinkActorType actorType = LinkActorType.API) { _source = source; _target = target; _actor = actorType; }
/// <summary>Creates an event info.</summary> /// <param name="source">The source that initiated the link.</param> /// <param name="target">The target that accepted the link.</param> /// <param name="actorType">The actor that did the change.</param> public KasLinkEventImpl(ILinkSource source, ILinkTarget target, LinkActorType actorType = LinkActorType.API) { this.source = source; this.target = target; actor = actorType; }
/// <summary> /// Fires when this module can link, and there is a source that has actived the linking mode. /// </summary> /// <remarks>KAS events listener.</remarks> /// <param name="source"></param> protected virtual void OnStartLinkingKASEvent(ILinkSource source) { if (CheckCanLinkWith(source)) { SetLinkState(LinkState.AcceptingLinks); } }
/// <inheritdoc/> public virtual void StopPhysicalHead() { headRb = null; headSource = null; Destroy(cableJoint); cableJoint = null; SetOriginalLength(null); }
public FeedWriter(IFeedSource <T> feedSource, IFeedDefinition <T> definition, ILinkSource <T> links, IUrlRegistry urls) { _feedSource = feedSource; _definition = definition; _links = links; _urls = urls; }
public MediaWriter(IMediaDocument document, ILinkSource <T> links, IUrlRegistry urls, IValueProjection <T> projection) { _document = document; _links = links; _urls = urls; _projection = projection; }
public MediaWriter(IMediaDocument document, ILinkSource <T> links, IUrlRegistry urls, IProjection <T> projection, IServiceLocator services) { _document = document; _links = links; _urls = urls; _projection = projection; _services = services; }
/// <summary>Checks if the link's angle at the target joint is within the limits.</summary> /// <remarks>This method takes into consideration the anchor settings.</remarks> /// <param name="source">The possible source of the link.</param> /// <param name="target">The possible target of the link.</param> /// <returns>An error message if the angle is over limit or <c>null</c> otherwise.</returns> /// <seealso cref="anchorAtSource"/> /// <seealso cref="anchorAtTarget"/> protected string CheckAngleLimitAtTarget(ILinkSource source, ILinkTarget target) { var linkVector = GetSourcePhysicalAnchor(source) - GetTargetPhysicalAnchor(source, target); var angle = Vector3.Angle(target.nodeTransform.rotation * Vector3.forward, linkVector); return(targetLinkAngleLimit > 0 && angle > targetLinkAngleLimit ? TargetNodeAngleLimitReachedMsg.Format(angle, targetLinkAngleLimit) : null); }
// Регистрирует пару "объект-наблюдатель" public void Register(ILinkSource source, ILinkTarget target) { if (source == null || target == null || _links.Any(l => l.Item1.Equals(source) && l.Item2.Equals(target))) { return; } _links.Add(new Tuple <ILinkSource, ILinkTarget>(source, target)); }
/// <inheritdoc/> public virtual string[] CheckConstraints(ILinkSource source, ILinkTarget target) { var errors = new[] { CheckLengthLimit(source, target), CheckAngleLimitAtSource(source, target), CheckAngleLimitAtTarget(source, target), }; return(errors.Where(x => x != null).ToArray()); }
/// <summary>Verifies that part can link with the source.</summary> /// <param name="source">Source to check against.</param> /// <returns> /// <c>true</c> if link is <i>technically</i> possible. It's not guaranteed that the link will /// succeed. /// </returns> protected virtual bool CheckCanLinkWith(ILinkSource source) { // Cannot attach to itself or incompatible link type. if (part != source.part && cfgLinkType == source.cfgLinkType) { return(true); } // Link is not allowed. return(false); }
// Уведомление конкретного получателя public void Notify <TTarget>(ILinkSource source, int commandId, Dictionary <string, object> parameters) { var target = _links.FirstOrDefault(l => l.Item1.Equals(source) && l.Item2.GetType() == typeof(TTarget)); if (target == null) { return; } target.Item2.Update(commandId, parameters); }
/// <summary>Cleans up the attach nodes and, optionally, breaks the link.</summary> /// <remarks> /// The actual changes are delyed till the end of frame. So it's safe to call this method from an /// event handler. /// </remarks> /// <param name="source">The link source at the moemnt of cleanup.</param> /// <param name="target">The link target at the moment of cleanup.</param> void MaybeBreakLink(ILinkSource source, ILinkTarget target) { // Delay the nodes cleanup to let the other logic work smoothly. Copy the properties since // they will be null'ed on the link destruction. AsyncCall.CallOnEndOfFrame(this, () => { if (isLinked) { source.BreakCurrentLink(LinkActorType.Physics); } }); }
/// <inheritdoc/> public override bool CreateJoint(ILinkSource source, ILinkTarget target) { if (!base.CreateJoint(source, target)) { return(false); } trgJoint.angularXMotion = ConfigurableJointMotion.Locked; SetLockingMode(persistedLockingMode, updateUi: false); SetActiveSteeringState(persistedActiveSteeringEnabled); return(true); }
public object GetState(ILinkTarget target, ILinkSource source) { if (target == null || source == null) { return(null); } var link = _links.FirstOrDefault(l => l.Item1.Equals(source) && l.Item2.Equals(target)); return(link == null ? null : link.Item1.GetState()); }
/// <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)); }
// Запускает обновление наблюдателям public void Notify(ILinkSource source, int commandId, Dictionary <string, object> parameters) { if (source == null) { return; } foreach (var link in _links.Where(l => l.Item1.Equals(source)).ToList()) { link.Item2.Update(commandId, parameters); } }
// Starts a renderer between the source and target. public static void StartRendrer(Part part, ILinkSource source, ILinkTarget target) { // It's a good idea to pre-cache this module in OnStart() method. var renderer = part.FindModulesImplementing <ILinkRenderer>() .FirstOrDefault(r => r.cfgRendererName == "MyRendererName"); if (renderer == null) { Debug.LogError("Ops! No renderer found"); return; } renderer.StartRenderer(source.nodeTransform, target.nodeTransform); }
/// <summary>Checks if the link's length is within the limits.</summary> /// <remarks>This method takes into consideration the anchor settings.</remarks> /// <param name="source">The possible source of the link.</param> /// <param name="target">The possible target of the link.</param> /// <returns>An error message if link length is over limit or <c>null</c> otherwise.</returns> /// <seealso cref="anchorAtSource"/> /// <seealso cref="anchorAtTarget"/> protected string CheckLengthLimit(ILinkSource source, ILinkTarget target) { var length = Vector3.Distance( GetSourcePhysicalAnchor(source), GetTargetPhysicalAnchor(source, target)); if (maxLinkLength > 0 && length > maxLinkLength) { return(MaxLengthLimitReachedMsg.Format(length, maxLinkLength)); } if (minLinkLength > 0 && length < minLinkLength) { return(MinLengthLimitReachedMsg.Format(length, minLinkLength)); } return(null); }
/// <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); }
/// <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); }
/// <summary>Restores the name and type of the vessels of the former coupled parts.</summary> /// <remarks> /// The source and target parts need to be separated, but the logical link still need to exist. /// On restore the vessel info will be cleared on the module. Alas, when the link is broken /// extrenally, the root vessel part cannot be properly restored. /// </remarks> void RestorePartialVesselInfo(ILinkSource source, ILinkTarget target, bool weDecouple) { AsyncCall.CallOnEndOfFrame(this, () => { var vesselInfo = weDecouple ? persistedSrcVesselInfo : persistedTgtVesselInfo; var childPart = weDecouple ? source.part : target.part; if (childPart.vessel.vesselType != vesselInfo.vesselType || childPart.vessel.vesselName != vesselInfo.name) { HostedDebugLog.Warning(this, "Partially restoring vessel info on {0}: type={1}, name={2}", childPart, vesselInfo.vesselType, vesselInfo.name); childPart.vessel.vesselType = vesselInfo.vesselType; childPart.vessel.vesselName = vesselInfo.name; } persistedSrcVesselInfo = null; persistedTgtVesselInfo = null; }); }
/// <inheritdoc/> public override void OnBeforeDebugAdjustablesUpdate() { base.OnBeforeDebugAdjustablesUpdate(); if (linkState != LinkState.Linked && linkState != LinkState.Available) { throw new InvalidOperationException("Cannot adjust value in link state: " + linkState); } dbgOldSource = linkSource; if (isLinked) { var cableJoint = linkSource.linkJoint as ILinkCableJoint; if (cableJoint != null) { cableLength = cableJoint.deployedCableLength; } linkSource.BreakCurrentLink(LinkActorType.Player); } }
/// <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); }
/// <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); 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; }
public void AddSource(ILinkSource NewSource) { List <ILinkingEventHandler> pendinglist; ILinkSource testoption; if (this._sources.TryGetValue(NewSource.ID, out testoption) == true) { throw new TsGuiKnownException("Duplicate ID found in LinkableLibrary: " + NewSource.ID, ""); } else { this._sources.Add(NewSource.ID, NewSource); } //now register any pending targets and cleanup if (this._pendingqueries.TryGetValue(NewSource.ID, out pendinglist) == true) { foreach (ILinkingEventHandler handler in pendinglist) { this.RegisterHandlerToSource(NewSource, handler); } this._pendingqueries.Remove(NewSource.ID); } }