mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-18 06:13:52 +02:00
Photon logging support
This commit is contained in:
20
AppApi.cs
20
AppApi.cs
@@ -18,7 +18,6 @@ using Windows.UI.Notifications;
|
||||
using Windows.Data.Xml.Dom;
|
||||
using librsync.net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace VRCX
|
||||
{
|
||||
@@ -232,6 +231,11 @@ namespace VRCX
|
||||
return CpuMonitor.Instance.CpuUsage;
|
||||
}
|
||||
|
||||
public string GetImage(string url, string fileId, string version)
|
||||
{
|
||||
return ImageCache.GetImage(url, fileId, version);
|
||||
}
|
||||
|
||||
public void DesktopNotification(string BoldText, string Text, string Image)
|
||||
{
|
||||
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText02);
|
||||
@@ -239,8 +243,7 @@ namespace VRCX
|
||||
String imagePath = Path.Combine(Program.BaseDirectory, "VRCX.ico");
|
||||
if (!String.IsNullOrEmpty(Image))
|
||||
{
|
||||
imagePath = Path.Combine(Program.AppDataDirectory, "cache\\toast");
|
||||
File.WriteAllBytes(imagePath, Convert.FromBase64String(Image));
|
||||
imagePath = Image;
|
||||
}
|
||||
stringElements[0].AppendChild(toastXml.CreateTextNode(BoldText));
|
||||
stringElements[1].AppendChild(toastXml.CreateTextNode(Text));
|
||||
@@ -274,12 +277,11 @@ namespace VRCX
|
||||
{
|
||||
UseBase64Icon = true;
|
||||
Icon = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHaGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIxLTA0LTA4VDE0OjU3OjAxKzEyOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMS0wNC0wOFQxNjozMzoxMCsxMjowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMS0wNC0wOFQxNjozMzoxMCsxMjowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2YTY5MmQzYi03ZTJkLTNiNGUtYTMzZC1hN2MwOTNlOGU0OTkiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo1NTE2MWIyMi1hYzgxLTY3NDYtODAyYi1kODIzYWFmN2RjYjciIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3ZjJjNTA2ZS02YTVhLWRhNGEtOTg5Mi02NDZiMzQ0MGQxZTgiPiA8cGhvdG9zaG9wOkRvY3VtZW50QW5jZXN0b3JzPiA8cmRmOkJhZz4gPHJkZjpsaT5hZG9iZTpkb2NpZDpwaG90b3Nob3A6NmJmOGE5MTgtY2QzZS03OTRjLTk3NzktMzM0YjYwZWJiNTYyPC9yZGY6bGk+IDwvcmRmOkJhZz4gPC9waG90b3Nob3A6RG9jdW1lbnRBbmNlc3RvcnM+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6N2YyYzUwNmUtNmE1YS1kYTRhLTk4OTItNjQ2YjM0NDBkMWU4IiBzdEV2dDp3aGVuPSIyMDIxLTA0LTA4VDE0OjU3OjAxKzEyOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoV2luZG93cykiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmJhM2ZjODI3LTM0ZjQtYjU0OC05ZGFiLTZhMTZlZmQzZjAxMSIgc3RFdnQ6d2hlbj0iMjAyMS0wNC0wOFQxNTowMTozMSsxMjowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo2YTY5MmQzYi03ZTJkLTNiNGUtYTMzZC1hN2MwOTNlOGU0OTkiIHN0RXZ0OndoZW49IjIwMjEtMDQtMDhUMTY6MzM6MTArMTI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE5IChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4XAd9sAAAFM0lEQVR42u2aWUhjVxjHjVpf3Iraoh3c4ksFx7ZYahV8EHEBqdQHFdsHQRRxpcyDIDNFpdSK+iBKUcTpmy/iglVrtT4oYsEq7hP3RGXcqqY6invy9Xy3OdPEE5PY5pKb5P7hTyA5y/1+Ofc7y70OAOBgz3YQAYgARAAiABGACEAEIAIQAYgADBT6V4HErcRbxCAwy4nriN/DC+UDADb8swADv++fiN3MDeAJ8be0k9HRUbi4uACUWq22qFFvzt5AZ1enNoSvzJ4DiJ5j412dXSBUVf9QTQH08gHgF2x8b2/P0nGqNGa0ML9AAazyAeA3bPzg4MDoFV5fX8PZ2RlcXl7qGL83JjKsVeT2UpHyaqxzdXXFtUVvOVpMYx3JFfK3CZEPAL9i4/v7+0aDwDL5+fmQl5cHBQUFnHNzc6GsrAzW19cNBQ8dHR3q7OxsFamvxnrFxcWQnp4O4+PjRvtdW1ujANYtCgBVWlqqN0vn5ORw/6o+TU1Nga+vL1MnMTERtre3rQvA3d0dZGZmMsG4ublBW1sbU/7k5ATi4+OZ8uHh4bC5uWlSn4ICQC/I39+fCSo0NBRWV1d1M3h1NVPOw8MDenp6HtWfoACg8N92dnZmgisqKuISI2pkZAS8vLyYMngb3dzcWDcAvBUKCwuZ4FxdXWFwcJDLB1FRUczvcXFxcHx8/Ki+BAkAtbW1BZGRkUyQsbGx3Gzh5OSk831QUJBJWd9qAKD6+/vB29tbJ1CJRMIE7+7uDk1NTf+pD0EDwFuhoqKCC9rQZiYrKwtub29tDwBqZ2cHUlNTwdHRkQkcwURHRxtcKFk9ANTAwAB4enoyAHCmqKys/F9tCx4ATnuY9B4a/mFhYTA3N2e7AFpaWoweaKSkpHCbH5sDMDMzw01vxgC4uLhAfX29oAHo3Yoa0vn5OSQnJzPBZmRkQFpaGjMz+Pn5wdjYmGAB3D0WQG1tLRM8Bjk7OwsKhQICAwOZ3xMSEkw6e7AEANVjAAwPD3ObmvsBVlVVgUr1z8FOQ0MD8zsukMrLyx+1JhBcDtjd3YWIiAgmOLwdtP9dTHpJSUl6d4M4bVolADzdKSkpYYIKCAjgdn/3NT8/Dz4+Pkz5mJgYkw5DBAUAh3ZzczOzDcYVYE1NzYNL5bq6Or1LZVw7nJ6eWg8APMHBRQ0ehkilUggODuaSHp4QGdriHh0dcTMDlsV6ISEhXF0cGb29vRYHMGTqqTCWmZiYgKWlJVheXgaZTMatAw4PD43WVSqVMD09zdVD48kRtiWXy98mzYe0Id+gADb4ADCMjSuPlYJ9MKLYVFAAm3wAaMbGFxcXBQugu7ubAviDDwCfY+N4Ro/DVGjCmUIrcX7P1+PxfdpJ68tWGBoagr7+PrMZH3DiwglnBGPCtQOWxeSIM45W8IvEUr4AfEG8xPcj7sbGRqMAVpZX9NWdIv6Ur/cDqD4k/o64j/h34jEzeUTTHhdMX2+fQQCyVzIa9KXmwe0z4hB6kXwCQL2DLyEQ+xK/byZ7EfsRN1AICwsLDwLAKVZTDkfkZ8RO2hfINwA+9YQ+iUYf/nloDADe80/vN2LNAFCRxGsYx4vnL/QmRS0Ar4g/sjUAqC/pKGhvb7dLAKhyCmFyctIuAbxL3EEhaL+eowVARvyxrQJASYlnKAS6IbInAKg44lMKAYU7Ra1p8BNbB4D6hvgGY8MlMG6PNQBWiCPsAYAL8Y96lr+4ivzAHgDQpPiS+EwikfxFPl8Tf00s4RWA+Lq8CEAEIAIQAYgARAA26b8BaVJkoY+4rDoAAAAASUVORK5CYII=";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UseBase64Icon = false;
|
||||
Icon = Path.Combine(Program.AppDataDirectory, "cache\\toast");
|
||||
File.WriteAllBytes(Icon, Convert.FromBase64String(Image));
|
||||
Icon = Image;
|
||||
}
|
||||
|
||||
IPAddress broadcastIP = IPAddress.Parse("127.0.0.1");
|
||||
@@ -306,16 +308,16 @@ namespace VRCX
|
||||
var Location = Path.Combine(Program.AppDataDirectory, "update.exe");
|
||||
WebClient client = new WebClient();
|
||||
client.Headers.Add("user-agent", AppVersion);
|
||||
client.DownloadFile(new System.Uri(url), Location);
|
||||
client.DownloadFile(new Uri(url), Location);
|
||||
}
|
||||
|
||||
public void RestartApplication()
|
||||
{
|
||||
System.Diagnostics.Process VRCXProcess = new System.Diagnostics.Process();
|
||||
Process VRCXProcess = new Process();
|
||||
VRCXProcess.StartInfo.FileName = Path.Combine(Program.BaseDirectory, "VRCX.exe");
|
||||
VRCXProcess.StartInfo.UseShellExecute = false;
|
||||
VRCXProcess.Start();
|
||||
System.Environment.Exit(0);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
public bool CheckForUpdateExe()
|
||||
|
||||
53
ImageCache.cs
Normal file
53
ImageCache.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
|
||||
namespace VRCX
|
||||
{
|
||||
class ImageCache
|
||||
{
|
||||
private static readonly string cacheLocation = Path.Combine(Program.AppDataDirectory, "ImageCache");
|
||||
|
||||
public static string GetImage(string url, string fileId, string version)
|
||||
{
|
||||
var directoryLocation = Path.Combine(cacheLocation, fileId);
|
||||
var fileLocation = Path.Combine(directoryLocation, $"{version}.png");
|
||||
|
||||
if (File.Exists(fileLocation))
|
||||
{
|
||||
Directory.SetLastWriteTime(directoryLocation, DateTime.Now);
|
||||
return fileLocation;
|
||||
}
|
||||
|
||||
if (Directory.Exists(directoryLocation))
|
||||
Directory.Delete(directoryLocation, true);
|
||||
Directory.CreateDirectory(directoryLocation);
|
||||
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
client.Headers.Add("user-agent", "VRCX");
|
||||
client.DownloadFile(url, fileLocation);
|
||||
}
|
||||
|
||||
int cacheSize = Directory.GetDirectories(cacheLocation).Length;
|
||||
if (cacheSize > 1100)
|
||||
CleanImageCache();
|
||||
|
||||
return fileLocation;
|
||||
}
|
||||
|
||||
private static void CleanImageCache()
|
||||
{
|
||||
DirectoryInfo dirInfo = new DirectoryInfo(cacheLocation);
|
||||
var folders = dirInfo.GetDirectories().OrderBy(p => p.LastWriteTime);
|
||||
int i = 0;
|
||||
foreach (DirectoryInfo folder in folders.Reverse())
|
||||
{
|
||||
i++;
|
||||
if (i > 1000)
|
||||
folder.Delete(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
370
LogWatcher.cs
370
LogWatcher.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
|
||||
namespace VRCX
|
||||
@@ -22,6 +23,11 @@ namespace VRCX
|
||||
public string RecentWorldName;
|
||||
public string LastVideoURL;
|
||||
public bool ShaderKeywordsLimitReached = false;
|
||||
public bool incomingJson;
|
||||
public string jsonChunk;
|
||||
public string jsonDate;
|
||||
public string onJoinPhotonDisplayName;
|
||||
public string photonEvent;
|
||||
}
|
||||
|
||||
public static readonly LogWatcher Instance;
|
||||
@@ -33,6 +39,7 @@ namespace VRCX
|
||||
private bool m_ResetLog;
|
||||
private bool m_FirstRun = true;
|
||||
private static DateTime tillDate = DateTime.Now;
|
||||
private static IDictionary<int, string> photonEvent7 = new Dictionary<int, string>();
|
||||
|
||||
// NOTE
|
||||
// FileSystemWatcher() is unreliable
|
||||
@@ -183,6 +190,21 @@ namespace VRCX
|
||||
break;
|
||||
}
|
||||
|
||||
if (logContext.incomingJson)
|
||||
{
|
||||
logContext.jsonChunk += line;
|
||||
if (line == "}}")
|
||||
{
|
||||
var data = logContext.jsonChunk.Replace("{{", "{").Replace("}}", "}");
|
||||
ParseLogPhotonEvent(fileInfo, data, logContext.jsonDate, logContext.photonEvent);
|
||||
logContext.incomingJson = false;
|
||||
logContext.jsonChunk = String.Empty;
|
||||
logContext.jsonDate = String.Empty;
|
||||
logContext.photonEvent = String.Empty;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2020.10.31 23:36:28 Log - [VRCFlowManagerVRC] Destination fetching: wrld_4432ea9b-729c-46e3-8eaf-846aa0a37fdd
|
||||
// 2021.02.03 10:18:58 Log - [DŽDŽDžDžDžDŽDŽDžDžDŽDžDžDžDžDŽDŽDŽDžDžDŽDŽDžDžDžDžDŽDžDžDžDžDŽDŽDŽDŽDŽDžDŽDžDŽDŽDŽDžDžDŽDžDžDž] Destination fetching: wrld_4432ea9b-729c-46e3-8eaf-846aa0a37fdd
|
||||
|
||||
@@ -209,7 +231,21 @@ namespace VRCX
|
||||
var offset = 34;
|
||||
if (line[offset] == '[')
|
||||
{
|
||||
if (ParseLogOnPlayerJoinedOrLeft(fileInfo, logContext, line, offset) == true ||
|
||||
if (string.Compare(line, offset, "[Network Data] OnEvent: PLAYER: ", 0, 33, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
logContext.photonEvent = line.Substring(offset + 33);
|
||||
logContext.incomingJson = true;
|
||||
logContext.jsonChunk = String.Empty;
|
||||
logContext.jsonDate = ConvertLogTimeToISO8601(line);
|
||||
}
|
||||
else if (string.Compare(line, offset, "[Network Data] OnEvent: SYSTEM ", 0, 31, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
logContext.photonEvent = line.Substring(offset + 31);
|
||||
logContext.incomingJson = true;
|
||||
logContext.jsonChunk = String.Empty;
|
||||
logContext.jsonDate = ConvertLogTimeToISO8601(line);
|
||||
}
|
||||
else if (ParseLogOnPlayerJoinedOrLeft(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogLocation(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogLocationDestination(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogPortalSpawn(fileInfo, logContext, line, offset) == true ||
|
||||
@@ -218,8 +254,9 @@ namespace VRCX
|
||||
ParseLogJoinBlocked(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogAvatarPedestalChange(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogVideoError(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogVideoPlay(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogWorldVRCX(fileInfo, logContext, line, offset) == true)
|
||||
ParseLogVideoChange(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogWorldVRCX(fileInfo, logContext, line, offset) == true ||
|
||||
ParseLogPhotonId(fileInfo, logContext, line, offset) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -289,16 +326,26 @@ namespace VRCX
|
||||
// 2021.02.03 10:18:58 Log - [DŽDŽDžDžDžDŽDŽDžDžDŽDžDžDžDžDŽDŽDŽDžDžDŽDŽDžDžDžDžDŽDžDžDžDžDŽDŽDŽDŽDŽDžDŽDžDŽDŽDŽDžDžDŽDžDžDž] Destination fetching: wrld_4432ea9b-729c-46e3-8eaf-846aa0a37fdd
|
||||
// 2021.06.23 12:02:56 Log - [Behaviour] Entering Room: VRChat Home
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] Entering Room: ", 0, 27, StringComparison.Ordinal) == 0)
|
||||
if (line.Contains("] Entering Room: "))
|
||||
{
|
||||
var worldName = line.Substring(offset + 27);
|
||||
var lineOffset = line.LastIndexOf("] Entering Room: ");
|
||||
if (lineOffset < 0)
|
||||
return false;
|
||||
lineOffset += 17;
|
||||
|
||||
var worldName = line.Substring(lineOffset);
|
||||
logContext.RecentWorldName = worldName;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] Joining wrld_", 0, 25, StringComparison.Ordinal) == 0)
|
||||
if (line.Contains("] Joining wrld_"))
|
||||
{
|
||||
var location = line.Substring(offset + 20);
|
||||
var lineOffset = line.LastIndexOf("] Joining ");
|
||||
if (lineOffset < 0)
|
||||
return false;
|
||||
lineOffset += 10;
|
||||
|
||||
var location = line.Substring(lineOffset);
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
@@ -309,6 +356,9 @@ namespace VRCX
|
||||
logContext.RecentWorldName
|
||||
});
|
||||
|
||||
photonEvent7 = new Dictionary<int, string>();
|
||||
logContext.onJoinPhotonDisplayName = String.Empty;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -320,9 +370,14 @@ namespace VRCX
|
||||
// 2021.09.02 00:02:12 Log - [Behaviour] Destination set: wrld_4432ea9b-729c-46e3-8eaf-846aa0a37fdd:15609~private(usr_032383a7-748c-4fb2-94e4-bcb928e5de6b)~nonce(72CC87D420C1D49AEFFBEE8824C84B2DF0E38678E840661E)
|
||||
// 2021.09.02 00:49:15 Log - [Behaviour] Destination fetching: wrld_4432ea9b-729c-46e3-8eaf-846aa0a37fdd
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] Destination fetching: ", 0, 34, StringComparison.Ordinal) == 0)
|
||||
if (line.Contains("] Destination fetching: "))
|
||||
{
|
||||
var location = line.Substring(offset + 34);
|
||||
var lineOffset = line.LastIndexOf("] Destination fetching: ");
|
||||
if (lineOffset < 0)
|
||||
return false;
|
||||
lineOffset += 24;
|
||||
|
||||
var location = line.Substring(lineOffset);
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
@@ -335,20 +390,6 @@ namespace VRCX
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2021.10.04 11:54:16 Log - [Behaviour] OnLeftRoom
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] OnLeftRoom", 0, 22, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
AppendLog(new[]
|
||||
{
|
||||
fileInfo.Name,
|
||||
ConvertLogTimeToISO8601(line),
|
||||
"location-destination"
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -365,16 +406,19 @@ namespace VRCX
|
||||
|
||||
// 2021.06.23 11:41:16 Log - [Behaviour] Initialized PlayerAPI "Natsumi-sama" is local
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] Initialized PlayerAPI \"", 0, 35, StringComparison.Ordinal) == 0)
|
||||
if (line.Contains("] Initialized PlayerAPI \""))
|
||||
{
|
||||
var lineOffset = line.LastIndexOf("] Initialized PlayerAPI \"");
|
||||
if (lineOffset < 0)
|
||||
return false;
|
||||
lineOffset += 25;
|
||||
|
||||
var pos = line.LastIndexOf("\" is ");
|
||||
if (pos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var userDisplayName = line.Substring(offset + 35, pos - (offset + 35));
|
||||
var userType = line.Substring(pos + 5);
|
||||
var userDisplayName = line.Substring(lineOffset, pos - lineOffset);
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
@@ -388,25 +432,14 @@ namespace VRCX
|
||||
return true;
|
||||
}
|
||||
|
||||
// fallback method
|
||||
/*if (string.Compare(line, offset, "OnPlayerJoined ", 0, 15, StringComparison.Ordinal) == 0)
|
||||
if (line.Contains("] OnPlayerLeft "))
|
||||
{
|
||||
var userDisplayName = line.Substring(offset + 15);
|
||||
var lineOffset = line.LastIndexOf("] OnPlayerLeft ");
|
||||
if (lineOffset < 0)
|
||||
return false;
|
||||
lineOffset += 15;
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
fileInfo.Name,
|
||||
ConvertLogTimeToISO8601(line),
|
||||
"player-joined",
|
||||
userDisplayName
|
||||
});
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] OnPlayerLeft ", 0, 25, StringComparison.Ordinal) == 0)
|
||||
{
|
||||
var userDisplayName = line.Substring(offset + 25);
|
||||
var userDisplayName = line.Substring(lineOffset);
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
@@ -427,22 +460,16 @@ namespace VRCX
|
||||
// 2021.04.06 11:25:45 Log - [Network Processing] RPC invoked ConfigurePortal on (Clone [1600004] Portals/PortalInternalDynamic) for Natsumi-sama
|
||||
// 2021.07.19 04:24:28 Log - [Behaviour] Will execute SendRPC/AlwaysBufferOne on (Clone [100004] Portals/PortalInternalDynamic) (UnityEngine.GameObject) for Natsumi-sama: S: "ConfigurePortal" I: 7 F: 0 B: 255 (local master owner)
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] Will execute SendRPC/AlwaysBufferOne on (Clone [", 0, 60, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
if (!line.Contains("] Will execute SendRPC/AlwaysBufferOne on (Clone ["))
|
||||
return false;
|
||||
}
|
||||
|
||||
var pos = line.LastIndexOf("] Portals/PortalInternalDynamic) (UnityEngine.GameObject) for ");
|
||||
if (pos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var endPos = line.LastIndexOf(": S: \"ConfigurePortal\"");
|
||||
if (endPos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = line.Substring(pos + 62, endPos - (pos + 62));
|
||||
|
||||
@@ -462,36 +489,32 @@ namespace VRCX
|
||||
// 2021.04.04 12:21:06 Error - Maximum number (256) of shader keywords exceeded, keyword _TOGGLESIMPLEBLUR_ON will be ignored.
|
||||
// 2021.08.20 04:20:69 Error - Maximum number (384) of shader global keywords exceeded, keyword _FOG_EXP2 will be ignored.
|
||||
|
||||
if (logContext.ShaderKeywordsLimitReached == true)
|
||||
if (line.Contains("Maximum number (384) of shader global keywords exceeded"))
|
||||
{
|
||||
return false;
|
||||
if (logContext.ShaderKeywordsLimitReached == true)
|
||||
return true;
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
fileInfo.Name,
|
||||
ConvertLogTimeToISO8601(line),
|
||||
"event",
|
||||
"Shader Keyword Limit has been reached"
|
||||
});
|
||||
logContext.ShaderKeywordsLimitReached = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (string.Compare(line, offset, "Maximum number (384) of shader global keywords exceeded", 0, 55, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
fileInfo.Name,
|
||||
ConvertLogTimeToISO8601(line),
|
||||
"event",
|
||||
"Shader Keyword Limit has been reached"
|
||||
});
|
||||
logContext.ShaderKeywordsLimitReached = true;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ParseLogJoinBlocked(FileInfo fileInfo, LogContext logContext, string line, int offset)
|
||||
{
|
||||
// 2021.04.07 09:34:37 Error - [Behaviour] Master is not sending any events! Moving to a new instance.
|
||||
|
||||
if (string.Compare(line, offset, "[Behaviour] Master is not sending any events! Moving to a new instance.", 0, 71, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
if (!line.Contains("] Master is not sending any events! Moving to a new instance."))
|
||||
return false;
|
||||
}
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
@@ -500,6 +523,7 @@ namespace VRCX
|
||||
"event",
|
||||
"Joining instance blocked by master"
|
||||
});
|
||||
logContext.ShaderKeywordsLimitReached = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -509,9 +533,7 @@ namespace VRCX
|
||||
// 2021.05.07 10:48:19 Log - [Network Processing] RPC invoked SwitchAvatar on AvatarPedestal for User
|
||||
|
||||
if (string.Compare(line, offset, "[Network Processing] RPC invoked SwitchAvatar on AvatarPedestal for ", 0, 68, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = line.Substring(offset + 68);
|
||||
|
||||
@@ -532,9 +554,7 @@ namespace VRCX
|
||||
// 2021.04.08 06:40:07 Error - [Video Playback] ERROR: Private video
|
||||
|
||||
if (string.Compare(line, offset, "[Video Playback] ERROR: ", 0, 24, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = line.Substring(offset + 24);
|
||||
|
||||
@@ -549,29 +569,20 @@ namespace VRCX
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ParseLogVideoPlay(FileInfo fileInfo, LogContext logContext, string line, int offset)
|
||||
private bool ParseLogVideoChange(FileInfo fileInfo, LogContext logContext, string line, int offset)
|
||||
{
|
||||
// 2021.04.20 13:37:69 Log - [Video Playback] Attempting to resolve URL 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
|
||||
|
||||
if (string.Compare(line, offset, "[Video Playback] Attempting to resolve URL '", 0, 44, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pos = line.LastIndexOf("'");
|
||||
if (pos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = line.Substring(offset + 44);
|
||||
data = data.Remove(data.Length - 1);
|
||||
|
||||
if (logContext.LastVideoURL == data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
logContext.LastVideoURL = data;
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
fileInfo.Name,
|
||||
@@ -610,23 +621,18 @@ namespace VRCX
|
||||
// 2021.04.23 13:12:25 Log - User Natsumi-sama added URL https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
||||
|
||||
if (string.Compare(line, offset, "User ", 0, 5, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pos = line.LastIndexOf(" added URL ");
|
||||
if (pos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var displayName = line.Substring(offset + 5, pos - (offset + 5));
|
||||
var playerPlayer = line.Substring(offset + 5, pos - (offset + 5));
|
||||
var data = line.Substring(pos + 11);
|
||||
|
||||
if (logContext.LastVideoURL == data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
logContext.LastVideoURL = data;
|
||||
|
||||
AppendLog(new[]
|
||||
@@ -635,7 +641,7 @@ namespace VRCX
|
||||
ConvertLogTimeToISO8601(line),
|
||||
"video-play",
|
||||
data,
|
||||
displayName
|
||||
playerPlayer
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -646,15 +652,11 @@ namespace VRCX
|
||||
// 2021.01.03 05:48:58 Log - [API] Received Notification: < Notification from username:pypy, sender user id:usr_4f76a584-9d4b-46f6-8209-8305eb683661 to of type: friendRequest, id: not_3a8f66eb-613c-4351-bee3-9980e6b5652c, created at: 01/14/2021 15:38:40 UTC, details: {{}}, type:friendRequest, m seen:False, message: ""> received at 01/02/2021 16:48:58 UTC
|
||||
|
||||
if (string.Compare(line, offset, "[API] Received Notification: <", 0, 30, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pos = line.LastIndexOf("> received at ");
|
||||
if (pos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = line.Substring(offset + 30, pos - (offset + 30));
|
||||
|
||||
@@ -675,15 +677,11 @@ namespace VRCX
|
||||
// 2021.10.03 09:48:43 Log - [API] [101] Sending Get request to https://api.vrchat.cloud/api/1/users/usr_032383a7-748c-4fb2-94e4-bcb928e5de6b?apiKey=JlE5Jldo5Jibnk5O5hTx6XVqsJu4WJ26&organization=vrchat
|
||||
|
||||
if (string.Compare(line, offset, "[API] [", 0, 7, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var pos = line.LastIndexOf("] Sending Get request to ");
|
||||
if (pos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = line.Substring(pos + 25);
|
||||
|
||||
@@ -698,6 +696,174 @@ namespace VRCX
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ParseLogPhotonId(FileInfo fileInfo, LogContext logContext, string line, int offset)
|
||||
{
|
||||
// 2021.11.02 02:21:41 Log - [Behaviour] Configuring remote player VRCPlayer[Remote] 22349737 1194
|
||||
// 2021.11.02 02:21:41 Log - [Behaviour] Initialized player Natsumi-sama
|
||||
|
||||
// 2021.11.10 08:06:12 Log - [Behaviour] Natsumi-sama: Limb IK
|
||||
// 2021.11.10 08:06:12 Log - [Behaviour] NatsumiDa: 3 Point IK
|
||||
// 2021.11.10 08:10:28 Log - [Behaviour] Initialize Limb Avatar (UnityEngine.Animator) VRCPlayer[Remote] 78614426 59 (DŽDŽDŽDžDŽDžDžDŽDžDŽDŽDžDžDŽDžDŽDžDžDžDŽDŽDŽDžDŽDŽDžDžDŽDžDžDŽDžDžDŽDžDžDžDžDŽDžDŽDžDŽDŽDŽDŽDž) False Loading
|
||||
// 2021.11.10 08:57:32 Log - [Behaviour] Initialize Limb Avatar (UnityEngine.Animator) VRCPlayer[Local] 59136629 1 (DŽDŽDŽDžDŽDžDžDŽDžDŽDŽDžDžDŽDžDŽDžDžDžDŽDŽDŽDžDŽDŽDžDžDŽDžDžDŽDžDžDŽDžDžDžDžDŽDžDŽDžDŽDŽDŽDŽDž) True Loading
|
||||
|
||||
if (line.Contains("] Initialize ") && line.Contains(" Avatar (UnityEngine.Animator) VRCPlayer["))
|
||||
{
|
||||
var pos = -1;
|
||||
|
||||
if (line.Contains(" Avatar (UnityEngine.Animator) VRCPlayer[Remote] "))
|
||||
{
|
||||
pos = line.LastIndexOf(" Avatar (UnityEngine.Animator) VRCPlayer[Remote] ");
|
||||
pos += 49;
|
||||
}
|
||||
|
||||
if (line.Contains(" Avatar (UnityEngine.Animator) VRCPlayer[Local] "))
|
||||
{
|
||||
pos = line.LastIndexOf(" Avatar (UnityEngine.Animator) VRCPlayer[Local] ");
|
||||
pos += 48;
|
||||
}
|
||||
|
||||
if (pos < 0)
|
||||
return false;
|
||||
|
||||
if (!String.IsNullOrEmpty(logContext.onJoinPhotonDisplayName))
|
||||
{
|
||||
var endPos = line.LastIndexOf(" (");
|
||||
var photonId = line.Substring(pos + 9, endPos - (pos + 9));
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
fileInfo.Name,
|
||||
ConvertLogTimeToISO8601(line),
|
||||
"photon-id",
|
||||
logContext.onJoinPhotonDisplayName,
|
||||
photonId
|
||||
});
|
||||
logContext.onJoinPhotonDisplayName = String.Empty;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (line.Contains(": 3 Point IK") || line.Contains(": Limb IK"))
|
||||
{
|
||||
var lineOffset = line.IndexOf("] ");
|
||||
if (lineOffset < 0)
|
||||
return false;
|
||||
lineOffset += 2;
|
||||
|
||||
if (line.Contains(": 3 Point IK"))
|
||||
{
|
||||
var endPos = line.LastIndexOf(": 3 Point IK");
|
||||
logContext.onJoinPhotonDisplayName = line.Substring(lineOffset, endPos - lineOffset);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (line.Contains(": Limb IK"))
|
||||
{
|
||||
var endPos = line.LastIndexOf(": Limb IK");
|
||||
logContext.onJoinPhotonDisplayName = line.Substring(lineOffset, endPos - lineOffset);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public class VrcEvent
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public Parameters Parameters { get; set; }
|
||||
public int SenderKey { get; set; }
|
||||
public int CustomDataKey { get; set; }
|
||||
public int Type { get; set; }
|
||||
public string EventType { get; set; }
|
||||
public Object Data { get; set; }
|
||||
}
|
||||
|
||||
public class Parameters
|
||||
{
|
||||
[JsonPropertyName("245")]
|
||||
public _245 _245 { get; set; }
|
||||
[JsonPropertyName("254")]
|
||||
public int _254 { get; set; }
|
||||
}
|
||||
|
||||
public class _245
|
||||
{
|
||||
[JsonPropertyName("$type")]
|
||||
public string Type { get; set; }
|
||||
[JsonPropertyName("$value")]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
private void ParseLogPhotonEvent(FileInfo fileInfo, string data, string date, string photonEvent)
|
||||
{
|
||||
// 2021.09.30 04:27:11 Log - [Network Data] OnEvent: PLAYER: 253
|
||||
// 2021.09.30 04:27:40 Log - [Network Data] OnEvent: SYSTEM 255
|
||||
|
||||
if (photonEvent == "1" || photonEvent == "8" || photonEvent == "9" || photonEvent == "210")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (photonEvent == "7")
|
||||
{
|
||||
var json = System.Text.Json.JsonSerializer.Deserialize<VrcEvent>(data);
|
||||
var photonId = json.Parameters._254;
|
||||
if (photonEvent7.ContainsKey(photonId))
|
||||
{
|
||||
photonEvent7[photonId] = date;
|
||||
} else
|
||||
{
|
||||
photonEvent7.Add(photonId, date);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (photonEvent == "254")
|
||||
{
|
||||
var json = System.Text.Json.JsonSerializer.Deserialize<VrcEvent>(data);
|
||||
photonEvent7.Remove(json.Parameters._254);
|
||||
}
|
||||
|
||||
if (photonEvent == "6")
|
||||
{
|
||||
var json = System.Text.Json.JsonSerializer.Deserialize<VrcEvent>(data);
|
||||
byte[] bytes = Convert.FromBase64String(json.Parameters._245.Value);
|
||||
try
|
||||
{
|
||||
var deserialization = new VRCEventDeserialization();
|
||||
var eventData = deserialization.DeserializeData(bytes);
|
||||
json.Data = eventData.Data;
|
||||
json.Type = eventData.Type;
|
||||
json.EventType = eventData.EventType;
|
||||
data = System.Text.Json.JsonSerializer.Serialize<VrcEvent>(json);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
data = ex.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
AppendLog(new[]
|
||||
{
|
||||
fileInfo.Name,
|
||||
date,
|
||||
"photon-event",
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
public IDictionary<int, string> GetEvent7()
|
||||
{
|
||||
return photonEvent7;
|
||||
}
|
||||
|
||||
public void ClearEvent7()
|
||||
{
|
||||
photonEvent7 = new Dictionary<int, string>();
|
||||
}
|
||||
|
||||
public string[][] Get()
|
||||
{
|
||||
Update();
|
||||
|
||||
208
VRCEventDeserialization.cs
Normal file
208
VRCEventDeserialization.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace VRCX
|
||||
{
|
||||
class VRCEventDeserialization
|
||||
{
|
||||
private byte[] byteData;
|
||||
private int byteOffset;
|
||||
private static readonly Dictionary<int, Type> DataType = new Dictionary<int, Type> {
|
||||
{2, typeof(byte)},
|
||||
{3, typeof(double)},
|
||||
{4, typeof(float)},
|
||||
{5, typeof(int)},
|
||||
{6, typeof(short)},
|
||||
{7, typeof(long)},
|
||||
{8, typeof(bool)},
|
||||
{9, typeof(string)},
|
||||
{10, typeof(object[])},
|
||||
{11, typeof(IList)},
|
||||
{100, typeof(Vector2)},
|
||||
{101, typeof(Vector3)},
|
||||
{102, typeof(Vector4)},
|
||||
{103, typeof(Quaternion)}
|
||||
};
|
||||
|
||||
public class EventEntry
|
||||
{
|
||||
public int Type;
|
||||
public string EventType;
|
||||
public object Data;
|
||||
}
|
||||
|
||||
private byte DeserializeByte()
|
||||
{
|
||||
return byteData[byteOffset++];
|
||||
}
|
||||
|
||||
private int DeserializeInt()
|
||||
{
|
||||
int output = BitConverter.ToInt32(byteData, byteOffset);
|
||||
byteOffset += 4;
|
||||
return output;
|
||||
}
|
||||
|
||||
private short DeserializeShort()
|
||||
{
|
||||
short output = BitConverter.ToInt16(byteData, byteOffset);
|
||||
byteOffset += 2;
|
||||
return output;
|
||||
}
|
||||
|
||||
private string DeserializeString()
|
||||
{
|
||||
short stringLength = DeserializeShort();
|
||||
string output = Encoding.UTF8.GetString(byteData, byteOffset, stringLength);
|
||||
byteOffset += stringLength;
|
||||
return output;
|
||||
}
|
||||
|
||||
private bool DeserializeBool()
|
||||
{
|
||||
bool output = BitConverter.ToBoolean(byteData, byteOffset);
|
||||
byteOffset++;
|
||||
return output;
|
||||
}
|
||||
|
||||
private float DeserializeFloat()
|
||||
{
|
||||
float output = BitConverter.ToSingle(byteData, byteOffset);
|
||||
byteOffset += 4;
|
||||
return output;
|
||||
}
|
||||
|
||||
private double DeserializeDouble()
|
||||
{
|
||||
double output = BitConverter.ToDouble(byteData, byteOffset);
|
||||
byteOffset += 8;
|
||||
return output;
|
||||
}
|
||||
|
||||
private object DeserializeTypeArray()
|
||||
{
|
||||
short length = DeserializeShort();
|
||||
byte typeCode = DeserializeByte();
|
||||
var output = Array.CreateInstance(DataType[typeCode], length);
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
output.SetValue(DeserializeBytes(typeCode), i);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private object[] DeserializeObjectArray()
|
||||
{
|
||||
short length = DeserializeShort();
|
||||
object[] output = new object[length];
|
||||
for (var i = 0; i < output.Length; i++)
|
||||
{
|
||||
output[i] = DeserializeBytes();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
private long DeserializeInt64()
|
||||
{
|
||||
long output = BitConverter.ToInt64(byteData, byteOffset);
|
||||
byteOffset += 8;
|
||||
return output;
|
||||
}
|
||||
|
||||
private Vector2 DeserializeVector2()
|
||||
{
|
||||
return new Vector2(DeserializeFloat(), DeserializeFloat());
|
||||
}
|
||||
|
||||
private Vector3 DeserializeVector3()
|
||||
{
|
||||
return new Vector3(DeserializeFloat(), DeserializeFloat(), DeserializeFloat());
|
||||
}
|
||||
|
||||
private Vector4 DeserializeVector4()
|
||||
{
|
||||
return new Vector4(DeserializeFloat(), DeserializeFloat(), DeserializeFloat(), DeserializeFloat());
|
||||
}
|
||||
|
||||
private Quaternion DeserializeQuaternion()
|
||||
{
|
||||
return new Quaternion(DeserializeFloat(), DeserializeFloat(), DeserializeFloat(), DeserializeFloat());
|
||||
}
|
||||
|
||||
private object DeserializeBytes(byte type = 0)
|
||||
{
|
||||
if (type == 0)
|
||||
{
|
||||
type = DeserializeByte();
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case 1:
|
||||
return null;
|
||||
case 2:
|
||||
return DeserializeByte();
|
||||
case 3:
|
||||
return DeserializeDouble();
|
||||
case 4:
|
||||
return DeserializeFloat();
|
||||
case 5:
|
||||
return DeserializeInt();
|
||||
case 6:
|
||||
return DeserializeShort();
|
||||
case 7:
|
||||
return DeserializeInt64();
|
||||
case 8:
|
||||
return DeserializeBool();
|
||||
case 9:
|
||||
return DeserializeString();
|
||||
case 10:
|
||||
return DeserializeObjectArray();
|
||||
case 11:
|
||||
return DeserializeTypeArray();
|
||||
case 100:
|
||||
return DeserializeVector2();
|
||||
case 101:
|
||||
return DeserializeVector3();
|
||||
case 102:
|
||||
return DeserializeVector4();
|
||||
case 103:
|
||||
return DeserializeQuaternion();
|
||||
default:
|
||||
throw new Exception("Ignoring data type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public EventEntry DeserializeData(byte[] bytes)
|
||||
{
|
||||
EventEntry eventEntry = new EventEntry();
|
||||
byteOffset = 0;
|
||||
byteData = bytes;
|
||||
byte type = DeserializeByte();
|
||||
if (type == 106)
|
||||
{
|
||||
byteOffset += 8;
|
||||
int length = DeserializeShort();
|
||||
byteOffset += length;
|
||||
eventEntry.Type = DeserializeByte();
|
||||
byteOffset += 10;
|
||||
eventEntry.EventType = DeserializeString();
|
||||
byteOffset += 5;
|
||||
eventEntry.Data = null;
|
||||
if (byteData.Length > byteOffset + 3)
|
||||
{
|
||||
byteData = (byte[])DeserializeTypeArray();
|
||||
byteOffset = 0;
|
||||
eventEntry.Data = DeserializeBytes();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected type: " + type);
|
||||
}
|
||||
return eventEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
@@ -81,6 +81,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssetBundleCacher.cs" />
|
||||
<Compile Include="ImageCache.cs" />
|
||||
<Compile Include="VRCEventDeserialization.cs" />
|
||||
<Compile Include="IPCClient.cs" />
|
||||
<Compile Include="IPCServer.cs" />
|
||||
<Compile Include="StartupArgs.cs" />
|
||||
|
||||
1432
html/src/app.js
1432
html/src/app.js
File diff suppressed because it is too large
Load Diff
@@ -82,10 +82,14 @@
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.el-table__expanded-cell[class*='cell'] {
|
||||
.el-table--mini .el-table__expanded-cell[class*='cell'] {
|
||||
padding: 20px 50px;
|
||||
}
|
||||
|
||||
.el-table--mini .el-table__cell {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 20px;
|
||||
}
|
||||
@@ -615,3 +619,20 @@ i.x-user-status.busy {
|
||||
.el-form-item {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.photon-event-table .el-table--mini .el-table__cell,
|
||||
.current-instance-table .el-table--mini .el-table__cell {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.photon-event-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.current-instance-table img.friends-list-avatar {
|
||||
width: unset;
|
||||
height: 16px;
|
||||
margin-right: 0;
|
||||
margin-left: 3px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
export var appVersion = 'VRCX 2021.11.04';
|
||||
export var appVersion = 'VRCX 2021.11.20';
|
||||
|
||||
@@ -59,6 +59,7 @@ html
|
||||
span= name
|
||||
+menuitem('feed', 'Feed', 'el-icon-news')
|
||||
+menuitem('gameLog', 'Game Log', 'el-icon-s-data')
|
||||
+menuitem('playerList', 'Player List', 'el-icon-tickets')
|
||||
+menuitem('search', 'Search', 'el-icon-search')
|
||||
+menuitem('favorite', 'Favorite', 'el-icon-star-off')
|
||||
+menuitem('friendLog', 'Friend Log', 'el-icon-notebook-2')
|
||||
@@ -68,6 +69,98 @@ html
|
||||
+menuitem('profile', 'Profile', 'el-icon-user')
|
||||
+menuitem('settings', 'Settings', 'el-icon-s-tools')
|
||||
|
||||
//- playerList
|
||||
.x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'playerList'")
|
||||
div(style="display:flex;flex-direction:column;height:100%")
|
||||
div(v-if="currentInstanceWorld.id" style="display:flex")
|
||||
el-popover(placement="right" width="500px" trigger="click" style="height:120px")
|
||||
img.x-link(slot="reference" v-lazy="currentInstanceWorld.thumbnailImageUrl" style="flex:none;width:160px;height:120px;border-radius:4px")
|
||||
img.x-link(v-lazy="currentInstanceWorld.imageUrl" style="width:500px;height:375px" @click="openExternalLink(currentInstanceWorld.imageUrl)")
|
||||
div(style="margin-left:10px;display:flex;flex-direction:column")
|
||||
div
|
||||
span.x-link(@click="showWorldDialog(currentInstanceWorld.id)" style="font-weight:bold;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1")
|
||||
| #[i.el-icon-s-home(v-show="API.currentUser.$homeLocation && API.currentUser.$homeLocation.worldId === currentInstanceWorld.id")] {{ currentInstanceWorld.name }}
|
||||
div
|
||||
span.x-link(v-text="currentInstanceWorld.authorName" @click="showUserDialog(currentInstanceWorld.authorId)" style="color:#909399;font-family:monospace")
|
||||
div(style="margin-top:5px")
|
||||
el-tag(v-if="currentInstanceWorld.$isLabs" type="primary" effect="plain" size="mini") Labs
|
||||
el-tag(v-else-if="currentInstanceWorld.releaseStatus === 'public'" type="success" effect="plain" size="mini") Public
|
||||
el-tag(v-else-if="currentInstanceWorld.releaseStatus === 'private'" type="danger" effect="plain" size="mini") Private
|
||||
span(style="margin-left:5px")
|
||||
span \#{{ currentInstanceLocation.instanceName }} {{ currentInstanceLocation.accessType }}
|
||||
span.famfamfam-flags(v-if="currentInstanceLocation.region === 'eu'" class="europeanunion" style="display:inline-block;margin-left:5px")
|
||||
span.famfamfam-flags(v-else-if="currentInstanceLocation.region === 'jp'" class="jp" style="display:inline-block;margin-left:5px")
|
||||
span.famfamfam-flags(v-else class="us" style="display:inline-block;margin-left:5px")
|
||||
span(v-if="lastLocation.playerList.size > 0" style="margin-left:5px")
|
||||
| {{ lastLocation.playerList.size }}
|
||||
| #[template(v-if="lastLocation.friendList.size > 0") ({{ lastLocation.friendList.size }})]
|
||||
template(v-if="photonLobbyBots.length > 0")
|
||||
|
|
||||
el-tooltip(placement="bottom")
|
||||
template(#content)
|
||||
span Photon Bot Id's: {{ photonLobbyBots.toString() }}
|
||||
span(v-text="photonLobbyBots.length" style="color:red")
|
||||
//- el-tag(type="info" effect="plain" size="mini" v-text="worldDialog.fileSize" style="margin-right:5px;margin-top:5px")
|
||||
div(style="margin-top:5px")
|
||||
span(v-show="currentInstanceWorld.name !== currentInstanceWorld.description" v-text="currentInstanceWorld.description" style="font-size:12px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2")
|
||||
div.current-instance-table
|
||||
data-tables(v-bind="currentInstanceUserList" @sort-change="updateTimers" @row-click="selectCurrentInstanceRow" style="margin-top:10px;cursor:pointer")
|
||||
el-table-column(label="Avatar" width="60" prop="photo")
|
||||
template(v-once #default="scope")
|
||||
template(v-if="userImage(scope.row.ref)")
|
||||
el-popover(placement="right" height="500px" trigger="hover")
|
||||
img.friends-list-avatar(slot="reference" v-lazy="userImage(scope.row.ref)")
|
||||
img.friends-list-avatar(v-lazy="userImageFull(scope.row.ref)" style="height:500px;cursor:pointer" @click="openExternalLink(userImageFull(scope.row.ref))")
|
||||
el-table-column(label="Timer" width="90" prop="timer" sortable)
|
||||
template(v-once #default="scope")
|
||||
timer(:epoch="scope.row.timer")
|
||||
el-table-column(label="Photon Id" width="100" prop="photonId" sortable)
|
||||
template(v-once #default="scope")
|
||||
span(v-text="scope.row.photonId")
|
||||
el-table-column(label="Display Name" min-width="140" prop="ref.displayName")
|
||||
template(v-once #default="scope")
|
||||
span(v-text="scope.row.ref.displayName" :class="scope.row.ref.$trustColor")
|
||||
el-table-column(label="Status" min-width="180" prop="ref.status")
|
||||
template(v-once #default="scope")
|
||||
template(v-if="scope.row.ref.status")
|
||||
i.x-user-status(:class="statusClass(scope.row.ref.status)")
|
||||
span
|
||||
span(v-text="scope.row.ref.statusDescription")
|
||||
el-table-column(label="Language" width="100" prop="ref.$languages")
|
||||
template(v-once #default="scope")
|
||||
el-tooltip(v-for="item in scope.row.ref.$languages" :key="item.key" placement="top")
|
||||
template(#content)
|
||||
span {{ item.value }} ({{ item.key }})
|
||||
span.famfamfam-flags(:class="languageClass(item.key)" style="display:inline-block;margin-left:5px")
|
||||
el-table-column(label="Bio Links" width="100" prop="ref.bioLinks")
|
||||
template(v-once #default="scope")
|
||||
el-tooltip(v-if="link" v-for="(link, index) in scope.row.ref.bioLinks" :key="index")
|
||||
template(#content)
|
||||
span(v-text="link")
|
||||
img(:src="getFaviconUrl(link)" style="width:16px;height:16px;vertical-align:middle;margin-right:5px;cursor:pointer" @click.stop="openExternalLink(link)")
|
||||
div.photon-event-table(v-if="photonEventTable.data.length > 0")
|
||||
data-tables(v-bind="photonEventTable" style="margin-bottom:10px")
|
||||
el-table-column(label="Date" prop="created_at" width="90")
|
||||
template(v-once #default="scope")
|
||||
el-tooltip(placement="right")
|
||||
template(#content)
|
||||
span {{ scope.row.created_at | formatDate('YYYY-MM-DD HH24:MI:SS') }}
|
||||
span {{ scope.row.created_at | formatDate('MM-DD HH24:MI') }}
|
||||
el-table-column(label="Name" prop="photonId" width="160")
|
||||
template(v-once #default="scope")
|
||||
span.x-link(v-text="getDisplayNameFromPhotonId(scope.row.photonId)" @click="showUserFromPhotonId(scope.row.photonId)" style="padding-right:10px")
|
||||
el-table-column(label="Event" prop="text")
|
||||
template(v-once #default="scope")
|
||||
span(v-if="scope.row.avatar")
|
||||
span ChangeAvatar
|
||||
span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)")
|
||||
|
|
||||
span.avatar-info-public(v-if="scope.row.avatar.releaseStatus === 'public'") (Public)
|
||||
span.avatar-info-own(v-else-if="scope.row.avatar.releaseStatus === 'private'") (Private)
|
||||
template(v-if="scope.row.avatar.description && scope.row.avatar.name !== scope.row.avatar.description")
|
||||
| - {{ scope.row.avatar.description }}
|
||||
span(v-else v-text="scope.row.text")
|
||||
|
||||
//- feed
|
||||
.x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'feed'")
|
||||
data-tables(v-bind="feedTable" v-loading="feedTable.loading")
|
||||
@@ -411,7 +504,7 @@ html
|
||||
template(#tool)
|
||||
div(style="margin:0 0 10px;display:flex;align-items:center")
|
||||
el-select(v-model="playerModerationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" placeholder="Filter")
|
||||
el-option(v-once v-for="type in ['block', 'mute', 'unmute', 'hideAvatar', 'showAvatar']" :key="type" :label="type" :value="type")
|
||||
el-option(v-once v-for="type in ['block', 'unblock', 'mute', 'unmute', 'hideAvatar', 'showAvatar']" :key="type" :label="type" :value="type")
|
||||
el-input(v-model="playerModerationTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px")
|
||||
el-tooltip(placement="bottom" content="Refresh" :disabled="hideTooltips")
|
||||
el-button(type="default" :loading="API.isPlayerModerationsLoading" @click="API.refreshPlayerModerations()" icon="el-icon-refresh" circle style="flex:none")
|
||||
@@ -806,7 +899,7 @@ html
|
||||
span.color-picker(slot="trigger") #[i.el-icon-s-open] Veteran User
|
||||
div
|
||||
v-swatches(v-model="trustColor.legendary" show-fallback fallback-input-type="color" popover-x="right" :swatches="trustColorSwatches" class="x-tag-legendary")
|
||||
span.color-picker(slot="trigger") #[i.el-icon-s-open] Early User
|
||||
span.color-picker(slot="trigger") #[i.el-icon-s-open] Legend
|
||||
div
|
||||
v-swatches(v-model="trustColor.vip" show-fallback fallback-input-type="color" popover-x="right" :swatches="trustColorSwatches" class="x-tag-vip")
|
||||
span.color-picker(slot="trigger") #[i.el-icon-s-open] VRChat Team
|
||||
@@ -977,6 +1070,33 @@ html
|
||||
div.options-container-item
|
||||
span.name Dance worlds only
|
||||
el-switch(v-model="progressPieFilter" @change="changeYouTubeApi" :disabled="!openVR")
|
||||
div.options-container
|
||||
span.header Photon Logging Overlay
|
||||
el-tooltip(placement="top" style="margin-left:5px" content="Requires '--log-debug-levels=API;NetworkData' steam launch option")
|
||||
i.el-icon-warning
|
||||
div.options-container-item
|
||||
span.sub-header Photon Event HUD
|
||||
div.options-container-item
|
||||
span.name Enable
|
||||
el-switch(v-model="photonEventOverlay" @change="saveEventOverlay" :disabled="!openVR")
|
||||
div.options-container-item
|
||||
span.name Filter
|
||||
el-radio-group(v-model="photonEventOverlayFilter" @change="saveEventOverlay" size="mini" :disabled="!openVR || !photonEventOverlay")
|
||||
el-radio-button(label="VIP")
|
||||
el-radio-button(label="Friends")
|
||||
el-radio-button(label="Everyone")
|
||||
span.sub-header User timeout HUD
|
||||
div.options-container-item
|
||||
span.name Enable
|
||||
el-switch(v-model="timeoutHudOverlay" @change="saveEventOverlay" :disabled="!openVR")
|
||||
div.options-container-item
|
||||
span.name Filter
|
||||
el-radio-group(v-model="timeoutHudOverlayFilter" @change="saveEventOverlay" size="mini" :disabled="!openVR || !timeoutHudOverlay")
|
||||
el-radio-button(label="VIP")
|
||||
el-radio-button(label="Friends")
|
||||
el-radio-button(label="Everyone")
|
||||
div.options-container-item
|
||||
el-button(size="small" icon="el-icon-time" @click="promptPhotonLobbyTimeoutThreshold" :disabled="!openVR") Timeout Threshold
|
||||
div.options-container
|
||||
span.header VRCX Instance Cache/Debug
|
||||
div.options-container-item
|
||||
@@ -1595,7 +1715,7 @@ html
|
||||
el-dialog.x-dialog(ref="favoriteDialog" :visible.sync="favoriteDialog.visible" title="Choose Group" width="300px")
|
||||
div(v-loading="favoriteDialog.loading")
|
||||
el-button(v-for="group in favoriteDialog.groups" :key="group.name" style="display:block;width:100%;margin:10px 0" @click="addFavorite(group)" :disabled="group.count >= group.capacity") {{ group.displayName }} ({{ group.count }} / {{ group.capacity }})
|
||||
|
||||
|
||||
//- dialog: invite
|
||||
el-dialog.x-dialog(ref="inviteDialog" :visible.sync="inviteDialog.visible" title="Invite" width="450px")
|
||||
div(v-loading="inviteDialog.loading")
|
||||
@@ -2088,10 +2208,42 @@ html
|
||||
el-radio-button(label="VIP")
|
||||
el-radio-button(label="Friends")
|
||||
el-radio-button(label="Everyone")
|
||||
br
|
||||
.toggle-item
|
||||
span.toggle-name Photon Event Logging
|
||||
el-tooltip(placement="top" style="margin-left:5px" content="Requires '--log-debug-levels=API;NetworkData' steam launch option")
|
||||
i.el-icon-warning
|
||||
.toggle-item
|
||||
span.toggle-name Lobby Avatar Change
|
||||
el-radio-group(v-model="sharedFeedFilters.noty.AvatarChange" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="VIP")
|
||||
el-radio-button(label="Friends")
|
||||
el-radio-button(label="Everyone")
|
||||
.toggle-item
|
||||
span.toggle-name Blocked
|
||||
el-radio-group(v-model="sharedFeedFilters.noty.Blocked" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
.toggle-item
|
||||
span.toggle-name Unblocked
|
||||
el-radio-group(v-model="sharedFeedFilters.noty.Unblocked" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
.toggle-item
|
||||
span.toggle-name Muted
|
||||
el-radio-group(v-model="sharedFeedFilters.noty.Muted" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
.toggle-item
|
||||
span.toggle-name Unmuted
|
||||
el-radio-group(v-model="sharedFeedFilters.noty.Unmuted" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
template(#footer)
|
||||
el-button(type="small" @click="cancelSharedFeedFilters") Cancel
|
||||
el-button(type="primary" size="small" style="margin-left:10px" @click="saveSharedFeedFilters") Save
|
||||
|
||||
|
||||
//- dialog: wrist feed filters
|
||||
el-dialog.x-dialog(ref="wristFeedFiltersDialog" :visible.sync="wristFeedFiltersDialog.visible" title="Wrist Feed Filters" width="500px")
|
||||
.toggle-list
|
||||
@@ -2244,6 +2396,38 @@ html
|
||||
el-radio-button(label="VIP")
|
||||
el-radio-button(label="Friends")
|
||||
el-radio-button(label="Everyone")
|
||||
br
|
||||
.toggle-item
|
||||
span.toggle-name Photon Event Logging
|
||||
el-tooltip(placement="top" style="margin-left:5px" content="Requires '--log-debug-levels=API;NetworkData' steam launch option")
|
||||
i.el-icon-warning
|
||||
.toggle-item
|
||||
span.toggle-name Lobby Avatar Change
|
||||
el-radio-group(v-model="sharedFeedFilters.wrist.AvatarChange" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="VIP")
|
||||
el-radio-button(label="Friends")
|
||||
el-radio-button(label="Everyone")
|
||||
.toggle-item
|
||||
span.toggle-name Blocked
|
||||
el-radio-group(v-model="sharedFeedFilters.wrist.Blocked" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
.toggle-item
|
||||
span.toggle-name Unblocked
|
||||
el-radio-group(v-model="sharedFeedFilters.wrist.Unblocked" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
.toggle-item
|
||||
span.toggle-name Muted
|
||||
el-radio-group(v-model="sharedFeedFilters.wrist.Muted" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
.toggle-item
|
||||
span.toggle-name Unmuted
|
||||
el-radio-group(v-model="sharedFeedFilters.wrist.Unmuted" size="mini")
|
||||
el-radio-button(label="Off")
|
||||
el-radio-button(label="On")
|
||||
template(#footer)
|
||||
el-button(type="small" @click="cancelSharedFeedFilters") Cancel
|
||||
el-button(type="primary" size="small" @click="saveSharedFeedFilters") Save
|
||||
|
||||
@@ -29,6 +29,9 @@ class Database {
|
||||
await sqliteService.executeNonQuery(
|
||||
`CREATE TABLE IF NOT EXISTS ${Database.userPrefix}_notifications (id TEXT PRIMARY KEY, created_at TEXT, type TEXT, sender_user_id TEXT, sender_username TEXT, receiver_user_id TEXT, message TEXT, world_id TEXT, world_name TEXT, image_url TEXT, invite_message TEXT, request_message TEXT, response_message TEXT, expired INTEGER)`
|
||||
);
|
||||
await sqliteService.executeNonQuery(
|
||||
`CREATE TABLE IF NOT EXISTS ${Database.userPrefix}_moderation (user_id TEXT PRIMARY KEY, updated_at TEXT, display_name TEXT, block INTEGER, mute INTEGER)`
|
||||
);
|
||||
await sqliteService.executeNonQuery(
|
||||
`CREATE TABLE IF NOT EXISTS memos (user_id TEXT PRIMARY KEY, edited_at TEXT, memo TEXT)`
|
||||
);
|
||||
@@ -1104,6 +1107,59 @@ class Database {
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
async getModeration(input) {
|
||||
var userId = input.replaceAll("'", '');
|
||||
var row = {};
|
||||
await sqliteService.execute((dbRow) => {
|
||||
var block = false;
|
||||
var mute = false;
|
||||
if (dbRow[3] === 1) {
|
||||
block = true;
|
||||
}
|
||||
if (dbRow[4] === 1) {
|
||||
mute = true;
|
||||
}
|
||||
row = {
|
||||
userId: dbRow[0],
|
||||
updatedAt: dbRow[1],
|
||||
displayName: dbRow[2],
|
||||
block,
|
||||
mute
|
||||
};
|
||||
}, `SELECT * FROM ${Database.userPrefix}_moderation WHERE user_id = '${userId}'`);
|
||||
return row;
|
||||
}
|
||||
|
||||
setModeration(entry) {
|
||||
var block = 0;
|
||||
var mute = 0;
|
||||
if (entry.block) {
|
||||
block = 1;
|
||||
}
|
||||
if (entry.mute) {
|
||||
mute = 1;
|
||||
}
|
||||
sqliteService.executeNonQuery(
|
||||
`INSERT OR REPLACE INTO ${Database.userPrefix}_moderation (user_id, updated_at, display_name, block, mute) VALUES (@user_id, @updated_at, @display_name, @block, @mute)`,
|
||||
{
|
||||
'@user_id': entry.userId,
|
||||
'@updated_at': entry.updatedAt,
|
||||
'@display_name': entry.displayName,
|
||||
'@block': block,
|
||||
'@mute': mute
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
deleteModeration(userId) {
|
||||
sqliteService.executeNonQuery(
|
||||
`DELETE FROM ${Database.userPrefix}_moderation WHERE user_id = @user_id`,
|
||||
{
|
||||
'@user_id': userId
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var self = new Database();
|
||||
|
||||
@@ -51,6 +51,15 @@ class GameLogService {
|
||||
gameLog.url = args[0];
|
||||
break;
|
||||
|
||||
case 'photon-event':
|
||||
gameLog.json = args[0];
|
||||
break;
|
||||
|
||||
case 'photon-id':
|
||||
gameLog.displayName = args[0];
|
||||
gameLog.photonId = args[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11,19 +11,10 @@ import locale from 'element-ui/lib/locale/lang/en';
|
||||
import MarqueeText from 'vue-marquee-text-component';
|
||||
Vue.component('marquee-text', MarqueeText);
|
||||
|
||||
import configRepository from './repository/config.js';
|
||||
|
||||
(async function () {
|
||||
var $app = null;
|
||||
|
||||
await CefSharp.BindObjectAsync(
|
||||
'AppApi',
|
||||
'WebApi',
|
||||
'SharedVariable',
|
||||
'SQLite'
|
||||
);
|
||||
|
||||
await configRepository.init();
|
||||
await CefSharp.BindObjectAsync('AppApi');
|
||||
|
||||
Noty.overrideDefaults({
|
||||
animation: {
|
||||
@@ -170,6 +161,17 @@ import configRepository from './repository/config.js';
|
||||
}
|
||||
});
|
||||
|
||||
var removeFromArray = function (array, item) {
|
||||
var {length} = array;
|
||||
for (var i = 0; i < length; ++i) {
|
||||
if (array[i] === item) {
|
||||
array.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var $app = {
|
||||
data: {
|
||||
// 1 = 대시보드랑 손목에 보이는거
|
||||
@@ -179,6 +181,7 @@ import configRepository from './repository/config.js';
|
||||
cpuUsage: 0,
|
||||
config: {},
|
||||
downloadProgress: 0,
|
||||
photonLobbyBotSize: 0,
|
||||
nowPlaying: {
|
||||
url: '',
|
||||
name: '',
|
||||
@@ -289,12 +292,18 @@ import configRepository from './repository/config.js';
|
||||
|
||||
$app.methods.configUpdate = function (json) {
|
||||
this.config = JSON.parse(json);
|
||||
this.hudFeed = [];
|
||||
this.hudTimeout = [];
|
||||
};
|
||||
|
||||
$app.methods.updateDownloadProgress = function (progress) {
|
||||
this.downloadProgress = parseInt(progress, 10);
|
||||
};
|
||||
|
||||
$app.methods.updatePhotonLobbyBotSize = function (size) {
|
||||
this.photonLobbyBotSize = parseInt(size, 10);
|
||||
};
|
||||
|
||||
$app.methods.nowPlayingUpdate = function (json) {
|
||||
this.nowPlaying = JSON.parse(json);
|
||||
if (this.appType === '2') {
|
||||
@@ -356,7 +365,7 @@ import configRepository from './repository/config.js';
|
||||
var text = '';
|
||||
var img = '';
|
||||
if (image) {
|
||||
img = `<img class="noty-img" src="data:image/png;base64, ${image}"></img>`;
|
||||
img = `<img class="noty-img" src="${image}"></img>`;
|
||||
}
|
||||
switch (noty.type) {
|
||||
case 'OnPlayerJoined':
|
||||
@@ -455,6 +464,18 @@ import configRepository from './repository/config.js';
|
||||
case 'MutedOnPlayerLeft':
|
||||
text = `Muted user <strong>${noty.displayName}</strong> has left`;
|
||||
break;
|
||||
case 'Blocked':
|
||||
text = `<strong>${noty.displayName}</strong> has blocked you`;
|
||||
break;
|
||||
case 'Unblocked':
|
||||
text = `<strong>${noty.displayName}</strong> has unblocked you`;
|
||||
break;
|
||||
case 'Muted':
|
||||
text = `<strong>${noty.displayName}</strong> has muted you`;
|
||||
break;
|
||||
case 'Unmuted':
|
||||
text = `<strong>${noty.displayName}</strong> has unmuted you`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -510,6 +531,61 @@ import configRepository from './repository/config.js';
|
||||
Noty.closeAll();
|
||||
};
|
||||
|
||||
$app.data.hudFeed = [];
|
||||
$app.data.cleanHudFeedLoopStatus = false;
|
||||
|
||||
$app.methods.cleanHudFeedLoop = function () {
|
||||
if (!this.cleanHudFeedLoopStatus) {
|
||||
return;
|
||||
}
|
||||
this.cleanHudFeed();
|
||||
if (this.hudFeed.length === 0) {
|
||||
this.cleanHudFeedLoopStatus = false;
|
||||
return;
|
||||
}
|
||||
setTimeout(() => this.cleanHudFeedLoop(), 500);
|
||||
};
|
||||
|
||||
$app.methods.cleanHudFeed = function () {
|
||||
var dt = Date.now();
|
||||
this.hudFeed.forEach((item) => {
|
||||
if (item.time + 6000 < dt) {
|
||||
removeFromArray(this.hudFeed, item);
|
||||
}
|
||||
});
|
||||
if (this.hudFeed.length > 10) {
|
||||
this.hudFeed.length = 10;
|
||||
}
|
||||
if (!this.cleanHudFeedLoopStatus) {
|
||||
this.cleanHudFeedLoopStatus = true;
|
||||
this.cleanHudFeedLoop();
|
||||
}
|
||||
};
|
||||
|
||||
$app.methods.addEntryHudFeed = function (json) {
|
||||
var {displayName, text} = JSON.parse(json);
|
||||
var combo = 1;
|
||||
this.hudFeed.forEach((item) => {
|
||||
if (item.displayName === displayName && item.text === text) {
|
||||
combo = item.combo + 1;
|
||||
removeFromArray(this.hudFeed, item);
|
||||
}
|
||||
});
|
||||
this.hudFeed.unshift({
|
||||
time: Date.now(),
|
||||
displayName,
|
||||
text,
|
||||
combo
|
||||
});
|
||||
this.cleanHudFeed();
|
||||
};
|
||||
|
||||
$app.data.hudTimeout = [];
|
||||
|
||||
$app.methods.updateHudTimeout = function (json) {
|
||||
this.hudTimeout = JSON.parse(json);
|
||||
};
|
||||
|
||||
$app = new Vue($app);
|
||||
window.$app = $app;
|
||||
})();
|
||||
|
||||
@@ -397,6 +397,7 @@ html
|
||||
span(style="float:right") {{ lastLocationTimer }}
|
||||
span(style="display:inline-block") {{ lastLocation.playerList.length }}
|
||||
span(style="display:inline-block;font-weight:bold") {{ lastLocation.friendList.length !== 0 ? ` (${lastLocation.friendList.length})` : ''}}
|
||||
span(v-if="photonLobbyBotSize > 0 && lastLocation.playerList.length > 0" style="display:inline-block;color:red;margin-left:5px") {{ photonLobbyBotSize }}
|
||||
template(v-else)
|
||||
template(v-if="downloadProgress === 100")
|
||||
span(style="display:inline-block;margin-right:5px") Downloading: #[i.el-icon-loading]
|
||||
@@ -406,11 +407,24 @@ html
|
||||
span(style="float:right") Timer: {{ lastLocationTimer }}
|
||||
span(style="display:inline-block") Players: {{ lastLocation.playerList.length }}
|
||||
span(style="display:inline-block;font-weight:bold") {{ lastLocation.friendList.length !== 0 ? ` (${lastLocation.friendList.length})` : ''}}
|
||||
span(v-if="photonLobbyBotSize > 0 && lastLocation.playerList.length > 0" style="display:inline-block;color:red;margin-left:5px") {{ photonLobbySize }}
|
||||
br
|
||||
span(style="float:right") {{ currentTime | formatDate('YYYY-MM-DD HH:MI:SS AMPM') }}
|
||||
span CPU {{ cpuUsage }}%
|
||||
template(v-else)
|
||||
svg(class="np-progress-circle")
|
||||
circle(class="np-progress-circle-stroke" cx="60" cy="60" stroke="white" r="30" fill="transparent" stroke-width="60")
|
||||
.hud-feed
|
||||
div(v-for="feed in hudFeed")
|
||||
.item <strong>{{ feed.displayName }}</strong> {{ feed.text }}
|
||||
template(v-if="feed.combo > 1")
|
||||
span.combo x{{ feed.combo }}
|
||||
.hud-timeout(v-if="hudTimeout.length > 0")
|
||||
.hud-timeout-feed
|
||||
div(v-for="feed in hudTimeout")
|
||||
p.item ({{ feed.time }}s) {{ feed.displayName }}
|
||||
svg(version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve")
|
||||
path(fill="#ED1B24" d="M68.6,96.5L87,78.1c1.6-1.6,1.6-4.1,0-5.7s-4.1-1.6-5.7,0L62.9,90.9L44.5,72.5l18.4-18.4c1.6-1.6,1.6-4.1,0-5.7c-1.6-1.6-4.1-1.6-5.7,0L38.9,66.8l-6.4-6.4L21.2,71.8C11,82,9.7,97.9,17.4,109.5L0,126.9l8.5,8.5L25.9,118c11.6,7.7,27.5,6.4,37.8-3.8L75,102.9C75,102.9,68.6,96.5,68.6,96.5z")
|
||||
path(fill="#ED1B24" d="M102.9,75l11.3-11.3c10.3-10.3,11.5-26.1,3.8-37.8l17.4-17.4L126.9,0l-17.4,17.4C97.9,9.7,82,11,71.8,21.2L60.5,32.5C102,74,60.8,32.9,102.9,75z")
|
||||
script(src="vendor.js")
|
||||
script(src="vr.js")
|
||||
|
||||
@@ -179,8 +179,8 @@ button {
|
||||
font-family: 'Noto Sans JP', 'Noto Sans KR', 'Meiryo UI', 'Malgun Gothic',
|
||||
'Segoe UI', sans-serif;
|
||||
line-height: normal;
|
||||
text-shadow: #000 0px 0px 2px, #000 0px 0px 2px, #000 0px 0px 2px,
|
||||
#000 0px 0px 2px, #000 0px 0px 2px, #000 0px 0px 2px;
|
||||
text-shadow: #000 0px 0px 3px, #000 0px 0px 3px, #000 0px 0px 3px,
|
||||
#000 0px 0px 3px, #000 0px 0px 3px, #000 0px 0px 3px;
|
||||
}
|
||||
|
||||
.x-app {
|
||||
@@ -350,3 +350,49 @@ i.x-user-status.busy {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
.hud-feed {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.hud-feed .item,
|
||||
.hud-timeout .item {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hud-feed .item {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.hud-feed .combo {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.hud-timeout .item {
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.hud-timeout {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.hud-timeout-feed {
|
||||
position: absolute;
|
||||
bottom: 150px;
|
||||
right: 0;
|
||||
color: #ed1b24;
|
||||
}
|
||||
|
||||
.hud-timeout svg {
|
||||
position: absolute;
|
||||
right: -160px;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user