v2019.08.19

This commit is contained in:
pypy
2019-08-19 23:21:08 +09:00
parent d725c8f1e3
commit 26b371fd0f
19 changed files with 768 additions and 515 deletions
+25 -12
View File
@@ -6,13 +6,14 @@
using CefSharp; using CefSharp;
using CefSharp.OffScreen; using CefSharp.OffScreen;
using SharpDX.Direct3D11; using SharpDX.Direct3D11;
using System;
using System.Drawing; using System.Drawing;
using System.Threading;
namespace VRCX namespace VRCX
{ {
public class Browser : ChromiumWebBrowser public class Browser : ChromiumWebBrowser
{ {
private readonly ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
private Texture2D m_Texture; private Texture2D m_Texture;
public Browser(Texture2D texture, string address) public Browser(Texture2D texture, string address)
@@ -24,38 +25,46 @@ namespace VRCX
m_Texture = texture; m_Texture = texture;
Size = new Size(texture.Description.Width, texture.Description.Height); Size = new Size(texture.Description.Width, texture.Description.Height);
RenderHandler.Dispose(); RenderHandler.Dispose();
RenderHandler = new RenderHandler(this); RenderHandler = new RenderHandler(this, m_Lock);
var options = new BindingOptions() var options = new BindingOptions()
{ {
CamelCaseJavascriptNames = false CamelCaseJavascriptNames = false
}; };
JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options); JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options);
JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options); JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options);
JavascriptObjectRepository.Register("SQLite", new SQLite(), true, options);
}
public new void Dispose()
{
RenderHandler.Dispose();
RenderHandler = null;
base.Dispose();
} }
public void Render() public void Render()
{ {
var handler = (RenderHandler)RenderHandler; m_Lock.EnterReadLock();
lock (handler.BufferLock) try
{ {
if (handler.Buffer.IsAllocated) var H = (RenderHandler)RenderHandler;
if (H.Buffer.IsAllocated)
{ {
var context = m_Texture.Device.ImmediateContext; var context = m_Texture.Device.ImmediateContext;
var box = context.MapSubresource(m_Texture, 0, MapMode.WriteDiscard, MapFlags.None); var box = context.MapSubresource(m_Texture, 0, MapMode.WriteDiscard, MapFlags.None);
if (box.DataPointer != IntPtr.Zero) if (box.IsEmpty)
{ {
var width = handler.Width; if (box.RowPitch == H.Width * 4)
var height = handler.Height;
if (box.RowPitch == width * 4)
{ {
WinApi.CopyMemory(box.DataPointer, handler.Buffer.AddrOfPinnedObject(), (uint)handler.BufferSize); WinApi.CopyMemory(box.DataPointer, H.Buffer.AddrOfPinnedObject(), (uint)H.BufferSize);
} }
else else
{ {
var dest = box.DataPointer; var dest = box.DataPointer;
var src = handler.Buffer.AddrOfPinnedObject(); var src = H.Buffer.AddrOfPinnedObject();
var pitch = box.RowPitch; var pitch = box.RowPitch;
var length = width * 4; var length = H.Width * 4;
var height = H.Height;
for (var i = 0; i < height; ++i) for (var i = 0; i < height; ++i)
{ {
WinApi.CopyMemory(dest, src, (uint)length); WinApi.CopyMemory(dest, src, (uint)length);
@@ -67,6 +76,10 @@ namespace VRCX
context.UnmapSubresource(m_Texture, 0); context.UnmapSubresource(m_Texture, 0);
} }
} }
finally
{
m_Lock.ExitReadLock();
}
} }
} }
} }
+32 -44
View File
@@ -13,36 +13,32 @@ namespace VRCX
public static float CpuUsage { get; private set; } public static float CpuUsage { get; private set; }
private static Thread m_Thread; private static Thread m_Thread;
public static void Start() public static void Init()
{ {
if (m_Thread == null) m_Thread = new Thread(() =>
{ {
m_Thread = new Thread(() => PerformanceCounter counter = null;
try
{ {
PerformanceCounter cpuCounter = null; counter = new PerformanceCounter("Processor Information", "% Processor Utility", "_Total", true);
try }
{ catch
cpuCounter = new PerformanceCounter("Processor Information", "% Processor Utility", "_Total", true); {
} }
catch try
{ {
} if (counter == null)
try
{
if (cpuCounter == null)
{
cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
}
}
catch
{ {
counter = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
} }
}
catch
{
}
if (counter != null)
{
while (m_Thread != null) while (m_Thread != null)
{ {
if (cpuCounter != null)
{
CpuUsage = cpuCounter.NextValue();
}
try try
{ {
Thread.Sleep(1000); Thread.Sleep(1000);
@@ -51,31 +47,23 @@ namespace VRCX
{ {
// ThreadInterruptedException // ThreadInterruptedException
} }
CpuUsage = counter.NextValue();
} }
if (cpuCounter != null) counter.Dispose();
{ }
cpuCounter.Dispose(); })
} {
}); IsBackground = true
m_Thread.Start(); };
} m_Thread.Start();
} }
public static void Stop() public static void Exit()
{ {
var thread = m_Thread; var T = m_Thread;
if (thread != null) m_Thread = null;
{ T.Interrupt();
m_Thread = null; T.Join();
try
{
thread.Interrupt();
thread.Join();
}
catch
{
}
}
} }
} }
} }
+78 -21
View File
@@ -4,38 +4,80 @@
// For a copy, see <https://opensource.org/licenses/MIT>. // For a copy, see <https://opensource.org/licenses/MIT>.
using DiscordRPC; using DiscordRPC;
using System.Threading;
namespace VRCX namespace VRCX
{ {
public class Discord public class Discord
{ {
private static RichPresence m_Presence = new RichPresence(); private static readonly ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
private static DiscordRpcClient m_Client; private static readonly RichPresence m_Presence = new RichPresence();
private static Thread m_Thread;
private static bool m_Active; private static bool m_Active;
public static void Update() public static void Init()
{ {
if (m_Client != null) m_Thread = new Thread(() =>
{ {
m_Client.Invoke(); DiscordRpcClient client = null;
} while (m_Thread != null)
if (m_Active)
{
if (m_Client == null)
{ {
m_Client = new DiscordRpcClient("525953831020920832"); try
m_Client.Initialize(); {
Thread.Sleep(1000);
}
catch
{
// ThreadInterruptedException
}
if (client != null)
{
m_Lock.EnterReadLock();
try
{
client.SetPresence(m_Presence);
}
finally
{
m_Lock.ExitReadLock();
}
client.Invoke();
}
if (m_Active)
{
if (client == null)
{
client = new DiscordRpcClient("525953831020920832");
if (!client.Initialize())
{
client.Dispose();
client = null;
}
}
}
else if (client != null)
{
client.Dispose();
client = null;
}
} }
lock (m_Presence) if (client != null)
{ {
m_Client.SetPresence(m_Presence); client.Dispose();
} }
} })
else if (m_Client != null)
{ {
m_Client.Dispose(); IsBackground = true
m_Client = null; };
} m_Thread.Start();
}
public static void Exit()
{
var T = m_Thread;
m_Thread = null;
T.Interrupt();
T.Join();
} }
public void SetActive(bool active) public void SetActive(bool active)
@@ -45,16 +87,22 @@ namespace VRCX
public void SetText(string details, string state) public void SetText(string details, string state)
{ {
lock (m_Presence) m_Lock.EnterWriteLock();
try
{ {
m_Presence.Details = details; m_Presence.Details = details;
m_Presence.State = state; m_Presence.State = state;
} }
finally
{
m_Lock.ExitWriteLock();
}
} }
public void SetAssets(string largeKey, string largeText, string smallKey, string smallText) public void SetAssets(string largeKey, string largeText, string smallKey, string smallText)
{ {
lock (m_Presence) m_Lock.EnterWriteLock();
try
{ {
if (string.IsNullOrEmpty(largeKey) && if (string.IsNullOrEmpty(largeKey) &&
string.IsNullOrEmpty(smallKey)) string.IsNullOrEmpty(smallKey))
@@ -73,6 +121,10 @@ namespace VRCX
m_Presence.Assets.SmallImageText = smallText; m_Presence.Assets.SmallImageText = smallText;
} }
} }
finally
{
m_Lock.ExitWriteLock();
}
} }
// JSB Sucks // JSB Sucks
@@ -83,7 +135,8 @@ namespace VRCX
public static void SetTimestamps(ulong startUnixMilliseconds, ulong endUnixMilliseconds) public static void SetTimestamps(ulong startUnixMilliseconds, ulong endUnixMilliseconds)
{ {
lock (m_Presence) m_Lock.EnterWriteLock();
try
{ {
if (startUnixMilliseconds == 0) if (startUnixMilliseconds == 0)
{ {
@@ -106,6 +159,10 @@ namespace VRCX
} }
} }
} }
finally
{
m_Lock.ExitWriteLock();
}
} }
} }
} }
+193 -152
View File
@@ -5,176 +5,194 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
namespace VRCX namespace VRCX
{ {
public class VRCX_LogWatcher public class LogWatcherFile
{ {
public long Length;
public long Position;
}
public class LogWatcher
{
private static readonly ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
private static List<string[]> m_GameLog = new List<string[]>(); private static List<string[]> m_GameLog = new List<string[]>();
private static Thread m_Thread; private static Thread m_Thread;
private static bool m_Reset; private static bool m_Reset;
public static void Start() // NOTE
// FileSystemWatcher() is unreliable
public static void Init()
{ {
if (m_Thread == null) m_Thread = new Thread(() =>
{ {
m_Thread = new Thread(() => var D = new Dictionary<string, LogWatcherFile>();
var di = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"Low\VRChat\VRChat");
while (m_Thread != null)
{ {
var lastPosition = 0L; try
var firstLine = string.Empty;
while (m_Thread != null)
{ {
if (m_Reset) Thread.Sleep(1000);
}
catch
{
// ThreadInterruptedException
}
if (m_Reset)
{
m_Reset = false;
D.Clear();
m_Lock.EnterWriteLock();
try
{ {
m_Reset = false; m_GameLog.Clear();
firstLine = string.Empty;
lastPosition = 0;
} }
var info = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"Low\VRChat\VRChat"); finally
if (info != null &&
info.Exists)
{ {
var files = info.GetFiles("output_log_*.txt", SearchOption.TopDirectoryOnly); m_Lock.ExitWriteLock();
if (files != null && }
files.Length >= 1) }
var S = new HashSet<string>(D.Keys);
di.Refresh();
if (di.Exists)
{
var files = di.GetFiles("output_log_*.txt", SearchOption.TopDirectoryOnly);
Array.Sort(files, (A, B) => A.CreationTime.CompareTo(B.CreationTime));
var bias = DateTime.Now.AddMinutes(-5d);
foreach (var fi in files)
{
if (bias.CompareTo(fi.LastWriteTime) <= 0)
{ {
Array.Sort(files, (A, B) => B.LastWriteTime.CompareTo(A.LastWriteTime)); fi.Refresh();
if (firstLine == string.Empty) }
if (D.TryGetValue(fi.Name, out LogWatcherFile F))
{
S.Remove(fi.Name);
if (F.Length == fi.Length)
{ {
for (var i = files.Length - 1; i >= 1; --i) continue;
}
}
else
{
F = new LogWatcherFile();
D.Add(fi.Name, F);
}
F.Length = fi.Length;
Parse(fi, ref F.Position);
}
}
foreach (var key in S)
{
D.Remove(key);
}
}
})
{
IsBackground = true
};
m_Thread.Start();
}
public static void Exit()
{
var T = m_Thread;
m_Thread = null;
T.Interrupt();
T.Join();
}
public static void Parse(FileInfo info, ref long position)
{
try
{
using (var stream = info.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
stream.Position = position;
var s = string.Empty;
while ((s = reader.ReadLine()) != null)
{
if (s.Length > 35)
{
var c = s[35];
if (c == 'R')
{
// 2019.07.31 22:26:24 Log - [RoomManager] Joining wrld_4432ea9b-729c-46e3-8eaf-846aa0a37fdd:6974~private(usr_4f76a584-9d4b-46f6-8209-8305eb683661)~nonce(0000000000000000000000000000000000000000000000000000000000000000)
// 2019.07.31 22:26:24 Log - [RoomManager] Joining or Creating Room: VRChat Home
if (s.Length > 56 &&
string.Compare(s, 34, "[RoomManager] Joining ", 0, "[RoomManager] Joining ".Length, StringComparison.Ordinal) == 0 &&
string.Compare(s, 56, "or ", 0, "or ".Length, StringComparison.Ordinal) != 0)
{
var item = new[]
{ {
using (var stream = files[i].Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) ConvertLogTimeToISO8601(s),
using (var reader = new StreamReader(stream, Encoding.UTF8)) "Location",
{ s.Substring(56)
var line = string.Empty; };
while ((line = reader.ReadLine()) != null) m_Lock.EnterWriteLock();
{ try
if (line.Length > 32 && {
line[31] == '-') m_GameLog.Add(item);
{ }
ParseLine(line); finally
} {
} m_Lock.ExitWriteLock();
}
} }
} }
using (var stream = files[0].Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) }
using (var reader = new StreamReader(stream, Encoding.UTF8)) else if (c == 'N')
{
// 2019.07.31 22:41:18 Log - [NetworkManager] OnPlayerJoined pypy
if (s.Length > 66 &&
string.Compare(s, 34, "[NetworkManager] OnPlayerJoined ", 0, "[NetworkManager] OnPlayerJoined ".Length, StringComparison.Ordinal) == 0)
{ {
var line = reader.ReadLine(); var item = new[]
if (line != null)
{ {
if (string.Equals(firstLine, line)) ConvertLogTimeToISO8601(s),
{ "OnPlayerJoined",
stream.Position = lastPosition; s.Substring(66)
} };
else m_Lock.EnterWriteLock();
{ try
firstLine = line; {
} m_GameLog.Add(item);
do }
{ finally
lastPosition = stream.Position; {
ParseLine(line); m_Lock.ExitWriteLock();
} }
while ((line = reader.ReadLine()) != null); }
// 2019.07.31 22:29:31 Log - [NetworkManager] OnPlayerLeft pypy
else if (s.Length > 64 &&
string.Compare(s, 34, "[NetworkManager] OnPlayerLeft ", 0, "[NetworkManager] OnPlayerLeft ".Length, StringComparison.Ordinal) == 0)
{
var item = new[]
{
ConvertLogTimeToISO8601(s),
"OnPlayerLeft",
s.Substring(64)
};
m_Lock.EnterWriteLock();
try
{
m_GameLog.Add(item);
}
finally
{
m_Lock.ExitWriteLock();
} }
} }
} }
} }
try
{
Thread.Sleep(3000);
}
catch
{
// ThreadInterruptedException
}
}
});
m_Thread.Start();
}
}
public static void Stop()
{
var thread = m_Thread;
if (thread != null)
{
m_Thread = null;
try
{
thread.Interrupt();
thread.Join();
}
catch
{
}
}
}
private static string ConvertLogTimeToISO8601(string s)
{
// 2019.07.31 22:26:24
var dt = new DateTime(
int.Parse(s.Substring(0, 4)),
int.Parse(s.Substring(5, 2)),
int.Parse(s.Substring(8, 2)),
int.Parse(s.Substring(11, 2)),
int.Parse(s.Substring(14, 2)),
int.Parse(s.Substring(17, 2)),
DateTimeKind.Local
).ToUniversalTime();
return $"{dt:yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'}";
}
private static void ParseLine(string line)
{
try
{
// 2019.07.31 22:26:24 Log - [RoomManager] Joining wrld_4432ea9b-729c-46e3-8eaf-846aa0a37fdd:6974~private(usr_4f76a584-9d4b-46f6-8209-8305eb683661)~nonce(0000000000000000000000000000000000000000000000000000000000000000)
// 2019.07.31 22:26:24 Log - [RoomManager] Joining or Creating Room: VRChat Home
if (string.Compare(line, 34, "[RoomManager] Joining ", 0, "[RoomManager] Joining ".Length) == 0 &&
string.Compare(line, 56, "or ", 0, "or ".Length) != 0)
{
lock (m_GameLog)
{
m_GameLog.Add(new[]
{
ConvertLogTimeToISO8601(line),
"Location",
line.Substring(56)
});
}
}
// 2019.07.31 22:41:18 Log - [NetworkManager] OnPlayerJoined pypy
else if (string.Compare(line, 34, "[NetworkManager] OnPlayerJoined ", 0, "[NetworkManager] OnPlayerJoined ".Length) == 0)
{
lock (m_GameLog)
{
m_GameLog.Add(new[]
{
ConvertLogTimeToISO8601(line),
"OnPlayerJoined",
line.Substring(66)
});
}
}
// 2019.07.31 22:29:31 Log - [NetworkManager] OnPlayerLeft pypy
else if (string.Compare(line, 34, "[NetworkManager] OnPlayerLeft ", 0, "[NetworkManager] OnPlayerLeft ".Length) == 0)
{
lock (m_GameLog)
{
m_GameLog.Add(new[]
{
ConvertLogTimeToISO8601(line),
"OnPlayerLeft",
line.Substring(64)
});
} }
position = stream.Position;
} }
} }
catch catch
@@ -182,31 +200,54 @@ namespace VRCX
} }
} }
private static string ConvertLogTimeToISO8601(string s)
{
// 2019.07.31 22:26:24
if (!DateTime.TryParseExact(s.Substring(0, 19),
"yyyy.MM.dd HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeLocal,
out DateTime dt))
{
dt = DateTime.UtcNow;
}
return $"{dt:yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'}";
}
public void Reset() public void Reset()
{ {
lock (m_GameLog) if (m_Thread != null)
{ {
m_Reset = true; m_Reset = true;
m_GameLog.Clear(); m_Thread.Interrupt();
} }
m_Thread.Interrupt();
} }
public string[][] GetLogs() public string[][] Get()
{ {
lock (m_GameLog) m_Lock.EnterUpgradeableReadLock();
try
{ {
if (m_Reset ||
m_GameLog.Count == 0)
{
return new string[][] { };
}
var array = m_GameLog.ToArray(); var array = m_GameLog.ToArray();
m_GameLog.Clear(); m_Lock.EnterWriteLock();
try
{
m_GameLog.Clear();
}
finally
{
m_Lock.ExitWriteLock();
}
return array; return array;
} }
} finally
public bool HasLog()
{
lock (m_GameLog)
{ {
return m_GameLog.Count > 0; m_Lock.ExitUpgradeableReadLock();
} }
} }
} }
-10
View File
@@ -33,16 +33,8 @@ namespace VRCX
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
this.components = new System.ComponentModel.Container();
this.timer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout(); this.SuspendLayout();
// //
// timer
//
this.timer.Enabled = true;
this.timer.Interval = 1000;
this.timer.Tick += new System.EventHandler(this.timer_Tick);
//
// MainForm // MainForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F); this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
@@ -56,7 +48,5 @@ namespace VRCX
} }
#endregion #endregion
private System.Windows.Forms.Timer timer;
} }
} }
+2 -6
View File
@@ -43,7 +43,8 @@ namespace VRCX
}; };
Browser.JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options); Browser.JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options);
Browser.JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options); Browser.JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options);
Browser.JavascriptObjectRepository.Register("LogWatcher", new VRCX_LogWatcher(), true, options); Browser.JavascriptObjectRepository.Register("SQLite", new SQLite(), true, options);
Browser.JavascriptObjectRepository.Register("LogWatcher", new LogWatcher(), true, options);
Browser.JavascriptObjectRepository.Register("Discord", new Discord(), true, options); Browser.JavascriptObjectRepository.Register("Discord", new Discord(), true, options);
Browser.IsBrowserInitializedChanged += (A, B) => Browser.IsBrowserInitializedChanged += (A, B) =>
{ {
@@ -51,10 +52,5 @@ namespace VRCX
}; };
Controls.Add(Browser); Controls.Add(Browser);
} }
private void timer_Tick(object sender, System.EventArgs e)
{
Discord.Update();
}
} }
} }
-3
View File
@@ -117,7 +117,4 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<metadata name="timer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root> </root>
+10 -6
View File
@@ -53,15 +53,19 @@ namespace VRCX
{ {
Application.EnableVisualStyles(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); Application.SetCompatibleTextRenderingDefault(false);
CpuMonitor.Start();
VRCXStorage.Load(); VRCXStorage.Load();
VRCXVR.Setup(); SQLite.Init();
VRCX_LogWatcher.Start(); CpuMonitor.Init();
Discord.Init();
LogWatcher.Init();
VRCXVR.Init();
Application.Run(new MainForm()); Application.Run(new MainForm());
VRCX_LogWatcher.Stop(); VRCXVR.Exit();
VRCXVR.Stop(); LogWatcher.Exit();
Discord.Exit();
CpuMonitor.Exit();
SQLite.Exit();
VRCXStorage.Save(); VRCXStorage.Save();
CpuMonitor.Stop();
Cef.Shutdown(); Cef.Shutdown();
} }
} }
+30 -10
View File
@@ -5,6 +5,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using CefSharp; using CefSharp;
using CefSharp.Enums; using CefSharp.Enums;
using CefSharp.OffScreen; using CefSharp.OffScreen;
@@ -15,26 +16,32 @@ namespace VRCX
public class RenderHandler : IRenderHandler public class RenderHandler : IRenderHandler
{ {
private ChromiumWebBrowser m_Browser; private ChromiumWebBrowser m_Browser;
public readonly object BufferLock = new object(); private ReaderWriterLockSlim m_Lock;
public int BufferSize { get; private set; } public int BufferSize { get; private set; }
public GCHandle Buffer { get; private set; } public GCHandle Buffer { get; private set; }
public int Width { get; private set; } public int Width { get; private set; }
public int Height { get; private set; } public int Height { get; private set; }
public RenderHandler(ChromiumWebBrowser browser) public RenderHandler(ChromiumWebBrowser browser, ReaderWriterLockSlim @lock)
{ {
m_Browser = browser; m_Browser = browser;
m_Lock = @lock;
} }
public void Dispose() public void Dispose()
{ {
lock (BufferLock) m_Lock.EnterWriteLock();
try
{ {
if (Buffer.IsAllocated) if (Buffer.IsAllocated)
{ {
Buffer.Free(); Buffer.Free();
} }
} }
finally
{
m_Lock.ExitWriteLock();
}
m_Browser = null; m_Browser = null;
} }
@@ -64,23 +71,36 @@ namespace VRCX
{ {
if (type == PaintElementType.View) if (type == PaintElementType.View)
{ {
lock (BufferLock) m_Lock.EnterUpgradeableReadLock();
try
{ {
if (!Buffer.IsAllocated || if (!Buffer.IsAllocated ||
width != Width || width != Width ||
height != Height) height != Height)
{ {
Width = width; m_Lock.EnterWriteLock();
Height = height; try
BufferSize = width * height * 4;
if (Buffer.IsAllocated)
{ {
Buffer.Free(); Width = width;
Height = height;
BufferSize = width * height * 4;
if (Buffer.IsAllocated)
{
Buffer.Free();
}
Buffer = GCHandle.Alloc(new byte[BufferSize], GCHandleType.Pinned);
}
finally
{
m_Lock.ExitWriteLock();
} }
Buffer = GCHandle.Alloc(new byte[BufferSize], GCHandleType.Pinned);
} }
WinApi.CopyMemory(Buffer.AddrOfPinnedObject(), buffer, (uint)BufferSize); WinApi.CopyMemory(Buffer.AddrOfPinnedObject(), buffer, (uint)BufferSize);
} }
finally
{
m_Lock.ExitUpgradeableReadLock();
}
} }
} }
+91
View File
@@ -0,0 +1,91 @@
using CefSharp;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.Threading;
using System.Windows.Forms;
namespace VRCX
{
public class SQLite
{
private static readonly ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
private static SQLiteConnection m_Connection;
public static void Init()
{
m_Connection = new SQLiteConnection($"Data Source={Application.StartupPath}/VRCX.sqlite;Version=3");
m_Connection.Open();
}
public static void Exit()
{
m_Connection.Close();
m_Connection.Dispose();
}
public void Execute(string sql, IDictionary<string, object> param = null)
{
m_Lock.EnterWriteLock();
try
{
if (m_Connection.State != ConnectionState.Open)
{
m_Connection.Close();
m_Connection.Open();
}
using (var C = new SQLiteCommand(sql, m_Connection))
{
if (param != null)
{
foreach (var prop in param)
{
C.Parameters.Add(new SQLiteParameter("@" + prop.Key, prop.Value));
}
}
C.ExecuteNonQuery();
}
}
finally
{
m_Lock.ExitWriteLock();
}
}
public void ExecuteQuery(IJavascriptCallback callback, string sql, IDictionary<string, object> param = null)
{
m_Lock.EnterReadLock();
try
{
if (m_Connection.State != ConnectionState.Open)
{
m_Connection.Close();
m_Connection.Open();
}
using (var C = new SQLiteCommand(sql, m_Connection))
{
if (param != null)
{
foreach (var prop in param)
{
C.Parameters.Add(new SQLiteParameter("@" + prop.Key, prop.Value));
}
}
using (var R = C.ExecuteReader())
{
while (R.Read())
{
var row = new object[R.FieldCount];
R.GetValues(row);
callback.ExecuteAsync(row);
}
}
}
}
finally
{
m_Lock.ExitReadLock();
}
}
}
}
+2 -2
View File
@@ -69,12 +69,12 @@ namespace VRCX
public void StartVR() public void StartVR()
{ {
VRCXVR.Start(); VRCXVR.SetActive(true);
} }
public void StopVR() public void StopVR()
{ {
VRCXVR.Stop(); VRCXVR.SetActive(false);
} }
public void RefreshVR() public void RefreshVR()
+6
View File
@@ -110,6 +110,9 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Data.SQLite, Version=1.0.111.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<HintPath>packages\System.Data.SQLite.Core.1.0.111.0\lib\net451\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@@ -125,6 +128,7 @@
<Compile Include="CpuMonitor.cs" /> <Compile Include="CpuMonitor.cs" />
<Compile Include="Browser.cs" /> <Compile Include="Browser.cs" />
<Compile Include="RenderHandler.cs" /> <Compile Include="RenderHandler.cs" />
<Compile Include="SQLite.cs" />
<Compile Include="VRForm.cs"> <Compile Include="VRForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
@@ -204,8 +208,10 @@
<Error Condition="!Exists('packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets'))" /> <Error Condition="!Exists('packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets'))" />
<Error Condition="!Exists('packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.props'))" /> <Error Condition="!Exists('packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.props'))" />
<Error Condition="!Exists('packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets'))" /> <Error Condition="!Exists('packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets'))" />
<Error Condition="!Exists('packages\System.Data.SQLite.Core.1.0.111.0\build\net451\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\System.Data.SQLite.Core.1.0.111.0\build\net451\System.Data.SQLite.Core.targets'))" />
</Target> </Target>
<Import Project="packages\CefSharp.Common.73.1.130\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.73.1.130\build\CefSharp.Common.targets')" /> <Import Project="packages\CefSharp.Common.73.1.130\build\CefSharp.Common.targets" Condition="Exists('packages\CefSharp.Common.73.1.130\build\CefSharp.Common.targets')" />
<Import Project="packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets')" /> <Import Project="packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets" Condition="Exists('packages\CefSharp.WinForms.73.1.130\build\CefSharp.WinForms.targets')" />
<Import Project="packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets" Condition="Exists('packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets')" /> <Import Project="packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets" Condition="Exists('packages\CefSharp.OffScreen.73.1.130\build\CefSharp.OffScreen.targets')" />
<Import Project="packages\System.Data.SQLite.Core.1.0.111.0\build\net451\System.Data.SQLite.Core.targets" Condition="Exists('packages\System.Data.SQLite.Core.1.0.111.0\build\net451\System.Data.SQLite.Core.targets')" />
</Project> </Project>
+62 -19
View File
@@ -4,71 +4,114 @@
// For a copy, see <https://opensource.org/licenses/MIT>. // For a copy, see <https://opensource.org/licenses/MIT>.
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
namespace VRCX namespace VRCX
{ {
public class VRCXStorage public class VRCXStorage
{ {
private static readonly ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
private static Dictionary<string, string> m_Storage = new Dictionary<string, string>(); private static Dictionary<string, string> m_Storage = new Dictionary<string, string>();
private static bool m_Dirty; private static bool m_Dirty;
public static void Load() public static void Load()
{ {
JsonSerializer.Deserialize(Application.StartupPath + "/VRCX.json", ref m_Storage); m_Lock.EnterWriteLock();
try
{
JsonSerializer.Deserialize(Application.StartupPath + "/VRCX.json", ref m_Storage);
m_Dirty = false;
}
finally
{
m_Lock.ExitWriteLock();
}
} }
public static void Save() public static void Save()
{ {
JsonSerializer.Serialize(Application.StartupPath + "/VRCX.json", m_Storage); m_Lock.EnterReadLock();
} try
public void Clear()
{
lock (m_Storage)
{ {
m_Dirty = true; if (m_Dirty)
m_Storage.Clear(); {
JsonSerializer.Serialize(Application.StartupPath + "/VRCX.json", m_Storage);
m_Dirty = false;
}
}
finally
{
m_Lock.ExitReadLock();
} }
} }
public void Flush() public void Flush()
{ {
lock (m_Storage) Save();
}
public void Clear()
{
m_Lock.EnterWriteLock();
try
{ {
if (m_Dirty) if (m_Storage.Count > 0)
{ {
m_Dirty = false; m_Dirty = true;
Save();
} }
m_Storage.Clear();
}
finally
{
m_Lock.ExitWriteLock();
} }
} }
public bool Remove(string key) public bool Remove(string key)
{ {
lock (m_Storage) m_Lock.EnterWriteLock();
try
{ {
m_Dirty = true; var result = m_Storage.Remove(key);
return m_Storage.Remove(key); if (result)
{
m_Dirty = true;
}
return result;
}
finally
{
m_Lock.ExitWriteLock();
} }
} }
public string Get(string key) public string Get(string key)
{ {
lock (m_Storage) m_Lock.EnterReadLock();
try
{ {
return m_Storage.TryGetValue(key, out string value) return m_Storage.TryGetValue(key, out string value)
? value ? value
: string.Empty; : string.Empty;
} }
finally
{
m_Lock.ExitReadLock();
}
} }
public void Set(string key, string value) public void Set(string key, string value)
{ {
lock (m_Storage) m_Lock.EnterWriteLock();
try
{ {
m_Dirty = true;
m_Storage[key] = value; m_Storage[key] = value;
m_Dirty = true;
}
finally
{
m_Lock.ExitWriteLock();
} }
} }
} }
+209 -206
View File
@@ -21,7 +21,7 @@ namespace VRCX
{ {
public static class VRCXVR public static class VRCXVR
{ {
private static readonly object m_LockObject = new object(); private static readonly ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
private static List<string[]> m_Devices = new List<string[]>(); private static List<string[]> m_Devices = new List<string[]>();
private static Thread m_Thread; private static Thread m_Thread;
private static Device m_Device; private static Device m_Device;
@@ -29,6 +29,7 @@ namespace VRCX
private static Texture2D m_Texture2; private static Texture2D m_Texture2;
private static Browser m_Browser1; private static Browser m_Browser1;
private static Browser m_Browser2; private static Browser m_Browser2;
private static bool m_Active;
private static float[] m_Rotation = { 0f, 0f, 0f }; private static float[] m_Rotation = { 0f, 0f, 0f };
private static float[] m_Translation = { 0f, 0f, 0f }; private static float[] m_Translation = { 0f, 0f, 0f };
private static float[] m_L_Translation = { -7f / 100f, -5f / 100f, 6f / 100f }; private static float[] m_L_Translation = { -7f / 100f, -5f / 100f, 6f / 100f };
@@ -38,7 +39,7 @@ namespace VRCX
// NOTE // NOTE
// 메모리 릭 때문에 미리 생성해놓고 계속 사용함 // 메모리 릭 때문에 미리 생성해놓고 계속 사용함
public static void Setup() public static void Init()
{ {
m_Device = new Device(DriverType.Hardware, DeviceCreationFlags.SingleThreaded | DeviceCreationFlags.BgraSupport); m_Device = new Device(DriverType.Hardware, DeviceCreationFlags.SingleThreaded | DeviceCreationFlags.BgraSupport);
m_Texture1 = new Texture2D(m_Device, new Texture2DDescription() m_Texture1 = new Texture2D(m_Device, new Texture2DDescription()
@@ -67,38 +68,139 @@ namespace VRCX
}); });
m_Browser1 = new Browser(m_Texture1, Application.StartupPath + "/html/vr.html?1"); m_Browser1 = new Browser(m_Texture1, Application.StartupPath + "/html/vr.html?1");
m_Browser2 = new Browser(m_Texture2, Application.StartupPath + "/html/vr.html?2"); m_Browser2 = new Browser(m_Texture2, Application.StartupPath + "/html/vr.html?2");
} m_Thread = new Thread(() =>
public static void Start()
{
lock (m_LockObject)
{ {
if (m_Thread == null) var active = false;
var e = new VREvent_t();
var nextInit = DateTime.MinValue;
var nextDeviceUpdate = DateTime.MinValue;
var nextOverlay = DateTime.MinValue;
var overlayIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
var overlayVisible1 = false;
var overlayVisible2 = false;
var dashboardHandle = 0UL;
var overlayHandle1 = 0UL;
var overlayHandle2 = 0UL;
while (m_Thread != null)
{ {
m_Thread = new Thread(ThreadProc);
m_Thread.Start();
}
}
}
public static void Stop()
{
lock (m_LockObject)
{
var thread = m_Thread;
if (thread != null)
{
m_Thread = null;
try try
{ {
thread.Interrupt(); Thread.Sleep(10);
thread.Join();
} }
catch catch
{ {
// ThreadInterruptedException
}
if (m_Active)
{
m_Browser1.Render();
m_Browser2.Render();
var system = OpenVR.System;
if (system == null)
{
if (DateTime.Now.CompareTo(nextInit) <= 0)
{
continue;
}
var _err = EVRInitError.None;
system = OpenVR.Init(ref _err, EVRApplicationType.VRApplication_Overlay);
nextInit = DateTime.Now.AddSeconds(5);
if (system == null)
{
continue;
}
active = true;
}
while (system.PollNextEvent(ref e, (uint)Marshal.SizeOf(e)))
{
var type = (EVREventType)e.eventType;
if (type == EVREventType.VREvent_Quit)
{
active = false;
OpenVR.Shutdown();
nextInit = DateTime.Now.AddSeconds(10);
system = null;
break;
}
}
if (system != null)
{
if (DateTime.Now.CompareTo(nextDeviceUpdate) >= 0)
{
overlayIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
UpdateDevices(system, ref overlayIndex);
if (overlayIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{
nextOverlay = DateTime.Now.AddSeconds(10);
}
nextDeviceUpdate = DateTime.Now.AddSeconds(0.1);
}
var overlay = OpenVR.Overlay;
if (overlay != null)
{
var dashboardVisible = overlay.IsDashboardVisible();
var err = ProcessDashboard(overlay, ref dashboardHandle, dashboardVisible);
if (err != EVROverlayError.None &&
dashboardHandle != 0)
{
overlay.DestroyOverlay(dashboardHandle);
dashboardHandle = 0;
}
err = ProcessOverlay1(overlay, ref overlayHandle1, ref overlayVisible1, dashboardVisible, overlayIndex, nextOverlay);
if (err != EVROverlayError.None &&
overlayHandle1 != 0)
{
overlay.DestroyOverlay(overlayHandle1);
overlayHandle1 = 0;
}
err = ProcessOverlay2(overlay, ref overlayHandle2, ref overlayVisible2, dashboardVisible);
if (err != EVROverlayError.None &&
overlayHandle2 != 0)
{
overlay.DestroyOverlay(overlayHandle2);
overlayHandle2 = 0;
}
}
}
}
else if (active)
{
active = false;
OpenVR.Shutdown();
m_Lock.EnterWriteLock();
try
{
m_Devices.Clear();
}
finally
{
m_Lock.ExitWriteLock();
}
} }
} }
} })
{
IsBackground = true
};
m_Thread.Start();
}
public static void Exit()
{
var T = m_Thread;
m_Thread = null;
T.Interrupt();
T.Join();
m_Browser2.Dispose();
m_Browser1.Dispose();
m_Texture2.Dispose();
m_Texture1.Dispose();
m_Device.Dispose();
}
public static void SetActive(bool active)
{
m_Active = active;
} }
public static void Refresh() public static void Refresh()
@@ -109,86 +211,105 @@ namespace VRCX
public static string[][] GetDevices() public static string[][] GetDevices()
{ {
lock (m_Devices) m_Lock.EnterReadLock();
try
{ {
return m_Devices.ToArray(); return m_Devices.ToArray();
} }
finally
{
m_Lock.ExitReadLock();
}
} }
private static void UpdateDevices(CVRSystem system, ref uint trackingIndex) private static void UpdateDevices(CVRSystem system, ref uint overlayIndex)
{ {
lock (m_Devices) m_Lock.EnterWriteLock();
try
{ {
m_Devices.Clear(); m_Devices.Clear();
var sb = new StringBuilder(256); }
var state = new VRControllerState_t(); finally
for (var i = 0u; i < OpenVR.k_unMaxTrackedDeviceCount; ++i) {
m_Lock.ExitWriteLock();
}
var sb = new StringBuilder(256);
var state = new VRControllerState_t();
for (var i = 0u; i < OpenVR.k_unMaxTrackedDeviceCount; ++i)
{
var devClass = system.GetTrackedDeviceClass(i);
if (devClass == ETrackedDeviceClass.Controller ||
devClass == ETrackedDeviceClass.GenericTracker)
{ {
var devClass = system.GetTrackedDeviceClass(i); var err = ETrackedPropertyError.TrackedProp_Success;
if (devClass == ETrackedDeviceClass.Controller || var batteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref err);
devClass == ETrackedDeviceClass.GenericTracker) if (err != ETrackedPropertyError.TrackedProp_Success)
{ {
var err = ETrackedPropertyError.TrackedProp_Success; batteryPercentage = 1f;
var batteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref err); }
if (err != ETrackedPropertyError.TrackedProp_Success) sb.Clear();
{ system.GetStringTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_TrackingSystemName_String, sb, (uint)sb.Capacity, ref err);
batteryPercentage = 1f; var isOculus = sb.ToString().IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0;
} // Oculus : B/Y, Bit 1, Mask 2
sb.Clear(); // Oculus : A/X, Bit 7, Mask 128
system.GetStringTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_TrackingSystemName_String, sb, (uint)sb.Capacity, ref err); // Vive : Menu, Bit 1, Mask 2,
var isOculus = sb.ToString().IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0; // Vive : Grip, Bit 2, Mask 4
// Oculus : B/Y, Bit 1, Mask 2 var role = system.GetControllerRoleForTrackedDeviceIndex(i);
// Oculus : A/X, Bit 7, Mask 128 if (role == ETrackedControllerRole.LeftHand ||
// Vive : Menu, Bit 1, Mask 2, role == ETrackedControllerRole.RightHand)
// Vive : Grip, Bit 2, Mask 4 {
var role = system.GetControllerRoleForTrackedDeviceIndex(i); if (system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)) &&
if (role == ETrackedControllerRole.LeftHand || (state.ulButtonPressed & (isOculus ? 2u : 4u)) != 0)
role == ETrackedControllerRole.RightHand)
{
if (system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)) &&
(state.ulButtonPressed & (isOculus ? 2u : 4u)) != 0)
{
if (role == ETrackedControllerRole.LeftHand)
{
Array.Copy(m_L_Translation, m_Translation, 3);
Array.Copy(m_L_Rotation, m_Rotation, 3);
}
else
{
Array.Copy(m_R_Translation, m_Translation, 3);
Array.Copy(m_R_Rotation, m_Rotation, 3);
}
trackingIndex = i;
}
}
var type = string.Empty;
if (devClass == ETrackedDeviceClass.Controller)
{ {
if (role == ETrackedControllerRole.LeftHand) if (role == ETrackedControllerRole.LeftHand)
{ {
type = "leftController"; Array.Copy(m_L_Translation, m_Translation, 3);
} Array.Copy(m_L_Rotation, m_Rotation, 3);
else if (role == ETrackedControllerRole.RightHand)
{
type = "rightController";
} }
else else
{ {
type = "controller"; Array.Copy(m_R_Translation, m_Translation, 3);
Array.Copy(m_R_Rotation, m_Rotation, 3);
} }
overlayIndex = i;
} }
else if (devClass == ETrackedDeviceClass.GenericTracker) }
var type = string.Empty;
if (devClass == ETrackedDeviceClass.Controller)
{
if (role == ETrackedControllerRole.LeftHand)
{ {
type = "tracker"; type = "leftController";
} }
m_Devices.Add(new[] else if (role == ETrackedControllerRole.RightHand)
{ {
type, type = "rightController";
system.IsTrackedDeviceConnected(i) }
? "connected" else
: "disconnected", {
(batteryPercentage * 100).ToString() type = "controller";
}); }
}
else if (devClass == ETrackedDeviceClass.GenericTracker)
{
type = "tracker";
}
var item = new[]
{
type,
system.IsTrackedDeviceConnected(i)
? "connected"
: "disconnected",
(batteryPercentage * 100).ToString()
};
m_Lock.EnterWriteLock();
try
{
m_Devices.Add(item);
}
finally
{
m_Lock.ExitWriteLock();
} }
} }
} }
@@ -267,7 +388,7 @@ namespace VRCX
return err; return err;
} }
private static EVROverlayError ProcessOverlay1(CVROverlay overlay, ref ulong overlayHandle, ref bool overlayVisible, bool dashboardVisible, uint trackingIndex, DateTime nextRender) private static EVROverlayError ProcessOverlay1(CVROverlay overlay, ref ulong overlayHandle, ref bool overlayVisible, bool dashboardVisible, uint overlayIndex, DateTime nextOverlay)
{ {
var err = EVROverlayError.None; var err = EVROverlayError.None;
@@ -304,7 +425,7 @@ namespace VRCX
} }
} }
if (trackingIndex != OpenVR.k_unTrackedDeviceIndexInvalid) if (overlayIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{ {
// http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices // http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices
// Scaling-Rotation-Translation // Scaling-Rotation-Translation
@@ -328,7 +449,7 @@ namespace VRCX
m10 = m.M33, m10 = m.M33,
m11 = m.M43, m11 = m.M43,
}; };
err = overlay.SetOverlayTransformTrackedDeviceRelative(overlayHandle, trackingIndex, ref hm34); err = overlay.SetOverlayTransformTrackedDeviceRelative(overlayHandle, overlayIndex, ref hm34);
if (err != EVROverlayError.None) if (err != EVROverlayError.None)
{ {
return err; return err;
@@ -336,7 +457,7 @@ namespace VRCX
} }
if (!dashboardVisible && if (!dashboardVisible &&
DateTime.Now.CompareTo(nextRender) <= 0) DateTime.Now.CompareTo(nextOverlay) <= 0)
{ {
var texture = new Texture_t var texture = new Texture_t
{ {
@@ -462,123 +583,5 @@ namespace VRCX
return err; return err;
} }
private static void ThreadProc()
{
var e = new VREvent_t();
var nextOpenVRInit = DateTime.MinValue;
var nextDeviceInfoUpdate = DateTime.MinValue;
var nextRender = DateTime.MinValue;
var trackingIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
var overlayVisible1 = false;
var overlayVisible2 = false;
var dashboardHandle = 0UL;
var overlayHandle1 = 0UL;
var overlayHandle2 = 0UL;
while (m_Thread != null)
{
m_Browser1.Render();
m_Browser2.Render();
try
{
Thread.Sleep(10);
}
catch
{
// ThreadInterruptedException
}
var system = OpenVR.System;
if (system == null)
{
if (DateTime.Now.CompareTo(nextOpenVRInit) < 0)
{
continue;
}
var _err = EVRInitError.None;
system = OpenVR.Init(ref _err, EVRApplicationType.VRApplication_Overlay);
nextOpenVRInit = DateTime.Now.AddSeconds(5);
if (system == null)
{
continue;
}
}
while (system.PollNextEvent(ref e, (uint)Marshal.SizeOf(e)))
{
var type = (EVREventType)e.eventType;
if (type == EVREventType.VREvent_Quit)
{
OpenVR.Shutdown();
// VRChat이 실행 중일 때만 켜는 옵션이 생겨서 시간을 줄임
nextOpenVRInit = DateTime.Now.AddSeconds(10);
system = null;
break;
}
}
if (system == null)
{
continue;
}
if (DateTime.Now.CompareTo(nextDeviceInfoUpdate) >= 0)
{
trackingIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
UpdateDevices(system, ref trackingIndex);
if (trackingIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{
nextRender = DateTime.Now.AddSeconds(10);
}
nextDeviceInfoUpdate = DateTime.Now.AddSeconds(0.1);
}
var overlay = OpenVR.Overlay;
if (overlay == null)
{
continue;
}
var dashboardVisible = overlay.IsDashboardVisible();
var err = ProcessDashboard(overlay, ref dashboardHandle, dashboardVisible);
if (err != EVROverlayError.None &&
dashboardHandle != 0)
{
overlay.DestroyOverlay(dashboardHandle);
dashboardHandle = 0;
}
err = ProcessOverlay1(overlay, ref overlayHandle1, ref overlayVisible1, dashboardVisible, trackingIndex, nextRender);
if (err != EVROverlayError.None &&
overlayHandle1 != 0)
{
overlay.DestroyOverlay(overlayHandle1);
overlayHandle1 = 0;
}
err = ProcessOverlay2(overlay, ref overlayHandle2, ref overlayVisible2, dashboardVisible);
if (err != EVROverlayError.None &&
overlayHandle2 != 0)
{
overlay.DestroyOverlay(overlayHandle2);
overlayHandle2 = 0;
}
}
lock (m_Devices)
{
m_Devices.Clear();
}
OpenVR.Shutdown();
}
} }
} }
+3 -1
View File
@@ -44,8 +44,10 @@ namespace VRCX
}; };
Browser1.JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options); Browser1.JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options);
Browser1.JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options); Browser1.JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options);
Browser1.JavascriptObjectRepository.Register("SQLite", new SQLite(), true, options);
Browser2.JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options); Browser2.JavascriptObjectRepository.Register("VRCX", new VRCX(), true, options);
Browser2.JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options); Browser2.JavascriptObjectRepository.Register("VRCXStorage", new VRCXStorage(), false, options);
Browser2.JavascriptObjectRepository.Register("SQLite", new SQLite(), true, options);
Browser1.IsBrowserInitializedChanged += (A, B) => Browser1.IsBrowserInitializedChanged += (A, B) =>
{ {
// Browser1.ShowDevTools(); // Browser1.ShowDevTools();
@@ -60,9 +62,9 @@ namespace VRCX
private void button_refresh_Click(object sender, System.EventArgs e) private void button_refresh_Click(object sender, System.EventArgs e)
{ {
VRCXVR.Refresh();
Browser1.ExecuteScriptAsync("location.reload()"); Browser1.ExecuteScriptAsync("location.reload()");
Browser2.ExecuteScriptAsync("location.reload()"); Browser2.ExecuteScriptAsync("location.reload()");
VRCXVR.Refresh();
} }
private void button_devtools_Click(object sender, System.EventArgs e) private void button_devtools_Click(object sender, System.EventArgs e)
+1
View File
@@ -9,6 +9,7 @@ module.exports = {
'CefSharp': 'readonly', 'CefSharp': 'readonly',
'VRCX': 'readonly', 'VRCX': 'readonly',
'VRCXStorage': 'readonly', 'VRCXStorage': 'readonly',
'SQLite': 'readonly',
'LogWatcher': 'readonly', 'LogWatcher': 'readonly',
'Discord': 'readonly', 'Discord': 'readonly',
'Noty': 'readonly', 'Noty': 'readonly',
+21 -22
View File
@@ -7,6 +7,7 @@ if (window.CefSharp) {
Promise.all([ Promise.all([
CefSharp.BindObjectAsync('VRCX'), CefSharp.BindObjectAsync('VRCX'),
CefSharp.BindObjectAsync('VRCXStorage'), CefSharp.BindObjectAsync('VRCXStorage'),
CefSharp.BindObjectAsync('SQLite'),
CefSharp.BindObjectAsync('LogWatcher'), CefSharp.BindObjectAsync('LogWatcher'),
CefSharp.BindObjectAsync('Discord') CefSharp.BindObjectAsync('Discord')
]).catch(() => { ]).catch(() => {
@@ -3490,6 +3491,8 @@ if (window.CefSharp) {
var ref; var ref;
var i; var i;
var j; var j;
// FIXME
// 여러 개 켠다면 gameLogTable의 데이터가 시간순이 아닐 수도 있음
i = this.gameLogTable.data.length; i = this.gameLogTable.data.length;
j = 0; j = 0;
while (j < 25) { while (j < 25) {
@@ -4460,31 +4463,27 @@ if (window.CefSharp) {
}; };
$app.methods.refreshGameLog = function () { $app.methods.refreshGameLog = function () {
LogWatcher.HasLog().then((result) => { LogWatcher.Get().then((logs) => {
if (result) { if (logs.length) {
LogWatcher.GetLogs().then((logs) => { logs.forEach((log) => {
logs.forEach((log) => { var ctx = {
var ctx = { created_at: log[0],
created_at: log[0], type: log[1],
type: log[1], data: log[2]
data: log[2] };
}; this.gameLogTable.data.push(ctx);
this.gameLogTable.data.push(ctx); if (ctx.type === 'Location') {
if (ctx.type === 'Location') { this.lastLocation = ctx.data;
this.lastLocation = ctx.data;
}
});
this.sweepGameLog();
this.updateSharedFeed();
// sweepGameLog로 기록이 삭제되면
// 아무 것도 없는데 알림이 떠서 이상함
if (this.gameLogTable.length) {
this.notifyMenu('gameLog');
} }
}); });
} else { this.sweepGameLog();
this.updateSharedFeed(); // sweepGameLog로 기록이 삭제되면
// 아무 것도 없는데 알림이 떠서 이상함
if (this.gameLogTable.length) {
this.notifyMenu('gameLog');
}
} }
this.updateSharedFeed();
}); });
}; };
+2 -1
View File
@@ -6,7 +6,8 @@
if (window.CefSharp) { if (window.CefSharp) {
Promise.all([ Promise.all([
CefSharp.BindObjectAsync('VRCX'), CefSharp.BindObjectAsync('VRCX'),
CefSharp.BindObjectAsync('VRCXStorage') CefSharp.BindObjectAsync('VRCXStorage'),
CefSharp.BindObjectAsync('SQLite')
]).catch(() => { ]).catch(() => {
location = 'https://github.com/pypy-vrc/vrcx'; location = 'https://github.com/pypy-vrc/vrcx';
}).then(() => { }).then(() => {
+1
View File
@@ -14,4 +14,5 @@
<package id="SharpDX.Direct3D11" version="4.2.0" targetFramework="net452" /> <package id="SharpDX.Direct3D11" version="4.2.0" targetFramework="net452" />
<package id="SharpDX.DXGI" version="4.2.0" targetFramework="net452" /> <package id="SharpDX.DXGI" version="4.2.0" targetFramework="net452" />
<package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net452" /> <package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net452" />
<package id="System.Data.SQLite.Core" version="1.0.111.0" targetFramework="net452" />
</packages> </packages>