Skip to content

Commit 5d883c6

Browse files
committed
feat: Add simplified extensions classes
1 parent 9728c01 commit 5d883c6

2 files changed

Lines changed: 256 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// <copyright file="ButtplugClientDeviceExtensions.cs" company="Nonpolynomial Labs LLC">
2+
// Buttplug C# Source Code File - Visit https://buttplug.io for more info about the project.
3+
// Copyright (c) Nonpolynomial Labs LLC. All rights reserved.
4+
// Licensed under the BSD 3-Clause license. See LICENSE file in the project root for full license information.
5+
// </copyright>
6+
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Buttplug.Core.Messages;
10+
11+
namespace Buttplug.Client
12+
{
13+
/// <summary>
14+
/// Extension methods for <see cref="ButtplugClientDevice"/> providing convenient shortcuts for common operations.
15+
/// </summary>
16+
public static class ButtplugClientDeviceExtensions
17+
{
18+
/// <summary>
19+
/// Sends a vibrate command to all vibration features on this device.
20+
/// </summary>
21+
/// <param name="device">The device.</param>
22+
/// <param name="percent">The vibration intensity (0.0 to 1.0).</param>
23+
/// <param name="token">Cancellation token.</param>
24+
/// <example>
25+
/// <code>
26+
/// await device.VibrateAsync(0.5); // Vibrate at 50%
27+
/// </code>
28+
/// </example>
29+
public static Task VibrateAsync(this ButtplugClientDevice device, double percent, CancellationToken token = default)
30+
{
31+
return device.RunOutputAsync(DeviceOutput.Vibrate.Percent(percent), token);
32+
}
33+
34+
/// <summary>
35+
/// Sends an oscillate command to all oscillation features on this device.
36+
/// </summary>
37+
/// <param name="device">The device.</param>
38+
/// <param name="percent">The oscillation intensity (0.0 to 1.0).</param>
39+
/// <param name="token">Cancellation token.</param>
40+
public static Task OscillateAsync(this ButtplugClientDevice device, double percent, CancellationToken token = default)
41+
{
42+
return device.RunOutputAsync(DeviceOutput.Oscillate.Percent(percent), token);
43+
}
44+
45+
/// <summary>
46+
/// Sends a rotate command to all rotation features on this device.
47+
/// </summary>
48+
/// <param name="device">The device.</param>
49+
/// <param name="percent">The rotation speed (0.0 to 1.0).</param>
50+
/// <param name="token">Cancellation token.</param>
51+
public static Task RotateAsync(this ButtplugClientDevice device, double percent, CancellationToken token = default)
52+
{
53+
return device.RunOutputAsync(DeviceOutput.Rotate.Percent(percent), token);
54+
}
55+
56+
/// <summary>
57+
/// Sends a position w/ duration command to all supported features on this device.
58+
/// </summary>
59+
/// <param name="device">The device.</param>
60+
/// <param name="percent">The target position (0.0 to 1.0).</param>
61+
/// <param name="durationMs">The duration in milliseconds to reach the position.</param>
62+
/// <param name="token">Cancellation token.</param>
63+
/// <example>
64+
/// <code>
65+
/// await device.PositionWithDurationAsync(1.0, 500); // Move to top over 500ms
66+
/// await device.PositionWithDurationAsync(0.0, 500); // Move to bottom over 500ms
67+
/// </code>
68+
/// </example>
69+
public static Task PositionWithDurationAsync(this ButtplugClientDevice device, double percent, uint durationMs, CancellationToken token = default)
70+
{
71+
return device.RunOutputAsync(DeviceOutput.PositionWithDuration.Percent(percent, durationMs), token);
72+
}
73+
74+
/// <summary>
75+
/// Sends a constrict command to all constriction features on this device.
76+
/// </summary>
77+
/// <param name="device">The device.</param>
78+
/// <param name="percent">The constriction level (0.0 to 1.0).</param>
79+
/// <param name="token">Cancellation token.</param>
80+
public static Task ConstrictAsync(this ButtplugClientDevice device, double percent, CancellationToken token = default)
81+
{
82+
return device.RunOutputAsync(DeviceOutput.Constrict.Percent(percent), token);
83+
}
84+
85+
/// <summary>
86+
/// Sends an inflate command to all inflation features on this device.
87+
/// </summary>
88+
/// <param name="device">The device.</param>
89+
/// <param name="percent">The inflation level (0.0 to 1.0).</param>
90+
/// <param name="token">Cancellation token.</param>
91+
public static Task InflateAsync(this ButtplugClientDevice device, double percent, CancellationToken token = default)
92+
{
93+
return device.RunOutputAsync(DeviceOutput.Inflate.Percent(percent), token);
94+
}
95+
}
96+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// <copyright file="ButtplugClientExtensions.cs" company="Nonpolynomial Labs LLC">
2+
// Buttplug C# Source Code File - Visit https://buttplug.io for more info about the project.
3+
// Copyright (c) Nonpolynomial Labs LLC. All rights reserved.
4+
// Licensed under the BSD 3-Clause license. See LICENSE file in the project root for full license information.
5+
// </copyright>
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
using Buttplug.Core.Messages;
13+
14+
namespace Buttplug.Client
15+
{
16+
/// <summary>
17+
/// Extension methods for <see cref="ButtplugClient"/> providing convenient shortcuts for common operations.
18+
/// </summary>
19+
public static class ButtplugClientExtensions
20+
{
21+
/// <summary>
22+
/// Connects to a Buttplug server using a WebSocket URI string.
23+
/// </summary>
24+
/// <param name="client">The client to connect.</param>
25+
/// <param name="uri">The WebSocket URI (e.g., "ws://localhost:12345").</param>
26+
/// <param name="token">Cancellation token.</param>
27+
/// <example>
28+
/// <code>
29+
/// var client = new ButtplugClient("My App");
30+
/// await client.ConnectAsync("ws://localhost:12345");
31+
/// </code>
32+
/// </example>
33+
public static Task ConnectAsync(this ButtplugClient client, string uri, CancellationToken token = default)
34+
{
35+
return client.ConnectAsync(new Uri(uri), token);
36+
}
37+
38+
/// <summary>
39+
/// Connects to a Buttplug server using a WebSocket URI.
40+
/// </summary>
41+
/// <param name="client">The client to connect.</param>
42+
/// <param name="uri">The WebSocket URI.</param>
43+
/// <param name="token">Cancellation token.</param>
44+
public static Task ConnectAsync(this ButtplugClient client, Uri uri, CancellationToken token = default)
45+
{
46+
return client.ConnectAsync(new ButtplugWebsocketConnector(uri), token);
47+
}
48+
49+
/// <summary>
50+
/// Gets a device by its index.
51+
/// </summary>
52+
/// <param name="client">The client.</param>
53+
/// <param name="index">The device index.</param>
54+
/// <returns>The device if found, otherwise null.</returns>
55+
public static ButtplugClientDevice GetDevice(this ButtplugClient client, uint index)
56+
{
57+
return client.Devices.FirstOrDefault(d => d.Index == index);
58+
}
59+
60+
/// <summary>
61+
/// Gets all devices that have the specified output type.
62+
/// </summary>
63+
/// <param name="client">The client.</param>
64+
/// <param name="outputType">The output type to filter by.</param>
65+
/// <returns>Enumerable of devices with the specified output type.</returns>
66+
public static IEnumerable<ButtplugClientDevice> GetDevicesWithOutput(this ButtplugClient client, OutputType outputType)
67+
{
68+
return client.Devices.Where(d => d.HasOutput(outputType));
69+
}
70+
71+
/// <summary>
72+
/// Gets all devices that have the specified input type.
73+
/// </summary>
74+
/// <param name="client">The client.</param>
75+
/// <param name="inputType">The input type to filter by.</param>
76+
/// <returns>Enumerable of devices with the specified input type.</returns>
77+
public static IEnumerable<ButtplugClientDevice> GetDevicesWithInput(this ButtplugClient client, InputType inputType)
78+
{
79+
return client.Devices.Where(d => d.HasInput(inputType));
80+
}
81+
82+
/// <summary>
83+
/// Sends a vibrate command to all devices that support vibration.
84+
/// </summary>
85+
/// <param name="client">The client.</param>
86+
/// <param name="percent">The vibration intensity (0.0 to 1.0).</param>
87+
/// <param name="token">Cancellation token.</param>
88+
/// <example>
89+
/// <code>
90+
/// await client.VibrateAllAsync(0.5); // Vibrate all devices at 50%
91+
/// </code>
92+
/// </example>
93+
public static async Task VibrateAllAsync(this ButtplugClient client, double percent, CancellationToken token = default)
94+
{
95+
var devices = client.GetDevicesWithOutput(OutputType.Vibrate).ToList();
96+
if (!devices.Any())
97+
{
98+
return;
99+
}
100+
101+
var tasks = devices.Select(d => d.RunOutputAsync(DeviceOutput.Vibrate.Percent(percent), token));
102+
await Task.WhenAll(tasks).ConfigureAwait(false);
103+
}
104+
105+
/// <summary>
106+
/// Sends an oscillate command to all devices that support oscillation.
107+
/// </summary>
108+
/// <param name="client">The client.</param>
109+
/// <param name="percent">The oscillation intensity (0.0 to 1.0).</param>
110+
/// <param name="token">Cancellation token.</param>
111+
public static async Task OscillateAllAsync(this ButtplugClient client, double percent, CancellationToken token = default)
112+
{
113+
var devices = client.GetDevicesWithOutput(OutputType.Oscillate).ToList();
114+
if (!devices.Any())
115+
{
116+
return;
117+
}
118+
119+
var tasks = devices.Select(d => d.RunOutputAsync(DeviceOutput.Oscillate.Percent(percent), token));
120+
await Task.WhenAll(tasks).ConfigureAwait(false);
121+
}
122+
123+
/// <summary>
124+
/// Sends a rotate command to all devices that support rotation.
125+
/// </summary>
126+
/// <param name="client">The client.</param>
127+
/// <param name="percent">The rotation speed (0.0 to 1.0).</param>
128+
/// <param name="token">Cancellation token.</param>
129+
public static async Task RotateAllAsync(this ButtplugClient client, double percent, CancellationToken token = default)
130+
{
131+
var devices = client.GetDevicesWithOutput(OutputType.Rotate).ToList();
132+
if (!devices.Any())
133+
{
134+
return;
135+
}
136+
137+
var tasks = devices.Select(d => d.RunOutputAsync(DeviceOutput.Rotate.Percent(percent), token));
138+
await Task.WhenAll(tasks).ConfigureAwait(false);
139+
}
140+
141+
/// <summary>
142+
/// Sends a position w/ duration command to all devices that support that output type.
143+
/// </summary>
144+
/// <param name="client">The client.</param>
145+
/// <param name="percent">The target position (0.0 to 1.0).</param>
146+
/// <param name="durationMs">The duration in milliseconds to reach the position.</param>
147+
/// <param name="token">Cancellation token.</param>
148+
public static async Task PositionWithDurationAllAsync(this ButtplugClient client, double percent, uint durationMs, CancellationToken token = default)
149+
{
150+
var devices = client.GetDevicesWithOutput(OutputType.PositionWithDuration).ToList();
151+
if (!devices.Any())
152+
{
153+
return;
154+
}
155+
156+
var tasks = devices.Select(d => d.RunOutputAsync(DeviceOutput.PositionWithDuration.Percent(percent, durationMs), token));
157+
await Task.WhenAll(tasks).ConfigureAwait(false);
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)