Metal666.GodotUtilities
0.3.0
Prefix Reserved
dotnet add package Metal666.GodotUtilities --version 0.3.0
NuGet\Install-Package Metal666.GodotUtilities -Version 0.3.0
<PackageReference Include="Metal666.GodotUtilities" Version="0.3.0" />
paket add Metal666.GodotUtilities --version 0.3.0
#r "nuget: Metal666.GodotUtilities, 0.3.0"
// Install Metal666.GodotUtilities as a Cake Addin #addin nuget:?package=Metal666.GodotUtilities&version=0.3.0 // Install Metal666.GodotUtilities as a Cake Tool #tool nuget:?package=Metal666.GodotUtilities&version=0.3.0
GodotUtilities
A set of utilities I use in my Godot projects.
Features
Architecture
Singletons - turn custom Nodes into Singletons by adding the
Singleton
attribute.The included source generator will add the
Instance
property + a parameterless constructor, where it is set.State (experimental) - use the
State
attribute to mark static classes as states.The following things will be generated for each private field in the state:
A public property
Use it to modify the field.
An
On<Property>Changed
eventInvoked when a property is set.
An interface with a single
On<Property>Changed
method.Implement it on any node and the method will be automatically called when the property is changed.
Logging
A modular logging system is available. In order to log a message, call the Log
method on the static LogManager
class. By default, the message will be processed by 2 loggers:
EditorLogger
(activated when running the game from the editor)Prints the message to the Godot console using one of the
GD.PrintRich
/GD.PushWarning
/GD.PushError
(based on the message log level).ConsoleLogger
(activated when running the game standalone)Prints the message using
Console.WriteLine
.
When logging, parameters such as logLevel
, sourceType
and indentation
can be specified to format the output.
Loggers extend a base LoggerBase
class. If you need to implement a custom logging solution you can extend either of the stock loggers, or the base class. Then you can override the available methods and properties to change how the message is processed and output. Finally, set the Loggers
value on the LogManager
class (overriding the default loggers).
Two additional logging features are available:
Extension methods
A vast selection of extension methods are available for convenient logging. For example, if you call the
LogMessage
extension method, the object'sType
will be automatically passed as thesourceType
parameter and the log level will be set toLogLevel.Message
. All extension methods are contained inside the staticLogging
class inside theMetal666.GodotUtilities.Extensions
namespace.LogSource
attributeAttach it to a custom node class, and specify the
Color
property (use HTML color names, such asred
). When a log arrives with that node's type as thesourceType
, the output will be colored using the specified color. TheEditorLogger
will use the[color]
BBCode
, while theConsoleLogger
will convert the color to the closestConsoleColor
enum value and set theConsole.ForegroundColor
.
Networking
LocalInstanceController
This class can be used as an alternative to the "Launch multiple instances" editor function. Use the
Initialize
method to spawn additional game instances. At the moment it is rather basic and doesn't offer much benefit over the editor functionality. I will be extending it with more features in the future.
Input
MouseContext
This is a wrapper around
Input.MouseMode
. When you call theChangeMouseMode
method, the current mouse mode is added to a stack collection. You can callRevertMouseMode
to go backwards through the stack and apply previous mouse modes. This is useful if you have a complex UI setup where different view/overlays/windows require different mouse modes. You can callChangeMouseMode
when a new view opens andRevertMouseMode
when it closes.Additionally, you can use the
PauseMouseModeUpdates
andResumeMouseModeUpdates
methods to temporarily stop the mouse mode from being applied (the stack will still have values added/removed from it). This can be useful when the game is minimized or the user is alt-tabbed and you don't want to mess with their mouse. To retrieve the "intended" mouse mode use theCurrentMouseMode
property.The
MouseContext
class can be instantiated, or you can use the staticMouseContext.Global
version of it. You can set theLogEvents
property totrue
to enable logging.
Extension methods
- Controls
Range.ValueF()
- retrieve the value of aRange
node as afloat
.Range.ValueI()
- retrieve the value of aRange
node as a roundedint
.Tree.SetColumn(int index, TreeColumnData treeColumnData)
- a shortcut toTree.SetColumn*
methods. Set all column properties with a single object.Tree.SetColumns(IEnumerable<TreeColumnData> treeColumnDatas)
- sets all Tree columns using the above method.
- LINQ
IEnumerable.If(bool condition, Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
- branches inside LINQ chains.
- Math
- Direct shortcuts to
Mathf
functions:float.Lerp(float to, float weight)
,float.Lerp(float to, double weight)
,double.Lerp(double to, double weight)
.float.MoveToward(float to, float delta)
,float.MoveToward(float to, double delta)
,double.MoveToward(double to, double delta)
.float.LerpAngle(float to, float weight)
,float.LerpAngle(float to, double weight)
,double.LerpAngle(double to, double weight)
.int.Abs()
,float.Abs()
,double.Abs()
.int.Clamp(int min, int max)
,float.Clamp(float min, float max)
,double.Clamp(double min, double max)
.int.Wrap(int min, int max)
,float.Wrap(float min, float max)
,double.Wrap(double min, double max)
.int.PosMod(int a, int b)
,float.PosMod(float a, float b)
,double.PosMod(double a, double b)
.float.AngleDifference(float to)
,double.AngleDifference(double to)
.float.IsZeroApprox()
,double.IsZeroApprox()
.float.IsEqualApprox(float to)
,double.IsEqualApprox(double to)
,float.IsEqualApprox(float to, float tolerance)
,double.IsEqualApprox(double to, double tolerance)
.int.ToDeg()
,float.ToDeg()
,double.ToDeg()
.int.ToRad()
,float.ToRad()
,double.ToRad()
.float.RoundToInt()
,float.FloorToInt()
,float.CeilToInt()
.double.RoundToInt()
,double.FloorToInt()
,double.CeilToInt()
.
- Extra shortcuts:
int.Clamp(Vector2I range)
,float.Clamp(Vector2 range)
- clamps using vector components as min/max values.int.Wrap360Deg()
,float.Wrap360Deg()
,double.Wrap360Deg()
- usesPosMod
to ensure the angle is in range [0, 360).float.Wrap360Rad()
,double.Wrap360Rad()
- usesPosMod
to ensure the angle is in range [0,Mathf.Tau
).int.SignedWrap360Deg()
,float.SignedWrap360Deg()
,double.SignedWrap360Deg()
- usesWrap
to ensure the angle is in range [-180, 180).float.SignedWrap360Rad()
,double.SignedWrap360Rad()
- usesWrap
to ensure the angle is in range [-Mathf.Pi
,Mathf.Pi
).int.Wrap720Deg()
,float.Wrap720Deg()
,double.Wrap720Deg()
- usesPosMod
to ensure the angle is in range [0, 720).float.Wrap720Rad()
,double.Wrap720Rad()
- usesPosMod
to ensure the angle is in range [0,Mathf.Tau * 2
).int.SignedWrap720Deg()
,float.SignedWrap720Deg()
,double.SignedWrap720Deg()
- usesWrap
to ensure the angle is in range [-360, 360).float.SignedWrap720Rad()
,double.SignedWrap720Rad()
- usesWrap
to ensure the angle is in range [-Mathf.Tau
,Mathf.Tau
).float.AngleDifferenceAbs(float to)
,double.AngleDifferenceAbs(double to)
- callsAngleDifference
thenAbs
.float.DifferenceAbs(float to)
,double.DifferenceAbs(double to)
- callsAbs
onvalue - to
.Vector2.Get(Vector2.Axis axis)
,Vector3.Get(Vector3.Axis axis)
- gets the vector component specified byaxis
.Vector2.IsEqualApprox(Vector2 vector, float tolerance)
,Vector3.IsEqualApprox(Vector3 vector, float tolerance)
- compare vectors with tolerance.Vector2.CopyWith(float? x = null, float? y = null)
,Vector2I.CopyWith(int? x = null, int? y = null)
,Vector3.CopyWith(float? x = null, float? y = null, float? z = null)
,Vector3I.CopyWith(int? x = null, int? y = null, int? z = null)
- returns a copy of the vector with the specified components replaced.Vector2.CopyWith(Vector2.Axis axis, float value)
,Vector2I.CopyWith(Vector2I.Axis axis, int value)
,Vector3.CopyWith(Vector3.Axis axis, float value)
,Vector3I.CopyWith(Vector3I.Axis axis, int value)
- returns a copy of the vector with the component, specified by theaxis
, replaced.Vector3.Lerp(Vector3 to, double weight)
,Vector2.Lerp(Vector2 to, double weight)
- callsvector.Lerp
withweight
cast tofloat
.Vector3.MoveToward(Vector3 to, double weight)
,Vector2.MoveToward(Vector2 to, double weight)
- callsvector.MoveToward
withdelta
cast tofloat
.Vector3.RotatedDeg(Vector3 axis, float angle)
- callsVector3.Rotated
withangle
converted to radians.Vector3.FlattenX()
,Vector3.FlattenY()
,Vector3.FlattenZ()
,Vector3I.FlattenX()
,Vector3I.FlattenY()
,Vector3I.FlattenZ()
- converts a 3D vector to a 2D one by removing the specified component.Vector2.AddXComponent(float x = 0)
,Vector2.AddYComponent(float y = 0)
,Vector2.AddZComponent(float z = 0)
,Vector2I.AddXComponent(int x = 0)
,Vector2I.AddYComponent(int y = 0)
,Vector2I.AddZComponent(int z = 0)
- converts a 2D vector to a 3D one by inserting the specified component.Vector2.ToDeg()
,Vector3.ToDeg()
,Vector2.ToRad()
,Vector3.ToRad()
- returns a copy of the vector with all components converted to degrees/radians.Vector2.RoundToInt()
,Vector2.FloorToInt()
,Vector2.CeilToInt()
,Vector3.RoundToInt()
,Vector3.FloorToInt()
,Vector3.CeilToInt()
- returns a copy of the vector with all components rounded/floored/ceiled to integer values.Vector2.UnsignedAngleTo(Vector2 to)
- callsvector.AngleTo
thenAbs
.Vector2.Swap()
,Vector2I.Swap()
- returns a copy of the vector with X and Y components swapped.Vector3.OverwriteXY(Vector2 with)
,Vector3.OverwriteXZ(Vector2 with)
,Vector3.OverwriteYZ(Vector2 with)
,Vector3I.OverwriteXY(Vector2I with)
,Vector3I.OverwriteXZ(Vector2I with)
,Vector3I.OverwriteYZ(Vector2I with)
- returns a copy of the vector with the specified components replaced with the components from a 2D vector.Vector2.ElementWiseProduct(Vector2 other)
,Vector3.ElementWiseProduct(Vector3 other)
,Vector2I.ElementWiseProduct(Vector2I other)
,Vector3I.ElementWiseProduct(Vector3I other)
- performs element-wise multiplication of the vectors.Vector3.ClampX(int min, int max)
,Vector3.ClampX(float min, float max)
,Vector3.ClampX(double min, double max)
,Vector3.ClampY(int min, int max)
,Vector3.ClampY(float min, float max)
,Vector3.ClampY(double min, double max)
,Vector3.ClampZ(int min, int max)
,Vector3.ClampZ(float min, float max)
,Vector3.ClampZ(double min, double max)
,Vector3I.ClampX(int min, int max)
,Vector3I.ClampY(int min, int max)
,Vector3I.ClampZ(int min, int max)
,Vector2.ClampX(int min, int max)
,Vector2.ClampX(float min, float max)
,Vector2.ClampX(double min, double max)
,Vector2.ClampY(int min, int max)
,Vector2.ClampY(float min, float max)
,Vector2.ClampY(double min, double max)
,Vector2I.ClampX(int min, int max)
,Vector2I.ClampY(int min, int max)
- returns a copy of the vector with the specified component clamped between themin
andmax
value.Curve.Sample(double offset)
- callscurve.Sample
withoffset
cast tofloat
.
- Direct shortcuts to
- Physics
CollisionShape2D.Shape<TShape>()
,CollisionShape3D.Shape<TShape>()
- returnscollider.Shape
cast toTShape
.CollisionShape2D.GetLength(Vector2.Axis axis = Vector2.Axis.Y)
,CollisionShape3D.GetLength(Vector3.Axis axis = Vector3.Axis.Y)
- returns the length of the collider:- For 2D shapes:
SeparationRayShape2D
- theLength
property.RectangleShape2D
- a component of theSize
property, specified by theaxis
.CircleShape2D
- theRadius
property.CapsuleShape2D
- ifaxis
is Y, returns theHeight
property. Otherwise returns theRadius
property.
- For 3D shapes:
SeparationRayShape3D
- theLength
property.BoxShape3D
- a component of theSize
property, specified by theaxis
.SphereShape3D
- theRadius
property.CapsuleShape3D
,CylinderShape3D
- ifaxis
is Y, returns theHeight
property. Otherwise returns theRadius
property.
- For 2D shapes:
CollisionShape2D.SetLength(float length, Vector2.Axis axis = Vector2.Axis.Y)
,CollisionShape3D.SetLength(float length, Vector3.Axis axis = Vector3.Axis.Y)
- sets the length of the collider; property to set is determined using the process above.Node3D.RayCast(PhysicsRayQueryParameters3D parameters)
- performsPhysicsDirectSpaceState3D.IntersectRay
. Returns a strongly typedRaycastResult3D
object.Node2D.RayCast(PhysicsRayQueryParameters2D parameters)
- performsPhysicsDirectSpaceState2D.IntersectRay
. Returns a strongly typedRaycastResult2D
object.Node3D.TryRayCast(PhysicsRayQueryParameters3D parameters, out RaycastResult3D result)
- same asNode3D.RayCast
but via aTryGet
pattern.Node2D.TryRayCast(PhysicsRayQueryParameters2D parameters, out RaycastResult2D result)
- same asNode2D.RayCast
but via aTryGet
pattern.
- Threading
Action.InvokeOnMainThread()
(+ 16 overloads) - a shortcut toCallable.From(action).CallDeferred()
.
- Transforms
Node2D.RotateDeg(int angle)
,Node2D.RotateDeg(float angle)
,Node2D.RotateDeg(double angle)
- callsNode2D.Rotate
withangle
converted to radians.Node3D.RotateDeg(Vector3 axis, int angle)
,Node3D.RotateDeg(Vector3 axis, float angle)
,Node3D.RotateDeg(Vector3 axis, double angle)
- callsNode3D.Rotate
withangle
converted to radians.Node3D.RotateXDeg(int angle)
,Node3D.RotateXDeg(float angle)
,Node3D.RotateXDeg(double angle)
,Node3D.RotateYDeg(int angle)
,Node3D.RotateYDeg(float angle)
,Node3D.RotateYDeg(double angle)
,Node3D.RotateZDeg(int angle)
,Node3D.RotateZDeg(float angle)
,Node3D.RotateZDeg(double angle)
- callsNode3D.Rotate*
withangle
converted to radians.Node3D.SetXRotation(int angle)
,Node3D.SetXRotation(float angle)
,Node3D.SetXRotation(double angle)
,Node3D.SetYRotation(int angle)
,Node3D.SetYRotation(float angle)
,Node3D.SetYRotation(double angle)
,Node3D.SetZRotation(int angle)
,Node3D.SetZRotation(float angle)
,Node3D.SetZRotation(double angle)
,Node3D.SetXRotationDeg(int angle)
,Node3D.SetXRotationDeg(float angle)
,Node3D.SetXRotationDeg(double angle)
,Node3D.SetYRotationDeg(int angle)
,Node3D.SetYRotationDeg(float angle)
,Node3D.SetYRotationDeg(double angle)
,Node3D.SetZRotationDeg(int angle)
,Node3D.SetZRotationDeg(float angle)
,Node3D.SetZRotationDeg(double angle)
,Node3D.SetXRotationGlobal(int angle)
,Node3D.SetXRotationGlobal(float angle)
,Node3D.SetXRotationGlobal(double angle)
,Node3D.SetYRotationGlobal(int angle)
,Node3D.SetYRotationGlobal(float angle)
,Node3D.SetYRotationGlobal(double angle)
,Node3D.SetZRotationGlobal(int angle)
,Node3D.SetZRotationGlobal(float angle)
,Node3D.SetZRotationGlobal(double angle)
,Node3D.SetXRotationDegGlobal(int angle)
,Node3D.SetXRotationGlobalDeg(float angle)
,Node3D.SetXRotationGlobalDeg(double angle)
,Node3D.SetYRotationGlobalDeg(int angle)
,Node3D.SetYRotationGlobalDeg(float angle)
,Node3D.SetYRotationGlobalDeg(double angle)
,Node3D.SetZRotationGlobalDeg(int angle)
,Node3D.SetZRotationGlobalDeg(float angle)
,Node3D.SetZRotationGlobalDeg(double angle)
,Node3D.SetXPosition(int angle)
,Node3D.SetXPosition(float angle)
,Node3D.SetXPosition(double angle)
,Node3D.SetYPosition(int angle)
,Node3D.SetYPosition(float angle)
,Node3D.SetYPosition(double angle)
,Node3D.SetZPosition(int angle)
,Node3D.SetZPosition(float angle)
,Node3D.SetZPosition(double angle)
,Node3D.SetXPositionGlobal(int angle)
,Node3D.SetXPositionGlobal(float angle)
,Node3D.SetXPositionGlobal(double angle)
,Node3D.SetYPositionGlobal(int angle)
,Node3D.SetYPositionGlobal(float angle)
,Node3D.SetYPositionGlobal(double angle)
,Node3D.SetZPositionGlobal(int angle)
,Node3D.SetZPositionGlobal(float angle)
,Node3D.SetZPositionGlobal(double angle)
,Node2D.SetXPosition(int angle)
,Node2D.SetXPosition(float angle)
,Node2D.SetXPosition(double angle)
,Node2D.SetYPosition(int angle)
,Node2D.SetYPosition(float angle)
,Node2D.SetYPosition(double angle)
,Node2D.SetXPositionGlobal(int angle)
,Node2D.SetXPositionGlobal(float angle)
,Node2D.SetXPositionGlobal(double angle)
,Node2D.SetYPositionGlobal(int angle)
,Node2D.SetYPositionGlobal(float angle)
,Node2D.SetYPositionGlobal(double angle)
- ... yea... I... I think you can tell what these methods do.
- Tree
Node.Unparent()
- self-explanatory.SceneTree.ChangeSceneToFileDeferred(string path, Action<Error>? callback = null)
- callsSceneTree.ChangeSceneToFile
in deferred mode. The return value is passed tocallback
(if provided).SceneTree.ChangeSceneToPackedDeferred(PackedScene packedScene, Action<Error>? callback = null)
- same as above, but forSceneTree.ChangeSceneToPacked
.Node.GetChildren<T>(bool includeInternal = false)
- callsnode.GetChildren(includeInternal)
then.OfType<T>()
.Node.GetChildrenOrThrow<T>(bool includeInternal = false)
- callsnode.GetChildren(includeInternal)
then.Cast<T>()
.
- Visual
Color.ToVector3()
- creates a vector from theR
,G
andB
values.Color.ToVector3I()
- creates a vector from theR8
,G8
andB8
values.
Additional utilities
- Access
Is.Editor
orIs.Standalone
to determine if the game was launched from the editor or not.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net6.0
- GodotSharp (>= 4.2.0)
- Metal666.GodotUtilities.SourceGenerators (>= 0.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.