Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
VolcanicArts committed Oct 22, 2023
2 parents 85276f6 + a318d8b commit e7a01d9
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 34 deletions.
1 change: 1 addition & 0 deletions VRCOSC.Game/Managers/ChatBoxManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public void Import(string filePath)

public void ResetTimeline()
{
SelectedClip.Value = null;
setDefaults();
Serialise();
}
Expand Down
1 change: 1 addition & 0 deletions VRCOSC.Game/Modules/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ internal bool TryGetParameter(string lookup, [NotNullWhen(true)] out ModuleAttri
private static Regex parameterToRegex(string parameterName)
{
var pattern = parameterName.Replace("/", @"\/").Replace("*", @"(\S*)");
pattern += "$";
return new Regex(pattern);
}

Expand Down
45 changes: 22 additions & 23 deletions VRCOSC.Game/OSC/VRChat/VRChatOscClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,55 +66,54 @@ public void Reset()
QueryPort = null;
}

public async Task<object?> FindParameterValue(string parameterName)
private async Task<OSCQueryNode?> findParameter(string parameterName)
{
if (QueryPort is null) return null;
try
{
if (QueryPort is null) return null;

var url = $"http://127.0.0.1:{QueryPort}/avatar/parameters/{parameterName}";
var url = $"http://127.0.0.1:{QueryPort}/avatar/parameters/{parameterName}";

var response = await client.GetAsync(new Uri(url));
var content = await response.Content.ReadAsStringAsync();
var node = JsonConvert.DeserializeObject<OSCQueryNode>(content);
var response = await client.GetAsync(new Uri(url));
var content = await response.Content.ReadAsStringAsync();
var node = JsonConvert.DeserializeObject<OSCQueryNode>(content);

if (node is null)
return node is null || node.Access == Attributes.AccessValues.NoValue ? null : node;
}
catch (Exception e)
{
Logger.Log("Could not decode node");
Logger.Error(e, $"Exception when trying to find parameter: {parameterName}");
return null;
}
}

public async Task<object?> FindParameterValue(string parameterName)
{
var node = await findParameter(parameterName);
if (node is null) return null;

return node.OscType switch
{
"f" => Convert.ToSingle(node.Value[0]),
"i" => Convert.ToInt32(node.Value[0]),
"T" => Convert.ToBoolean(node.Value[0]),
"F" => Convert.ToBoolean(node.Value[0]),
_ => throw new InvalidOperationException("Unknown type")
_ => throw new InvalidOperationException($"Unknown type {node.OscType}")
};
}

public async Task<TypeCode?> FindParameterType(string parameterName)
{
if (QueryPort is null) return null;

var url = $"http://127.0.0.1:{QueryPort}/avatar/parameters/{parameterName}";

var response = await client.GetAsync(new Uri(url));
var content = await response.Content.ReadAsStringAsync();
var node = JsonConvert.DeserializeObject<OSCQueryNode>(content);

if (node is null)
{
Logger.Log("Could not decode node");
return null;
}
var node = await findParameter(parameterName);
if (node is null) return null;

return node.OscType switch
{
"f" => TypeCode.Single,
"i" => TypeCode.Int32,
"T" => TypeCode.Boolean,
"F" => TypeCode.Boolean,
_ => throw new InvalidOperationException("Unknown type")
_ => throw new InvalidOperationException($"Unknown type {node.OscType}")
};
}
}
2 changes: 1 addition & 1 deletion VRCOSC.Game/Providers/PiShock/PiShockProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task<PiShockResponse> Execute(string username, string apiKey, strin
{
var response = await client.PostAsync(action_api_url, new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"));
var responseString = await response.Content.ReadAsStringAsync();
return new PiShockResponse(responseString == "Operation Succeeded.", responseString, duration, intensity);
return new PiShockResponse(responseString is "Operation Succeeded." or "Operation Attempted.", responseString, duration, intensity);
}
catch (Exception e)
{
Expand Down
50 changes: 41 additions & 9 deletions VRCOSC.Modules/PiShock/PiShockModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ public class PiShockModule : AvatarModule
private SpeechToTextProvider? speechToTextProvider;

private int group;

private int selectedGroup
{
get => group;
set
{
group = value;
SendParameter(PiShockParameter.Group, group);
}
}

private float duration;
private float intensity;

Expand Down Expand Up @@ -71,15 +82,18 @@ protected override void CreateAttributes()
CreateParameter<int>(PiShockParameter.Group, ParameterMode.ReadWrite, "VRCOSC/PiShock/Group", "Group", "The group to select for the actions");
CreateParameter<float>(PiShockParameter.Duration, ParameterMode.ReadWrite, "VRCOSC/PiShock/Duration", "Duration", "The duration of the action as a percentage mapped between 1-15");
CreateParameter<float>(PiShockParameter.Intensity, ParameterMode.ReadWrite, "VRCOSC/PiShock/Intensity", "Intensity", "The intensity of the action as a percentage mapped between 1-100");
CreateParameter<bool>(PiShockParameter.Shock, ParameterMode.Read, "VRCOSC/PiShock/Shock", "Shock", "Executes a shock using the defined parameters");
CreateParameter<bool>(PiShockParameter.Vibrate, ParameterMode.Read, "VRCOSC/PiShock/Vibrate", "Vibrate", "Executes a vibration using the defined parameters");
CreateParameter<bool>(PiShockParameter.Beep, ParameterMode.Read, "VRCOSC/PiShock/Beep", "Beep", "Executes a beep using the defined parameters");
CreateParameter<bool>(PiShockParameter.Shock, ParameterMode.Read, "VRCOSC/PiShock/Shock", "Shock", "Executes a shock using the defined parameters on the selected group");
CreateParameter<bool>(PiShockParameter.ShockGroup, ParameterMode.Read, "VRCOSC/PiShock/Shock/*", "Shock Group", "For use when you want to execute a shock on a specific group instead of selecting a group");
CreateParameter<bool>(PiShockParameter.Vibrate, ParameterMode.Read, "VRCOSC/PiShock/Vibrate", "Vibrate", "Executes a vibration using the defined parameters on the selected group");
CreateParameter<bool>(PiShockParameter.VibrateGroup, ParameterMode.Read, "VRCOSC/PiShock/Vibrate/*", "Vibrate Group", "For use when you want to execute a vibration on a specific group instead of selecting a group");
CreateParameter<bool>(PiShockParameter.Beep, ParameterMode.Read, "VRCOSC/PiShock/Beep", "Beep", "Executes a beep using the defined parameters on the selected group");
CreateParameter<bool>(PiShockParameter.BeepGroup, ParameterMode.Read, "VRCOSC/PiShock/Beep/*", "Beep Group", "For use when you want to execute a beep on a specific group instead of selecting a group");
CreateParameter<bool>(PiShockParameter.Success, ParameterMode.Write, "VRCOSC/PiShock/Success", "Success", "If the execution was successful, this will become true for 1 second to act as a notification");
}

protected override void OnModuleStart()
{
group = 0;
selectedGroup = 0;
duration = 0f;
intensity = 0f;
shock = null;
Expand Down Expand Up @@ -175,11 +189,11 @@ private async void onNewSentenceSpoken(bool success, string sentence)

private async void executePiShockMode(PiShockMode mode)
{
var groupData = GetSettingList<PiShockGroupInstance>(PiShockSetting.Groups).ElementAtOrDefault(group);
var groupData = GetSettingList<PiShockGroupInstance>(PiShockSetting.Groups).ElementAtOrDefault(selectedGroup);

if (groupData is null)
{
Log($"No group with ID {group}");
Log($"No group with ID {selectedGroup}");
return;
}

Expand Down Expand Up @@ -223,7 +237,7 @@ private async Task sendPiShockData(PiShockMode mode, PiShockShockerInstance inst

private void sendParameters()
{
SendParameter(PiShockParameter.Group, group);
SendParameter(PiShockParameter.Group, selectedGroup);
SendParameter(PiShockParameter.Duration, duration);
SendParameter(PiShockParameter.Intensity, intensity);
}
Expand All @@ -236,16 +250,31 @@ protected override void OnRegisteredParameterReceived(AvatarParameter parameter)
shock = parameter.ValueAs<bool>() ? DateTimeOffset.Now : null;
break;

case PiShockParameter.ShockGroup:
selectedGroup = parameter.WildcardAs<int>(0);
shock = parameter.ValueAs<bool>() ? DateTimeOffset.Now : null;
break;

case PiShockParameter.Vibrate:
vibrate = parameter.ValueAs<bool>() ? DateTimeOffset.Now : null;
break;

case PiShockParameter.VibrateGroup:
selectedGroup = parameter.WildcardAs<int>(0);
vibrate = parameter.ValueAs<bool>() ? DateTimeOffset.Now : null;
break;

case PiShockParameter.Beep:
beep = parameter.ValueAs<bool>() ? DateTimeOffset.Now : null;
break;

case PiShockParameter.BeepGroup:
selectedGroup = parameter.WildcardAs<int>(0);
beep = parameter.ValueAs<bool>() ? DateTimeOffset.Now : null;
break;

case PiShockParameter.Group:
group = parameter.ValueAs<int>();
selectedGroup = parameter.ValueAs<int>();
break;

case PiShockParameter.Duration:
Expand Down Expand Up @@ -281,6 +310,9 @@ private enum PiShockParameter
Shock,
Vibrate,
Beep,
Success
Success,
ShockGroup,
VibrateGroup,
BeepGroup
}
}
53 changes: 53 additions & 0 deletions VRCOSC.Modules/Timer/TimerModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
// See the LICENSE file in the repository root for full license text.

using System.Globalization;
using VRCOSC.Game.Modules;
using VRCOSC.Game.Modules.Avatar;

namespace VRCOSC.Modules.Timer;

[ModuleTitle("Timer")]
[ModuleDescription("Counts down to a specified time to be put in the ChatBox")]
[ModuleGroup(ModuleType.General)]
public class TimerModule : ChatBoxModule
{
protected override void CreateAttributes()
{
CreateSetting(TimerSetting.Time, "Time", "The date/time to countdown to", string.Empty);

CreateVariable(TimerVariable.Time, "Time", "time");
CreateState(TimerState.Default, "Default", GetVariableFormat(TimerVariable.Time));
}

[ModuleUpdate(ModuleUpdateMode.ChatBox)]
private void onChatBoxUpdate()
{
if (DateTime.TryParse(GetSetting<string>(TimerSetting.Time), null, DateTimeStyles.AssumeLocal, out var time))
{
var timeNow = DateTime.Now;
var difference = time - timeNow;
var differenceNoMilli = new TimeSpan(difference.Days, difference.Hours, difference.Minutes, difference.Seconds);
SetVariableValue(TimerVariable.Time, differenceNoMilli.ToString("g"));
}
else
{
Log("Could not parse entered time");
}
}

private enum TimerSetting
{
Time
}

private enum TimerState
{
Default
}

private enum TimerVariable
{
Time
}
}
9 changes: 8 additions & 1 deletion VRCOSC.Modules/VoiceRecognition/VoiceRecognitionModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ private async void onNewSentenceSpoken(bool success, string sentence)
{
if (!success) return;

var phraseInstances = GetSettingList<VoiceRecognitionPhraseInstance>(VoiceRecognitionSetting.PhraseList).Where(wordInstance => sentence.Contains(wordInstance.Phrase.Value, StringComparison.InvariantCultureIgnoreCase)).ToList();
var phraseInstances = GetSettingList<VoiceRecognitionPhraseInstance>(VoiceRecognitionSetting.PhraseList)
.Where(wordInstance =>
sentence.Contains(wordInstance.Phrase.Value, StringComparison.InvariantCultureIgnoreCase) &&
!string.IsNullOrEmpty(wordInstance.Phrase.Value) &&
!string.IsNullOrEmpty(wordInstance.ParameterName.Value) &&
!string.IsNullOrEmpty(wordInstance.Value.Value))
.ToList();

if (!phraseInstances.Any()) return;

Log($"Found phrase '{phraseInstances[0].Phrase.Value}'");
Expand Down

0 comments on commit e7a01d9

Please sign in to comment.