Weapons/ToolGun/Modes/Motor/MotorTool.cs
[Hide]
[Title( "#tool.name.motor" )]
[Icon( "🔄" )]
[ClassName( "MotorTool" )]
[Group( "#tool.group.constraints" )]
public sealed class MotorTool : BaseConstraintToolMode
{
public override string Description => Stage == 1 ? "#tool.hint.motortool.stage1" : "#tool.hint.motortool.stage0";
public override string PrimaryAction => Stage == 1 ? "#tool.hint.motortool.finish" : "#tool.hint.motortool.source";
public override string ReloadAction => "#tool.hint.motortool.remove";
/// <summary>
/// The spin axis is the surface normal where you make the first selection - this flips it
/// 180 degrees, which is only useful in combination with <see cref="Reversed"/> and a limit range.
/// </summary>
[Property, Sync]
public bool FlipAxis { get; set; } = false;
[Property, Sync]
public bool Reversed { get; set; } = false;
protected override IEnumerable<GameObject> FindConstraints( GameObject linked, GameObject target )
{
foreach ( var joint in linked.GetComponentsInChildren<HingeJoint>( true ) )
if ( joint.GetComponent<MotorEntity>() is not null && (linked == target || joint.Body?.Root == target) )
yield return joint.GameObject;
}
protected override void CreateConstraint( SelectionPoint point1, SelectionPoint point2 )
{
if ( point1.GameObject == point2.GameObject )
return;
// The hinge spins around its anchor's local Up - build a rotation whose Up matches the
// normal at the first click (i.e. point at the surface you want to spin around).
var normal = point1.WorldTransform().Rotation.Forward * (FlipAxis ? -1f : 1f);
var reference = MathF.Abs( normal.Dot( Vector3.Up ) ) > 0.99f ? Vector3.Forward : Vector3.Up;
var axisForward = Vector3.Cross( reference, normal ).Normal;
var axisRotation = Rotation.LookAt( axisForward, normal );
var go1 = new GameObject( false, "motor_a" );
go1.Parent = point1.GameObject;
go1.WorldPosition = point1.WorldPosition();
go1.WorldRotation = axisRotation;
go1.Tags.Add( "constraint" );
var go2 = new GameObject( false, "motor_b" );
go2.Parent = point2.GameObject;
go2.WorldTransform = go1.WorldTransform;
go2.Tags.Add( "constraint" );
var cleanup = go1.AddComponent<ConstraintCleanup>();
cleanup.Attachment = go2;
var joint = go1.AddComponent<HingeJoint>();
joint.Attachment = Sandbox.Joint.AttachmentMode.Auto;
joint.Body = go2;
joint.EnableCollision = false;
var entity = go1.AddComponent<MotorEntity>();
entity.Reversed = Reversed;
entity.Joint = joint;
go2.NetworkSpawn( true, null );
go1.NetworkSpawn( true, null );
Track( go1, go2 );
var undo = Player.Undo.Create();
undo.Name = "Motor";
undo.Add( go1 );
undo.Add( go2 );
CheckContraptionStats( point1.GameObject );
}
}