StringBuilder DumpBaseJoint(Joint joint) { var msg = new StringBuilder(); msg.Append("name: ").Append(joint.name).AppendLine(); msg.Append("ownerBody: ") .Append(DebugEx.ObjectToString(joint.gameObject.GetComponent <Rigidbody>())) .AppendLine(); msg.Append("connectedBody: ") .Append(DebugEx.ObjectToString(joint.connectedBody)) .AppendLine(); // Collider setup. msg.Append("enableCollision: ").Append(joint.enableCollision).AppendLine(); // Optimization. msg.Append("enablePreprocessing: ").Append(joint.enablePreprocessing).AppendLine(); // Break forces. msg.Append("breakForce: ").Append(joint.breakForce).AppendLine(); msg.Append("breakTorque: ").Append(joint.breakTorque).AppendLine(); // Geometry. msg.Append("anchor: ").Append(DbgFormatter.Vector(joint.anchor)).AppendLine(); msg.Append("connectedAnchor: ") .Append(DbgFormatter.Vector(joint.connectedAnchor)) .AppendLine(); msg.Append("axis: ").Append(DbgFormatter.Vector(joint.axis)).AppendLine(); return(msg); }
public void TestMachine() { var sm = new SimpleStateMachine <State>(strict: false); sm.AddStateHandlers( State.One, enterHandler: oldState => Debug.Log("Now in state ONE"), leaveHandler: newState => Debug.LogFormat("Going into state: {0}", newState)); sm.onAfterTransition += (from, to) => Debug.LogFormat( "Move from {0} to {1}", DbgFormatter.Nullable(from), DbgFormatter.Nullable(to)); sm.currentState = State.One; // Start the machine. // Logs: // Now in state ONE // Move from NULL to One sm.currentState = State.Two; // Logs: // Going into state: Two // Move from One to Two sm.currentState = State.Three; // Logs: Move from Two to Three sm.currentState = null; // Stop the machine. // Logs: Move Three to NULL }
/// <inheritdoc/> public virtual bool CheckCanLinkTo(ILinkTarget target, bool checkStates = true, bool reportToGui = false, bool reportToLog = true) { var errors = new List <string>() .Concat(CheckBasicLinkConditions(target, checkStates)) .Concat(linkRenderer.CheckColliderHits(nodeTransform, target.nodeTransform)) .Concat(linkJoint.CheckConstraints(this, target)) .ToArray(); if (errors.Length > 0) { if (reportToGui || reportToLog) { HostedDebugLog.Warning( this, "Cannot link a part of type={0} with: part={1}, type={2}, errors={3}", cfgLinkType, target.part, target.cfgLinkType, DbgFormatter.C2S(errors)); } if (reportToGui) { ShowStatusMessage(DbgFormatter.C2S(errors, separator: "\n"), isError: true); } } return(errors.Length == 0); }
/// <summary>Disables/enables all the colliders between the parts.</summary> /// <remarks>The ignore state is reset to <c>false</c> on every scene load.</remarks> /// <param name="part1">Source part.</param> /// <param name="part2">Target part.</param> /// <param name="ignore"> /// If <c>true</c> then the collisions between the parts will be ignored. Otherwise, the /// collisions will be handled. /// </param> /// <seealso href="https://docs.unity3d.com/ScriptReference/Collider.html"> /// Unity3D: Collider</seealso> /// <seealso href="https://docs.unity3d.com/ScriptReference/Physics.IgnoreCollision.html"> /// Unity3D: Physics.IgnoreCollision</seealso> public static void SetCollisionIgnores(Part part1, Part part2, bool ignore) { Debug.LogFormat("Set collision ignores between {0} and {1} to {2}", DbgFormatter.PartId(part1), DbgFormatter.PartId(part2), ignore); SetCollisionIgnores( Hierarchy.GetPartModelTransform(part1), Hierarchy.GetPartModelTransform(part2), ignore); }
/// <inheritdoc/> public override void OnDebugAdjustablesUpdated() { base.OnDebugAdjustablesUpdated(); if (isLinked) { var checks = CheckConstraints(linkSource, linkTarget); if (checks.Length == 0) { // Given all checks are green, we can simply recreate the joint to update it. HostedDebugLog.Warning( this, "New settings fit the current link. Refreshing the joint..."); DropJoint(); CreateJoint(dbgLinkSource, dbgLinkTarget); } else { // STOP! The joint, once broken, won't re-establish with the new settings. HostedDebugLog.Warning(this, "New settings DON'T fit the current link:\n{0}" + "\n\nNot refershing the joint, re-link manually to update.", DbgFormatter.C2S(checks, separator: "\n")); } } else { // No joint, not update. However, it makes sense to note it. HostedDebugLog.Warning( this, "No link esatblished, only update the module settings"); } }
/// <summary>Adds default items to the pod's seats.</summary> /// <remarks>Items are only added to a part created in the editor. Thus, reacting on the editor /// event.</remarks> /// <param name="type">Unused.</param> /// <param name="p">A target part.</param> void OnEditPartCreate(ConstructionEventType type, Part p) { if (type != ConstructionEventType.PartCreated && type != ConstructionEventType.PartCopied) { return; } var inventories = p.GetComponents <ModuleKISInventory>(); foreach (var inventory in inventories) { if (inventory.podSeat == 0 && ModuleKISInventory.defaultItemsForTheFirstSeat.Count > 0) { Debug.LogFormat("Adding default item(s) into the first seat of part {0}: {1}", p.name, DbgFormatter.C2S(ModuleKISInventory.defaultItemsForTheFirstSeat)); AddItems(inventory, ModuleKISInventory.defaultItemsForTheFirstSeat); } if (inventory.podSeat != -1 && ModuleKISInventory.defaultItemsForAllSeats.Count > 0) { Debug.LogFormat( "Adding default item(s) into seat's {0} inventory of part {1}: {2}", inventory.podSeat, p.name, DbgFormatter.C2S(ModuleKISInventory.defaultItemsForAllSeats)); AddItems(inventory, ModuleKISInventory.defaultItemsForAllSeats); } } }
void LogObjectChildren(Transform objTransform) { Debug.Log(DbgFormatter.TranformPath(objTransform)); for (var i = 0; i < objTransform.transform.childCount; i++) { LogObjectChildren(objTransform.transform.GetChild(i)); } }
/// <summary>Throws if enum value is not in the expected set.</summary> /// <typeparam name="T">Type of value to check.</typeparam> /// <param name="arg">The value to check.</param> /// <param name="message">An optional message to present in the error.</param> /// <param name="context">The optional "owner" object.</param> /// <param name="values">The acceptable values of the enum.</param> /// <exception cref="InvalidOperationException">If condition fails.</exception> public static void OneOf <T>(T arg, T[] values, string message = null, object context = null) { if (!values.Contains(arg)) { throw new InvalidOperationException( Preconditions.MakeContextError( context, "Not one of: {1}. {2}", DbgFormatter.C2S(values), message)); } }
/// <summary>Throws if enum value is not in the expected set.</summary> /// <typeparam name="T">Type of value to check.</typeparam> /// <param name="arg">The argument value to check.</param> /// <param name="argName">The argument name.</param> /// <param name="values">The acceptable values of the enum.</param> /// <param name="message">An optional message to present in the error.</param> /// <param name="context">The optional "owner" object.</param> /// <exception cref="ArgumentOutOfRangeException"> /// If the argument is not one of the specified. /// </exception> public static void OneOf <T>(T arg, string argName, T[] values, string message = null, object context = null) { if (!values.Contains(arg)) { throw new ArgumentOutOfRangeException( argName, arg, Preconditions.MakeContextError( context, "Not one of: {1}. {2}", DbgFormatter.C2S(values), message)); } }
/// <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)); }
/// <summary>Finds a transform in the hirerachy by the provided path.</summary> /// <remarks> /// Every element of the path may specify an exact transform name or a partial match pattern: /// <list type="bullet"> /// <item> /// <c>*</c> - any name matches. Such patterns can be nested to specify the desired level of /// nesting. E.g. <c>*/*/a</c> will look for name <c>a</c> in the grandchildren. /// </item> /// <item> /// <c>*</c> as a prefix - the name is matched by suffix. E.g. <c>*a</c> matches any name that /// ends with <c>a</c>. /// </item> /// <item> /// <c>*</c> as a suffix - the name is matched by prefix. E.g. <c>a*</c> matches any name that /// starts with <c>a</c>. /// </item> /// <item> /// <c>**</c> - any <i>path</i> matches. What will eventually be found depends on the pattern to /// the right of <c>**</c>. The path match pattern does a "breadth-first" search, i.e. it tries to /// find the shortest path possible. E.g. <c>**/a/b</c> will go through all the nodes starting /// from the parent until path <c>a/b</c> is found. Be careful with this pattern since in case of /// not matching anything it will walk thought the <i>whole</i> hirerachy. /// </item> /// </list> /// <para> /// All patterns except <c>**</c> may have a matching index. It can be used to resolve matches /// when there are multiple objects found with the same name and at the <i>same level</i>. E.g. if /// there are two objects with name "a" at the root level then the first one can be accessed by /// pattern <c>a:0</c>, and the second one by pattern <c>a:1</c>. /// </para> /// <para> /// Path search is <i>slow</i> since it needs walking though the hierarchy nodes. In the worst /// case all the nodes will be visited. Don't use this method in the performance demanding /// methods. /// </para> /// </remarks> /// <param name="parent">The transfrom to start looking from.</param> /// <param name="path">The path elements. All the special symbols must be unescaped.</param> /// <param name="defValue"> /// An object to return if the path is not found. This situation will be treated as a danger, and /// a warning log record will be made. /// </param> /// <returns>Transform or <c>null</c> if nothing found.</returns> /// <example> /// Given the following hierarchy: /// <code lang="c++"><![CDATA[ /// // a /// // + b /// // | + c /// // | | + c1 /// // | | + d /// // | + c /// // | + d /// // | + e /// // | + e1 /// // + abc /// ]]></code> /// <para>The following pattern/output will be possible:</para> /// <code><![CDATA[ /// // a/b/c/d/e/e1 => node "e1" /// // a/b/*/d/e/e1 => node "e1" /// // a/b/*/*/e/e1 => node "e1" /// // a/b/c/c1 => node "с1" /// // a/b/*:0 => branch "a/b/c/c1", node "c" /// // a/b/*:1 => branch "a/b/c/d/e/e1", node "c" /// // a/b/c:1/d => branch "a/b/c/d/e/e1", node "d" /// // **/e1 => node "e1" /// // **/c1 => node "c1" /// // **/c/d => AMBIGUITY! The first found branch will be taken /// // a/**/e1 => node "e1" /// // *bc => node "abc" /// // ab* => node "abc" /// // *b* => node "abc" /// ]]></code> /// </example> /// <seealso cref="UnescapeName"/> /// <include file="Unity3D_HelpIndex.xml" path="//item[@name='T:UnityEngine.Transform']/*"/> public static Transform FindTransformByPath(Transform parent, string[] path, Transform defValue = null) { var obj = FindTransformByPathInternal(parent, path); if (obj == null && defValue != null) { HostedDebugLog.Warning(parent, "Cannot find path: {0}. Using a fallback: {1}", MakePath(path), DbgFormatter.TranformPath(defValue)); return(defValue); } return(obj); }
/// <summary>Updates data in all the open part menus.</summary> public static void LocalizePartMenus() { // The editor's tooltip caches the data, and we cannot update it. So just reset it. if (HighLogic.LoadedSceneIsEditor) { UIMasterController.Instance.DestroyCurrentTooltip(); } UnityEngine.Object.FindObjectsOfType(typeof(UIPartActionWindow)) .OfType <UIPartActionWindow>() .ToList() .ForEach(m => { Debug.LogFormat("Localize menu for part {0}", DbgFormatter.PartId(m.part)); m.titleText.text = m.part.partInfo.title; }); }
/// <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 debug dialog for the parts.</summary> /// <remarks> /// Implement a code that would react on user interactions and invoke this method to show a debug /// dialog. The dialog can be bound to a specific part, in which case it only showns for that /// part, or the dialog may allow interactively selecting a part from the scene. /// </remarks> /// <param name="title">The titile of the dialog.</param> /// <param name="dialogWidth"> /// The width of the dialog. If omitted, then the code will decide. /// </param> /// <param name="valueColumnWidth"> /// The width of the value changing controls. If omitted, then the code will decide. /// </param> /// <param name="group"> /// The group of the controls to present. If empty, then all the controls are shown. /// </param> /// <param name="bindToPart"> /// The part to attach the dialog to. If set, then the dialog won't allow changing the part via /// GUI. Otherwise, there will be controls in the dialog that allow selection a part from the /// scene. /// </param> /// <returns>The created dialog.</returns> /// <seealso cref="DestroyPartDebugDialog"/> /// <seealso cref="DebugAdjustableAttribute"/> public static PartDebugAdjustmentDialog MakePartDebugDialog( string title, float?dialogWidth = null, float?valueColumnWidth = null, string group = "", Part bindToPart = null) { if (bindToPart != null) { title += " : " + DbgFormatter.PartId(bindToPart); } var dlg = dialogsRoot.AddComponent <PartDebugAdjustmentDialog>(); dlg.dialogTitle = title; dlg.dialogWidth = dialogWidth ?? dlg.dialogWidth; dlg.dialogValueSize = valueColumnWidth ?? dlg.dialogValueSize; dlg.controlsGroup = group; if (bindToPart != null) { dlg.lockToPart = true; dlg.SetPart(bindToPart); } DebugEx.Info("Created debug dialog: {0}", title); return(dlg); }
public void TestMachine() { var sm = new SimpleStateMachine <State>(strict: false); sm.AddStateHandlers( State.One, enterHandler: oldState => Debug.Log("Now in state ONE"), leaveHandler: newState => Debug.LogFormat("Going into state: {0}", newState)); sm.onBeforeTransition += (from, to) => Debug.LogFormat( "Before move: current={0}, new={1}", DbgFormatter.Nullable(sm.currentState), DbgFormatter.Nullable(to)); sm.onAfterTransition += (from, to) => Debug.LogFormat( "After move: old={0}, current={1}", DbgFormatter.Nullable(from), DbgFormatter.Nullable(sm.currentState)); sm.currentState = State.One; // Start the machine. // Logs: // Now in state ONE // Before move: current=NULL, new=One // After move: old=NULL, current=One sm.currentState = State.Two; // Logs: // Going into state: Two // Before move: current=One, new=Two // After move: old=One, current=Two sm.currentState = State.Three; // Logs: // Before move: current=Two, new=Three // After move: old=Two, current=Three sm.currentState = null; // Stop the machine. // Logs: // Before move: current=Three, new=NULL // After move: old=Three, current=NULL }
void WaitAndApplyTweaks() { var roots = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects(); foreach (var root in roots) { if (logAllObjects) { LogObjectChildren(root.transform); } foreach (var tweak in modelTweaks) { var names = tweak.modelNamePattern.Split('/'); var reducedNames = names.Skip(1).ToArray(); // Try first name part separately since the scene objects don't have a single root. if (names[0] == "**") { reducedNames = names; // Try all children in the root. } else if (!Hierarchy.PatternMatch(names[0], root.transform.name)) { continue; } var objTransform = Hierarchy.FindTransformByPath(root.transform, reducedNames); if (objTransform != null) { Debug.LogFormat("Tweak '{0}' matched kerbal model: {1}", tweak.tweakName, DbgFormatter.TranformPath(objTransform)); tweak.itemNames.ToList().ForEach(x => { var item = new TweakEquippableItem(x, tweak.matchMeshesBySuffix); item.ApplyTweak(objTransform.gameObject); sceneTweaks.Add(item); }); } } } }
/// <inheritdoc/> public string DumpJoint(ConfigurableJoint joint) { if (joint == null) { return("<NULL JOINT>"); } var msg = DumpBaseJoint(joint); // Geometry. msg.Append("secondaryAxis: ").Append(DbgFormatter.Vector(joint.secondaryAxis)).AppendLine(); // X axis settings. msg.Append("xDrive: ").Append(Dump(joint.xDrive)).AppendLine(); msg.Append("xMotion: ").Append(joint.xMotion).AppendLine(); msg.Append("angularXMotion: ").Append(joint.angularXMotion).AppendLine(); msg.Append("angularXLimitSpring: ").Append(Dump(joint.angularXLimitSpring)).AppendLine(); msg.Append("angularXDrive: ").Append(Dump(joint.angularXDrive)).AppendLine(); msg.Append("lowAngularXLimit: ").Append(Dump(joint.lowAngularXLimit)).AppendLine(); msg.Append("highAngularXLimit: ").Append(Dump(joint.highAngularXLimit)).AppendLine(); // Y axis settings. msg.Append("yDrive: ").Append(Dump(joint.yDrive)).AppendLine(); msg.Append("yMotion: ").Append(joint.yMotion).AppendLine(); msg.Append("angularYMotion: ").Append(joint.angularYMotion).AppendLine(); msg.Append("angularYLimit: ").Append(Dump(joint.angularYLimit)).AppendLine(); // Z axis settings. msg.Append("zDrive: ").Append(Dump(joint.zDrive)).AppendLine(); msg.Append("zMotion: ").Append(joint.zMotion).AppendLine(); msg.Append("angularZMotion: ").Append(joint.angularZMotion).AppendLine(); msg.Append("angularZLimit: ").Append(Dump(joint.angularZLimit)).AppendLine(); // Multiple axis settings. msg.Append("linearLimit: ").Append(Dump(joint.linearLimit)).AppendLine(); msg.Append("linearLimitSpring: ").Append(Dump(joint.linearLimitSpring)).AppendLine(); msg.Append("angularYZDrive: ").Append(Dump(joint.angularYZDrive)).AppendLine(); msg.Append("angularYZLimitSpring: ").Append(Dump(joint.angularYZLimitSpring)).AppendLine(); return(msg.ToString()); }
/// <summary>Invokes a callback with the original value of an attribute argument.</summary> /// <param name="member">The attributed member.</param> /// <param name="attrType">The type of the attribute.</param> /// <param name="argName">The name of the attribute argument.</param> /// <param name="setupFn"> /// The callback that is called if the specified argument in the attribute is found. /// </param> static void SetupArgumentFromAttribute( MemberInfo member, Type attrType, string argName, Action <string> setupFn) { var fieldAttr = member.CustomAttributes.FirstOrDefault(x => x.AttributeType == attrType); if (fieldAttr == null) { DebugEx.Error("Attribute not found: attrType={0}, member={1}.{2}", attrType, member.DeclaringType, member.Name); return; } var namedArgument = fieldAttr.NamedArguments? .FirstOrDefault(x => x.MemberName == argName); if (namedArgument == null) { DebugEx.Error("Cannot fetch named argument: attrType={0}, member={1}.{2}, argName={3}", attrType, member.DeclaringType, member.Name, argName); DebugEx.Warning("Available arguments for attribute {0}: {1}", DbgFormatter.C2S(fieldAttr.NamedArguments, predicate: x => x.MemberName)); return; } setupFn((string)namedArgument.Value.TypedValue.Value); }
/// <summary>Shows a window that displays the winch controls.</summary> /// <param name="windowId">Window ID.</param> void ConsoleWindowFunc(int windowId) { MakeGuiStyles(); if (guiActions.ExecutePendingGuiActions()) { if (parentPartTracking) { SetPart(Mouse.HoveredPart); } if (parentPartTracking && Input.GetMouseButtonDown(0)) { parentPartTracking = false; } } using (new GUILayout.VerticalScope(GUI.skin.box)) { using (new GuiEnabledStateScope(!parentPartTracking)) { if (GUILayout.Button("Set part")) { guiActions.Add(() => parentPartTracking = true); } } using (new GuiEnabledStateScope(parentPartTracking)) { if (GUILayout.Button("Cancel set mode...")) { guiActions.Add(() => parentPartTracking = false); } } var parentPartName = "Part: " + (parentPart != null ? DbgFormatter.PartId(parentPart) : "NONE"); GUILayout.Label(parentPartName, guiNoWrapStyle); } if (parentPart != null && itemModule != null && (itemModule.equipable || itemModule.carriable)) { GUILayout.Label("KIS Item detected:"); using (new GUILayout.VerticalScope(GUI.skin.box)) { using (new GUILayout.HorizontalScope(GUI.skin.box)) { GUILayout.Label("Equip pos (metres):", guiCaptionStyle); GUILayout.FlexibleSpace(); itemModule.equipPos = itemPosition.UpdateFrame( itemModule.equipPos, guiValueStyle, new[] { GUILayout.Width(100) }); } using (new GUILayout.HorizontalScope(GUI.skin.box)) { GUILayout.Label("Equip dir (euler degrees):", guiCaptionStyle); GUILayout.FlexibleSpace(); itemModule.equipDir = itemDirection.UpdateFrame( itemModule.equipDir, guiValueStyle, new[] { GUILayout.Width(100) }); } } } if (GUILayout.Button("Close", GUILayout.ExpandWidth(false))) { guiActions.Add(() => isGUIOpen = false); } // Allow the window to be dragged by its title bar. GuiWindow.DragWindow(ref windowRect, titleBarRect); }
/// <summary>Shows a window that displays the winch controls.</summary> /// <param name="windowId">Window ID.</param> void ConsoleWindowFunc(int windowId) { if (guiActions.ExecutePendingGuiActions()) { if (parentPartTracking && Input.GetMouseButtonDown(0) && !windowRect.Contains(Mouse.screenPos)) { SetPart(Mouse.HoveredPart); parentPartTracking = false; } } string parentPartName = parentPart != null?DbgFormatter.PartId(parentPart) : "NONE"; if (!lockToPart) { if (GUILayout.Button(!parentPartTracking ? "Set part" : "Cancel set mode...")) { guiActions.Add(() => { parentPartTracking = !parentPartTracking; }); } if (parentPartTracking && Mouse.HoveredPart != null) { parentPartName = "Select: " + DbgFormatter.PartId(Mouse.HoveredPart); } GUILayout.Label(parentPartName, new GUIStyle(GUI.skin.box) { wordWrap = true }); } // Render the adjustable fields. if (parentPart != null && adjustableModules != null) { if (adjustableModules.Length > 0) { mainScrollView.BeginView(GUI.skin.box, Screen.height - 200); for (var i = 0; i < adjustableModules.Length; i++) { var isSelected = selectedModule == i; var module = adjustableModules[i]; var toggleCaption = (isSelected ? "\u25b2 " : "\u25bc ") + "Module: " + module.Key; if (GUILayout.Button(toggleCaption)) { var selectedModuleSnapshot = selectedModule == i ? -1 : i; // Make a copy for lambda! guiActions.Add(() => selectedModule = selectedModuleSnapshot); } if (isSelected) { foreach (var control in module.Value) { control.RenderControl( guiActions, GUI.skin.label, new[] { GUILayout.Width(dialogValueSize) }); } } } mainScrollView.EndView(); } else { GUILayout.Box("No adjustable members found"); } } if (GUILayout.Button("Close", GUILayout.ExpandWidth(false))) { guiActions.Add(() => DebugGui.DestroyPartDebugDialog(this)); } // Allow the window to be dragged by its title bar. GuiWindow.DragWindow(ref windowRect, titleBarRect); }
/// <summary>Shows a human readable representation.</summary> /// <returns>String value.</returns> public override string ToString() { return(string.Format( "[PosAndRot Pos={0}, Euler={1}]", DbgFormatter.Vector(pos), DbgFormatter.Vector(euler))); }
void LogFromTo(State?from, State?to) { Debug.LogFormat( "Move from {0} to {1}", DbgFormatter.Nullable(from), DbgFormatter.Nullable(to)); }