Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions VRCFTPicoModule/Assets/Locales/en-US.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"start-init": "Starting Initialization...",
"initializing-udp-clients": "Initializing UDP Clients on ports: {0}",
"using-port": "Using port: {0}",
"eye-tracking-disabled": "Eye tracking is disabled",
"expression-tracking-disabled": "Expression tracking is disabled",
"legacy-protocol": "Legacy Protocol",
"full-face-tracking": "Full FaceTracking",
"eye-tracking": "Eye Tracking",
"expression-tracking": "Expression Tracking",
"init-failed": "Initialization failed, exception: {0}",
"update-timeout": "Receive data timed out",
"update-failed": "Update failed with exception: {0}"
}
14 changes: 14 additions & 0 deletions VRCFTPicoModule/Assets/Locales/zh-CN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"start-init": "正在开始初始化...",
"initializing-udp-clients": "正在端口 {0} 上初始化 UDP 客户端",
"using-port": "使用端口:{0}",
"eye-tracking-disabled": "眼部追踪已停用",
"expression-tracking-disabled": "表情追踪已停用",
"legacy-protocol": "旧版协议",
"full-face-tracking": "完整面部追踪",
"eye-tracking": "眼部追踪",
"expression-tracking": "表情追踪",
"init-failed": "初始化失败,原因:{0}",
"update-timeout": "接收数据超时",
"update-failed": "更新数据失败,原因:{0}"
}
4 changes: 2 additions & 2 deletions VRCFTPicoModule/Utils/DataPacketHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ public static class DataPacketHelpers
{
public static T ByteArrayToStructure<T>(byte[] bytes, int offset = 0) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
IntPtr ptr = Marshal.AllocHGlobal(size);
var size = Marshal.SizeOf(typeof(T));
var ptr = Marshal.AllocHGlobal(size);

try
{
Expand Down
54 changes: 54 additions & 0 deletions VRCFTPicoModule/Utils/Localization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using VRCFaceTracking.Core.Helpers;

namespace VRCFTPicoModule.Utils;

public class Localization
{
private Dictionary<string, string>? _translations;

private Localization() { }

private static Localization LocInstance { get; } = new();

public static void Initialize(string languageCode)
{
LocInstance.LoadLanguageAsync(languageCode).GetAwaiter().GetResult();
}

private async Task LoadLanguageAsync(string languageCode)
{
var jsonContent = await LoadResourceAsync($"VRCFTPicoModule.Assets.Locales.{languageCode}.json")
?? await LoadResourceAsync("VRCFTPicoModule.Assets.Locales.en-US.json");

if (jsonContent != null)
{
_translations = await Json.ToObjectAsync<Dictionary<string, string>>(jsonContent);
}
else
{
_translations = new Dictionary<string, string>();
}
}

private async Task<string?> LoadResourceAsync(string resourceName)
{
await using var stream = GetType().Assembly.GetManifestResourceStream(resourceName);
if (stream == null) return null;
using var reader = new StreamReader(stream);
return await reader.ReadToEndAsync();
}

private string GetTranslation(string key)
{
if (_translations != null && _translations.TryGetValue(key, out var translation))
{
return translation;
}
return key;
}

public static string T(string key)
{
return LocInstance.GetTranslation(key);
}
}
18 changes: 8 additions & 10 deletions VRCFTPicoModule/Utils/Updater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using VRCFaceTracking.Core.Library;
using VRCFaceTracking.Core.Params.Expressions;
using VRCFTPicoModule.Data;
using static VRCFTPicoModule.Utils.Localization;

namespace VRCFTPicoModule.Utils
{
Expand Down Expand Up @@ -59,13 +60,13 @@ public void Update(ModuleState state)
{
if (++_timeOut > 600)
{
_logger.LogWarning("Receive data timed out.");
_logger.LogWarning(T("update-timeout"));
_timeOut = 0;
}
}
catch (Exception ex)
{
_logger.LogWarning("Update failed with exception: {0}", ex);
_logger.LogWarning(T("update-failed"), ex);
}
}

Expand All @@ -74,13 +75,10 @@ private static float[] ParseData(byte[] data, bool isLegacy)
if (isLegacy && data.Length >= Marshal.SizeOf<LegacyDataPacket.DataPackBody>())
return DataPacketHelpers.ByteArrayToStructure<LegacyDataPacket.DataPackBody>(data).blendShapeWeight;

if (data.Length >= Marshal.SizeOf<DataPacket.DataPackHeader>() + Marshal.SizeOf<DataPacket.DataPackBody>())
{
var header = DataPacketHelpers.ByteArrayToStructure<DataPacket.DataPackHeader>(data);
if (header.trackingType == 2)
return DataPacketHelpers.ByteArrayToStructure<DataPacket.DataPackBody>(data, Marshal.SizeOf<DataPacket.DataPackHeader>()).blendShapeWeight;
}
return [];
if (data.Length <
Marshal.SizeOf<DataPacket.DataPackHeader>() + Marshal.SizeOf<DataPacket.DataPackBody>()) return [];
var header = DataPacketHelpers.ByteArrayToStructure<DataPacket.DataPackHeader>(data);
return header.trackingType == 2 ? DataPacketHelpers.ByteArrayToStructure<DataPacket.DataPackBody>(data, Marshal.SizeOf<DataPacket.DataPackHeader>()).blendShapeWeight : [];
}

private static void UpdateEye(float[] pShape)
Expand Down Expand Up @@ -209,7 +207,7 @@ private void UpdateExpression(float[] pShape)
#endregion

#region Tongue
SetParam(pShape[(int)BlendShape.Index.TongueOut] > 0f ? 1f : 0f, UnifiedExpressions.TongueOut);
SetParam(pShape, BlendShape.Index.TongueOut, UnifiedExpressions.TongueOut);
#endregion
}

Expand Down
38 changes: 22 additions & 16 deletions VRCFTPicoModule/VRCFTPicoModule.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Microsoft.Extensions.Logging;
using System.Globalization;
using Microsoft.Extensions.Logging;
using System.Net.Sockets;
using VRCFaceTracking;
using VRCFTPicoModule.Utils;
using static VRCFTPicoModule.Utils.Localization;

namespace VRCFTPicoModule;

Expand All @@ -18,40 +20,47 @@ public class VRCFTPicoModule : ExtTrackingModule

public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAvailable, bool expressionAvailable)
{
Logger.LogInformation("Starting initialization");
Localization.Initialize(CultureInfo.CurrentUICulture.Name);
Logger.LogInformation(T("start-init"));
_trackingAvailable = (eyeAvailable, expressionAvailable);
var initializationResult = InitializeAsync().GetAwaiter().GetResult();

if (!initializationResult.Item1 || !initializationResult.Item2)
UpdateModuleInfo();
UpdateModuleInfo(initializationResult);

return initializationResult;
}

private async Task<(bool eyeSuccess, bool expressionSuccess)> InitializeAsync()
{
Logger.LogDebug("Initializing UDP Clients on ports: {0}", string.Join(", ", Ports));
Logger.LogDebug(T("initializing-udp-clients"), string.Join(", ", Ports));

var portIndex = await ListenOnPorts();
if (portIndex == -1) return (false, false);

_port = Ports[portIndex];
_udpClient = new UdpClient(_port);
Logger.LogInformation("Using port: {0}", _port);
Logger.LogInformation(T("using-port"), _port);

if (!_trackingAvailable.Item1)
Logger.LogInformation("Eye tracking is disabled");
Logger.LogInformation(T("eye-tracking-disabled"));
if (!_trackingAvailable.Item2)
Logger.LogInformation("Expression tracking is disabled");
Logger.LogInformation(T("expression-tracking-disabled"));

_updater = new Updater(_udpClient, Logger, _port == Ports[1], _trackingAvailable);

return _trackingAvailable;
}

private void UpdateModuleInfo()
private void UpdateModuleInfo((bool, bool) initializationResult)
{
ModuleInformation.Name = "PICO Connect";
var moduleProtocol = _port == Ports[1] ? $" [{T("legacy-protocol")}]" : "";
var moduleTrackingStatus = initializationResult switch
{
{ Item1: true, Item2: true } => T("full-face-tracking"),
{ Item1: true, Item2: false } => T("eye-tracking"),
{ Item1: false, Item2: true } => T("expression-tracking"),
_ => ""
};
ModuleInformation.Name = "PICO / " + moduleTrackingStatus + moduleProtocol;
var stream = GetType().Assembly.GetManifestResourceStream("VRCFTPicoModule.Assets.pico.png");
ModuleInformation.StaticImages = stream != null ? [stream] : ModuleInformation.StaticImages;
}
Expand All @@ -75,18 +84,15 @@ private async Task<int> ListenOnPorts()
}
catch (Exception ex)
{
Logger.LogError("Initialization failed, exception: {0}", ex);
Logger.LogError(T("init-failed"), ex);
}

return -1;
}

public override void Update()
{
if (_updater == null)
return;

_updater.Update(Status);
_updater?.Update(Status);
}

public override void Teardown()
Expand Down
10 changes: 10 additions & 0 deletions VRCFTPicoModule/VRCFTPicoModule.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
<EmbeddedResource Include="Assets\pico.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="Assets\Locales\en-US.json" />
<EmbeddedResource Include="Assets\Locales\en-US.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Locales\zh-CN.json" />
<EmbeddedResource Include="Assets\Locales\zh-CN.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="Build" Condition="'$(ContinuousIntegrationBuild)' != 'true'">
<Copy SourceFiles="$(TargetPath)" DestinationFiles="$(APPDATA)\VRCFaceTracking\CustomLibs\$(TargetFileName)" OverwriteReadOnlyFiles="True" SkipUnchangedFiles="True" />
Expand Down
Loading