Updates and fixes

This commit is contained in:
Natsumi
2024-01-09 23:22:31 +13:00
parent 581d5fe418
commit cd2387aa32
16 changed files with 260 additions and 137 deletions
-32
View File
@@ -147,25 +147,6 @@ namespace VRCX
VRCXVR.Instance.Restart(); VRCXVR.Instance.Restart();
} }
/// <summary>
/// Returns an array of arrays containing information about the connected VR devices.
/// Each sub-array contains the type of device and its current state
/// </summary>
/// <returns>An array of arrays containing information about the connected VR devices.</returns>
public string[][] GetVRDevices()
{
return VRCXVR.Instance.GetDevices();
}
/// <summary>
/// Returns the current CPU usage as a percentage.
/// </summary>
/// <returns>The current CPU usage as a percentage.</returns>
public float CpuUsage()
{
return CpuMonitor.Instance.CpuUsage;
}
/// <summary> /// <summary>
/// Retrieves an image from the VRChat API and caches it for future use. The function will return the cached image if it already exists. /// Retrieves an image from the VRChat API and caches it for future use. The function will return the cached image if it already exists.
/// </summary> /// </summary>
@@ -352,19 +333,6 @@ namespace VRCX
WinformThemer.DoFunny(); WinformThemer.DoFunny();
} }
/// <summary>
/// Returns the number of milliseconds that the system has been running.
/// </summary>
/// <returns>The number of milliseconds that the system has been running.</returns>
public double GetUptime()
{
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
return TimeSpan.FromSeconds(uptime.NextValue()).TotalMilliseconds;
}
}
/// <summary> /// <summary>
/// Returns a color value derived from the given user ID. /// Returns a color value derived from the given user ID.
/// This is, essentially, and is used for, random colors. /// This is, essentially, and is used for, random colors.
+62
View File
@@ -0,0 +1,62 @@
using System;
using System.Diagnostics;
using System.Globalization;
using CefSharp;
namespace VRCX
{
public class AppApiVr
{
public static readonly AppApiVr Instance;
static AppApiVr()
{
Instance = new AppApiVr();
}
public void VrInit()
{
if (MainForm.Instance?.Browser != null && !MainForm.Instance.Browser.IsLoading && MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame)
MainForm.Instance.Browser.ExecuteScriptAsync("$app.vrInit", "");
}
/// <summary>
/// Returns the current CPU usage as a percentage.
/// </summary>
/// <returns>The current CPU usage as a percentage.</returns>
public float CpuUsage()
{
return CpuMonitor.Instance.CpuUsage;
}
/// <summary>
/// Returns an array of arrays containing information about the connected VR devices.
/// Each sub-array contains the type of device and its current state
/// </summary>
/// <returns>An array of arrays containing information about the connected VR devices.</returns>
public string[][] GetVRDevices()
{
return VRCXVR.Instance.GetDevices();
}
/// <summary>
/// Returns the number of milliseconds that the system has been running.
/// </summary>
/// <returns>The number of milliseconds that the system has been running.</returns>
public double GetUptime()
{
using var uptime = new PerformanceCounter("System", "System Up Time");
uptime.NextValue();
return TimeSpan.FromSeconds(uptime.NextValue()).TotalMilliseconds;
}
/// <summary>
/// Returns the current language of the operating system.
/// </summary>
/// <returns>The current language of the operating system.</returns>
public string CurrentCulture()
{
return CultureInfo.CurrentCulture.ToString();
}
}
}
+22 -21
View File
@@ -58,51 +58,52 @@ namespace VRCX
/// Starts the VRChat game process with the specified command-line arguments. /// Starts the VRChat game process with the specified command-line arguments.
/// </summary> /// </summary>
/// <param name="arguments">The command-line arguments to pass to the VRChat game.</param> /// <param name="arguments">The command-line arguments to pass to the VRChat game.</param>
public void StartGame(string arguments) public bool StartGame(string arguments)
{ {
// try stream first // try stream first
try try
{ {
using (var key = Registry.ClassesRoot.OpenSubKey(@"steam\shell\open\command")) using var key = Registry.ClassesRoot.OpenSubKey(@"steam\shell\open\command");
// "C:\Program Files (x86)\Steam\steam.exe" -- "%1"
var match = Regex.Match(key.GetValue(string.Empty) as string, "^\"(.+?)\\\\steam.exe\"");
if (match.Success)
{ {
// "C:\Program Files (x86)\Steam\steam.exe" -- "%1" var path = match.Groups[1].Value;
var match = Regex.Match(key.GetValue(string.Empty) as string, "^\"(.+?)\\\\steam.exe\""); // var _arguments = Uri.EscapeDataString(arguments);
if (match.Success) Process.Start(new ProcessStartInfo
{
var path = match.Groups[1].Value;
// var _arguments = Uri.EscapeDataString(arguments);
Process.Start(new ProcessStartInfo
{ {
WorkingDirectory = path, WorkingDirectory = path,
FileName = $"{path}\\steam.exe", FileName = $"{path}\\steam.exe",
UseShellExecute = false, UseShellExecute = false,
Arguments = $"-applaunch 438100 {arguments}" Arguments = $"-applaunch 438100 {arguments}"
}).Close(); })
return; ?.Close();
} return true;
} }
} }
catch catch
{ {
logger.Warn("Failed to start VRChat from Steam");
} }
// fallback // fallback
try try
{ {
using (var key = Registry.ClassesRoot.OpenSubKey(@"VRChat\shell\open\command")) using var key = Registry.ClassesRoot.OpenSubKey(@"VRChat\shell\open\command");
// "C:\Program Files (x86)\Steam\steamapps\common\VRChat\launch.exe" "%1" %*
var match = Regex.Match(key.GetValue(string.Empty) as string, "(?!\")(.+?\\\\VRChat.*)(!?\\\\launch.exe\")");
if (match.Success)
{ {
// "C:\Program Files (x86)\Steam\steamapps\common\VRChat\launch.exe" "%1" %* var path = match.Groups[1].Value;
var match = Regex.Match(key.GetValue(string.Empty) as string, "(?!\")(.+?\\\\VRChat.*)(!?\\\\launch.exe\")"); return StartGameFromPath(path, arguments);
if (match.Success)
{
var path = match.Groups[1].Value;
StartGameFromPath(path, arguments);
}
} }
} }
catch catch
{ {
logger.Warn("Failed to start VRChat from registry");
} }
return false;
} }
/// <summary> /// <summary>
@@ -116,7 +117,7 @@ namespace VRCX
if (!path.EndsWith(".exe")) if (!path.EndsWith(".exe"))
path = Path.Combine(path, "launch.exe"); path = Path.Combine(path, "launch.exe");
if (!File.Exists(path)) if (!path.EndsWith("launch.exe") || !File.Exists(path))
return false; return false;
Process.Start(new ProcessStartInfo Process.Start(new ProcessStartInfo
@@ -1,11 +1,10 @@
using System;
using CefSharp; using CefSharp;
namespace VRCX namespace VRCX
{ {
public static class Util public static class JavascriptBindings
{ {
public static void ApplyJavascriptBindings(IJavascriptObjectRepository repository) public static void ApplyAppJavascriptBindings(IJavascriptObjectRepository repository)
{ {
repository.NameConverter = null; repository.NameConverter = null;
repository.Register("AppApi", AppApi.Instance); repository.Register("AppApi", AppApi.Instance);
@@ -17,5 +16,11 @@ namespace VRCX
repository.Register("Discord", Discord.Instance); repository.Register("Discord", Discord.Instance);
repository.Register("AssetBundleCacher", AssetBundleCacher.Instance); repository.Register("AssetBundleCacher", AssetBundleCacher.Instance);
} }
public static void ApplyVrJavascriptBindings(IJavascriptObjectRepository repository)
{
repository.NameConverter = null;
repository.Register("AppApiVr", AppApiVr.Instance);
}
} }
} }
+1 -1
View File
@@ -63,7 +63,7 @@ namespace VRCX
Browser.ShowDevTools(); Browser.ShowDevTools();
}; };
Util.ApplyJavascriptBindings(Browser.JavascriptObjectRepository); JavascriptBindings.ApplyAppJavascriptBindings(Browser.JavascriptObjectRepository);
Browser.ConsoleMessage += (_, args) => Browser.ConsoleMessage += (_, args) =>
{ {
jslogger.Debug(args.Message + " (" + args.Source + ":" + args.Line + ")"); jslogger.Debug(args.Message + " (" + args.Source + ":" + args.Line + ")");
+1 -1
View File
@@ -37,7 +37,7 @@ namespace VRCX
Size = new System.Drawing.Size(width, height); Size = new System.Drawing.Size(width, height);
RenderHandler = this; RenderHandler = this;
Util.ApplyJavascriptBindings(JavascriptObjectRepository); JavascriptBindings.ApplyVrJavascriptBindings(JavascriptObjectRepository);
} }
public new void Dispose() public new void Dispose()
+2 -2
View File
@@ -45,8 +45,8 @@ namespace VRCX
Dock = DockStyle.Fill Dock = DockStyle.Fill
}; };
Util.ApplyJavascriptBindings(_browser1.JavascriptObjectRepository); JavascriptBindings.ApplyVrJavascriptBindings(_browser1.JavascriptObjectRepository);
Util.ApplyJavascriptBindings(_browser2.JavascriptObjectRepository); JavascriptBindings.ApplyVrJavascriptBindings(_browser2.JavascriptObjectRepository);
panel1.Controls.Add(_browser1); panel1.Controls.Add(_browser1);
panel2.Controls.Add(_browser2); panel2.Controls.Add(_browser2);
+46 -15
View File
@@ -13,26 +13,41 @@ namespace VRCX
{ {
public class WorldDBManager public class WorldDBManager
{ {
public static WorldDBManager Instance; public static readonly WorldDBManager Instance;
private readonly HttpListener listener; private readonly HttpListener listener;
private readonly WorldDatabase worldDB; private readonly WorldDatabase worldDB;
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private const string WorldDBServerUrl = "http://127.0.0.1:22500/";
private string lastError = null; private string lastError = null;
private bool debugWorld = false; private bool debugWorld = false;
public WorldDBManager(string url) static WorldDBManager()
{ {
Instance = this; Instance = new WorldDBManager();
// http://localhost:22500
listener = new HttpListener();
listener.Prefixes.Add(url);
worldDB = new WorldDatabase(Path.Combine(Program.AppDataDirectory, "VRCX-WorldData.db"));
} }
public async Task Start() public WorldDBManager()
{
// http://localhost:22500
listener = new HttpListener();
listener.Prefixes.Add(WorldDBServerUrl);
worldDB = new WorldDatabase(Path.Combine(Program.AppDataDirectory, "VRCX-WorldData.db"));
}
public void Init()
{
if (VRCXStorage.Instance.Get("VRCX_DisableWorldDatabase") == "true")
{
logger.Info("World database is disabled. Not starting.");
return;
}
Task.Run(Start);
}
private async Task Start()
{ {
// typing this in vr gonna kms // typing this in vr gonna kms
try try
@@ -223,9 +238,13 @@ namespace VRCX
} }
var worldOverride = request.QueryString["world"]; var worldOverride = request.QueryString["world"];
if (worldOverride == "global")
{
TryInitializeWorld(worldOverride, out connectionKey);
}
if (worldOverride != null && worldId != worldOverride) if (worldOverride != null && worldId != worldOverride)
{ {
var allowed = worldDB.GetWorldAllowExternalRead(worldOverride); var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global";
if (!allowed) if (!allowed)
{ {
return ConstructSuccessResponse(null, connectionKey); return ConstructSuccessResponse(null, connectionKey);
@@ -262,9 +281,13 @@ namespace VRCX
} }
var worldOverride = request.QueryString["world"]; var worldOverride = request.QueryString["world"];
if (worldOverride == "global")
{
TryInitializeWorld(worldOverride, out connectionKey);
}
if (worldOverride != null && worldId != worldOverride) if (worldOverride != null && worldId != worldOverride)
{ {
var allowed = worldDB.GetWorldAllowExternalRead(worldOverride); var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global";
if (!allowed) if (!allowed)
{ {
return ConstructSuccessResponse(null, connectionKey); return ConstructSuccessResponse(null, connectionKey);
@@ -319,9 +342,13 @@ namespace VRCX
} }
var worldOverride = request.QueryString["world"]; var worldOverride = request.QueryString["world"];
if (worldOverride == "global")
{
TryInitializeWorld(worldOverride, out connectionKey);
}
if (worldOverride != null && worldId != worldOverride) if (worldOverride != null && worldId != worldOverride)
{ {
var allowed = worldDB.GetWorldAllowExternalRead(worldOverride); var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global";
if (!allowed) if (!allowed)
{ {
return ConstructSuccessResponse(null, connectionKey); return ConstructSuccessResponse(null, connectionKey);
@@ -526,8 +553,6 @@ namespace VRCX
return; return;
} }
// Make sure the connection key is a valid GUID. No point in doing anything else if it's not. // Make sure the connection key is a valid GUID. No point in doing anything else if it's not.
if (!debugWorld && !Guid.TryParse(request.ConnectionKey, out Guid _)) if (!debugWorld && !Guid.TryParse(request.ConnectionKey, out Guid _))
{ {
@@ -540,6 +565,12 @@ namespace VRCX
// Get the world ID from the connection key // Get the world ID from the connection key
string worldId = worldDB.GetWorldByConnectionKey(request.ConnectionKey); string worldId = worldDB.GetWorldByConnectionKey(request.ConnectionKey);
// Global override
if (request.ConnectionKey == "global")
{
worldId = "global";
}
// World ID is null, which means the connection key is invalid (or someone just deleted a world from the DB while VRCX was running lol). // World ID is null, which means the connection key is invalid (or someone just deleted a world from the DB while VRCX was running lol).
if (worldId == null) if (worldId == null)
{ {
+2 -4
View File
@@ -136,15 +136,13 @@ namespace VRCX
logger.Info("{0} Starting...", Version); logger.Info("{0} Starting...", Version);
// I'll re-do this whole function eventually I swear
var worldDBServer = new WorldDBManager("http://127.0.0.1:22500/");
Task.Run(worldDBServer.Start);
ProcessMonitor.Instance.Init(); ProcessMonitor.Instance.Init();
SQLiteLegacy.Instance.Init(); SQLiteLegacy.Instance.Init();
VRCXStorage.Load(); VRCXStorage.Load();
CpuMonitor.Instance.Init(); CpuMonitor.Instance.Init();
Discord.Instance.Init(); Discord.Instance.Init();
WorldDBManager.Instance.Init();
WebApi.Instance.Init(); WebApi.Instance.Init();
LogWatcher.Instance.Init(); LogWatcher.Instance.Init();
AutoAppLaunchManager.Instance.Init(); AutoAppLaunchManager.Instance.Init();
@@ -161,7 +159,7 @@ namespace VRCX
AutoAppLaunchManager.Instance.Exit(); AutoAppLaunchManager.Instance.Exit();
LogWatcher.Instance.Exit(); LogWatcher.Instance.Exit();
WebApi.Instance.Exit(); WebApi.Instance.Exit();
worldDBServer.Stop(); WorldDBManager.Instance.Stop();
Discord.Instance.Exit(); Discord.Instance.Exit();
CpuMonitor.Instance.Exit(); CpuMonitor.Instance.Exit();
+3 -3
View File
@@ -117,12 +117,12 @@
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CefSharp.OffScreen.NETCore" Version="120.1.80" /> <PackageReference Include="CefSharp.OffScreen.NETCore" Version="120.1.110" />
<PackageReference Include="CefSharp.WinForms.NETCore" Version="120.1.80" /> <PackageReference Include="CefSharp.WinForms.NETCore" Version="120.1.110" />
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" /> <PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" /> <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.6" /> <PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" /> <PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" /> <PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" /> <PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
+1
View File
@@ -29,6 +29,7 @@
"LogWatcher": "readonly", "LogWatcher": "readonly",
"Discord": "readonly", "Discord": "readonly",
"AppApi": "readonly", "AppApi": "readonly",
"AppApiVr": "readonly",
"SharedVariable": "readonly", "SharedVariable": "readonly",
"WebApi": "readonly", "WebApi": "readonly",
"AssetBundleCacher": "readonly" "AssetBundleCacher": "readonly"
+52 -19
View File
@@ -643,8 +643,8 @@ speechSynthesis.getVoices();
options.N > 0 options.N > 0
? options.N > options.params.offset ? options.N > options.params.offset
: options.N < 0 : options.N < 0
? args.json.length ? args.json.length
: options.params.n === args.json.length) : options.params.n === args.json.length)
) { ) {
this.bulk(options); this.bulk(options);
} else if ('done' in options) { } else if ('done' in options) {
@@ -4684,7 +4684,7 @@ speechSynthesis.getVoices();
} }
this.errorNoty = new Noty({ this.errorNoty = new Noty({
type: 'error', type: 'error',
text: `WebSocket Error: ${err}` text: escapeTag(`WebSocket Error: ${err}`)
}).show(); }).show();
return; return;
} }
@@ -14687,14 +14687,10 @@ speechSynthesis.getVoices();
'VRCX_StartAtWindowsStartup', 'VRCX_StartAtWindowsStartup',
false false
); );
$app.data.isStartAsMinimizedState = false; $app.data.isStartAsMinimizedState =
$app.data.isCloseToTray = false; (await VRCXStorage.Get('VRCX_StartAsMinimizedState')) === 'true';
VRCXStorage.Get('VRCX_StartAsMinimizedState').then((result) => { $app.data.isCloseToTray =
$app.isStartAsMinimizedState = result === 'true'; (await VRCXStorage.Get('VRCX_CloseToTray')) === 'true';
});
VRCXStorage.Get('VRCX_CloseToTray').then((result) => {
$app.isCloseToTray = result === 'true';
});
if (await configRepository.getBool('VRCX_CloseToTray')) { if (await configRepository.getBool('VRCX_CloseToTray')) {
// move back to JSON // move back to JSON
$app.data.isCloseToTray = $app.data.isCloseToTray =
@@ -14702,6 +14698,8 @@ speechSynthesis.getVoices();
VRCXStorage.Set('VRCX_CloseToTray', $app.data.isCloseToTray.toString()); VRCXStorage.Set('VRCX_CloseToTray', $app.data.isCloseToTray.toString());
await configRepository.remove('VRCX_CloseToTray'); await configRepository.remove('VRCX_CloseToTray');
} }
$app.data.disableWorldDatabase =
(await VRCXStorage.Get('VRCX_DisableWorldDatabase')) === 'true';
$app.methods.saveVRCXWindowOption = async function () { $app.methods.saveVRCXWindowOption = async function () {
await configRepository.setBool( await configRepository.setBool(
'VRCX_StartAtWindowsStartup', 'VRCX_StartAtWindowsStartup',
@@ -14712,6 +14710,10 @@ speechSynthesis.getVoices();
this.isStartAsMinimizedState.toString() this.isStartAsMinimizedState.toString()
); );
VRCXStorage.Set('VRCX_CloseToTray', this.isCloseToTray.toString()); VRCXStorage.Set('VRCX_CloseToTray', this.isCloseToTray.toString());
VRCXStorage.Set(
'VRCX_DisableWorldDatabase',
this.disableWorldDatabase.toString()
);
AppApi.SetStartup(this.isStartAtWindowsStartup); AppApi.SetStartup(this.isStartAtWindowsStartup);
}; };
$app.data.photonEventOverlay = await configRepository.getBool( $app.data.photonEventOverlay = await configRepository.getBool(
@@ -16662,6 +16664,16 @@ speechSynthesis.getVoices();
D.isShowAvatar = true; D.isShowAvatar = true;
} }
}); });
} else {
database
.getUserStats(D.ref, inCurrentWorld)
.then((ref1) => {
if (ref1.userId === D.id) {
D.lastSeen = ref1.created_at;
D.joinCount = ref1.joinCount;
D.timeSpent = ref1.timeSpent;
}
});
} }
API.getRepresentedGroup({ userId }).then((args1) => { API.getRepresentedGroup({ userId }).then((args1) => {
D.representedGroup = args1.json; D.representedGroup = args1.json;
@@ -19541,14 +19553,25 @@ speechSynthesis.getVoices();
$app.launchOptionsDialog.visible = false; $app.launchOptionsDialog.visible = false;
}); });
$app.methods.updateLaunchOptions = async function () { $app.methods.updateLaunchOptions = function () {
var D = this.launchOptionsDialog; var D = this.launchOptionsDialog;
D.visible = false;
D.launchArguments = String(D.launchArguments) D.launchArguments = String(D.launchArguments)
.replace(/\s+/g, ' ') .replace(/\s+/g, ' ')
.trim(); .trim();
await configRepository.setString('launchArguments', D.launchArguments); configRepository.setString('launchArguments', D.launchArguments);
await configRepository.setString( if (
D.vrcLaunchPathOverride &&
D.vrcLaunchPathOverride.endsWith('.exe') &&
!D.vrcLaunchPathOverride.endsWith('launch.exe')
) {
this.$message({
message:
'Invalid path, you must enter VRChat folder or launch.exe',
type: 'error'
});
return;
}
configRepository.setString(
'vrcLaunchPathOverride', 'vrcLaunchPathOverride',
D.vrcLaunchPathOverride D.vrcLaunchPathOverride
); );
@@ -19556,6 +19579,7 @@ speechSynthesis.getVoices();
message: 'Updated launch options', message: 'Updated launch options',
type: 'success' type: 'success'
}); });
D.visible = false;
}; };
$app.methods.showLaunchOptions = function () { $app.methods.showLaunchOptions = function () {
@@ -20101,10 +20125,19 @@ speechSynthesis.getVoices();
} }
}); });
} else { } else {
AppApi.StartGame(args.join(' ')); AppApi.StartGame(args.join(' ')).then((result) => {
this.$message({ if (!result) {
message: 'VRChat launched', this.$message({
type: 'success' message:
'Failed to find VRChat, set a custom path in launch options',
type: 'error'
});
} else {
this.$message({
message: 'VRChat launched',
type: 'success'
});
}
}); });
} }
console.log('Launch Game', args.join(' '), desktopMode); console.log('Launch Game', args.join(' '), desktopMode);
+9 -1
View File
@@ -407,6 +407,14 @@ html
i.el-icon-warning i.el-icon-warning
span.extra(v-if="userDialog.timeSpent === 0") - span.extra(v-if="userDialog.timeSpent === 0") -
span.extra(v-else) {{ userDialog.timeSpent | timeToText }} span.extra(v-else) {{ userDialog.timeSpent | timeToText }}
template(v-else)
.x-friend-item(@click="showPreviousInstancesUserDialog(userDialog.ref)")
.detail
span.name {{ $t('dialog.user.info.play_time') }}
el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')")
i.el-icon-warning
span.extra(v-if="userDialog.timeSpent === 0") -
span.extra(v-else) {{ userDialog.timeSpent | timeToText }}
.x-friend-item(style="cursor:default") .x-friend-item(style="cursor:default")
el-tooltip(placement="top") el-tooltip(placement="top")
template(#content) template(#content)
@@ -1486,7 +1494,7 @@ html
el-button(type="primary" size="small" @click="createGroupInstance()" :disabled="!newInstanceDialog.groupId") {{ $t('dialog.new_instance.create_instance') }} el-button(type="primary" size="small" @click="createGroupInstance()" :disabled="!newInstanceDialog.groupId") {{ $t('dialog.new_instance.create_instance') }}
//- dialog: launch options //- dialog: launch options
el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="launchOptionsDialog" :visible.sync="launchOptionsDialog.visible" :title="$t('dialog.launch_options.header')" width="500px") el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="launchOptionsDialog" :visible.sync="launchOptionsDialog.visible" :title="$t('dialog.launch_options.header')" width="600px")
div(style="font-size:12px") div(style="font-size:12px")
| {{ $t('dialog.launch_options.description') }} #[br] | {{ $t('dialog.launch_options.description') }} #[br]
| {{ $t('dialog.launch_options.example') }} #[el-tag(size="mini") --fps=144] | {{ $t('dialog.launch_options.example') }} #[el-tag(size="mini") --fps=144]
+6 -1
View File
@@ -403,6 +403,10 @@
"header": "Automatically Manage Cache When Closing VRChat", "header": "Automatically Manage Cache When Closing VRChat",
"description": "Auto delete old versions from cache" "description": "Auto delete old versions from cache"
}, },
"disable_local_world_persistence": {
"header": "Disable Local World Persistence",
"description": "Disable localhost webserver (requires restart)"
},
"remote_database": { "remote_database": {
"header": "Remote Avatar Database", "header": "Remote Avatar Database",
"enable": "Enable", "enable": "Enable",
@@ -582,6 +586,7 @@
"last_seen": "Last Seen", "last_seen": "Last Seen",
"join_count": "Join Count", "join_count": "Join Count",
"time_together": "Time Together", "time_together": "Time Together",
"play_time": "Play Time",
"online_for": "Online For", "online_for": "Online For",
"offline_for": "Offline For", "offline_for": "Offline For",
"last_activity": "Last Activity", "last_activity": "Last Activity",
@@ -592,7 +597,7 @@
"avatar_cloning": "Avatar Cloning", "avatar_cloning": "Avatar Cloning",
"avatar_cloning_allow": "Allowed", "avatar_cloning_allow": "Allowed",
"avatar_cloning_deny": "Deny", "avatar_cloning_deny": "Deny",
"home_location": "Home Location", "home_location": "Home World",
"id": "User ID", "id": "User ID",
"id_tooltip": "Copy to clipboard", "id_tooltip": "Copy to clipboard",
"copy_id": "Copy ID", "copy_id": "Copy ID",
+5
View File
@@ -415,6 +415,11 @@ mixin settingsTab()
div.options-container-item div.options-container-item
span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.auto_cache_management.description') }} span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.auto_cache_management.description') }}
el-switch(v-model="autoSweepVRChatCache" @change="saveOpenVROption") el-switch(v-model="autoSweepVRChatCache" @change="saveOpenVROption")
//- Advanced | Disable local world database
span.sub-header {{ $t('view.settings.advanced.advanced.disable_local_world_persistence.header') }}
div.options-container-item
span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.disable_local_world_persistence.description') }}
el-switch(v-model="disableWorldDatabase" @change="saveVRCXWindowOption")
//- Advanced | Remote Avatar Database //- Advanced | Remote Avatar Database
div.options-container div.options-container
span.header {{ $t('view.settings.advanced.advanced.remote_database.header') }} span.header {{ $t('view.settings.advanced.advanced.remote_database.header') }}
+43 -37
View File
@@ -20,7 +20,7 @@ Vue.component('marquee-text', MarqueeText);
(async function () { (async function () {
var $app = null; var $app = null;
await CefSharp.BindObjectAsync('AppApi'); await CefSharp.BindObjectAsync('AppApiVr');
Noty.overrideDefaults({ Noty.overrideDefaults({
animation: { animation: {
@@ -50,6 +50,18 @@ Vue.component('marquee-text', MarqueeText);
String(s).replace(/["&'<>]/gu, (c) => `&#${c.charCodeAt(0)};`); String(s).replace(/["&'<>]/gu, (c) => `&#${c.charCodeAt(0)};`);
Vue.filter('escapeTag', escapeTag); Vue.filter('escapeTag', escapeTag);
var escapeTagRecursive = (obj) => {
if (typeof obj === 'string') {
return escapeTag(obj);
}
if (typeof obj === 'object') {
for (var key in obj) {
obj[key] = escapeTagRecursive(obj[key]);
}
}
return obj;
};
var commaNumber = (n) => var commaNumber = (n) =>
String(Number(n) || 0).replace(/(\d)(?=(\d{3})+(?!\d))/gu, '$1,'); String(Number(n) || 0).replace(/(\d)(?=(\d{3})+(?!\d))/gu, '$1,');
Vue.filter('commaNumber', commaNumber); Vue.filter('commaNumber', commaNumber);
@@ -216,10 +228,7 @@ Vue.component('marquee-text', MarqueeText);
watch: {}, watch: {},
el: '#x-app', el: '#x-app',
mounted() { mounted() {
workerTimers.setTimeout( workerTimers.setTimeout(() => AppApiVr.VrInit(), 1000);
() => AppApi.ExecuteAppFunction('vrInit', ''),
1000
);
if (this.appType === '1') { if (this.appType === '1') {
this.updateStatsLoop(); this.updateStatsLoop();
} }
@@ -410,7 +419,7 @@ Vue.component('marquee-text', MarqueeText);
.replace(',', ''); .replace(',', '');
if (!this.config.hideCpuUsageFromFeed) { if (!this.config.hideCpuUsageFromFeed) {
var cpuUsage = await AppApi.CpuUsage(); var cpuUsage = await AppApiVr.CpuUsage();
this.cpuUsage = cpuUsage.toFixed(0); this.cpuUsage = cpuUsage.toFixed(0);
} }
if (this.lastLocation.date !== 0) { if (this.lastLocation.date !== 0) {
@@ -429,7 +438,7 @@ Vue.component('marquee-text', MarqueeText);
} }
if (!this.config.hideDevicesFromFeed) { if (!this.config.hideDevicesFromFeed) {
AppApi.GetVRDevices().then((devices) => { AppApiVr.GetVRDevices().then((devices) => {
var deviceList = []; var deviceList = [];
var baseStations = 0; var baseStations = 0;
devices.forEach((device) => { devices.forEach((device) => {
@@ -480,7 +489,7 @@ Vue.component('marquee-text', MarqueeText);
this.devices = []; this.devices = [];
} }
if (this.config.pcUptimeOnFeed) { if (this.config.pcUptimeOnFeed) {
AppApi.GetUptime().then((uptime) => { AppApiVr.GetUptime().then((uptime) => {
this.pcUptime = timeToText(uptime); this.pcUptime = timeToText(uptime);
}); });
} else { } else {
@@ -494,7 +503,12 @@ Vue.component('marquee-text', MarqueeText);
$app.methods.playNoty = function (json) { $app.methods.playNoty = function (json) {
var { noty, message, image } = JSON.parse(json); var { noty, message, image } = JSON.parse(json);
var message = escapeTag(message); if (typeof noty === 'undefined') {
console.error('noty is undefined');
return;
}
var noty = escapeTagRecursive(noty);
var message = escapeTag(message) || '';
var text = ''; var text = '';
var img = ''; var img = '';
if (image) { if (image) {
@@ -515,8 +529,8 @@ Vue.component('marquee-text', MarqueeText);
noty.displayName noty.displayName
}</strong> is in ${this.displayLocation( }</strong> is in ${this.displayLocation(
noty.location, noty.location,
escapeTag(noty.worldName), noty.worldName,
escapeTag(noty.groupName) noty.groupName
)}`; )}`;
break; break;
case 'Online': case 'Online':
@@ -524,8 +538,8 @@ Vue.component('marquee-text', MarqueeText);
if (noty.worldName) { if (noty.worldName) {
locationName = ` to ${this.displayLocation( locationName = ` to ${this.displayLocation(
noty.location, noty.location,
escapeTag(noty.worldName), noty.worldName,
escapeTag(noty.groupName) noty.groupName
)}`; )}`;
} }
text = `<strong>${noty.displayName}</strong> has logged in${locationName}`; text = `<strong>${noty.displayName}</strong> has logged in${locationName}`;
@@ -534,16 +548,14 @@ Vue.component('marquee-text', MarqueeText);
text = `<strong>${noty.displayName}</strong> has logged out`; text = `<strong>${noty.displayName}</strong> has logged out`;
break; break;
case 'Status': case 'Status':
text = `<strong>${noty.displayName}</strong> status is now <i>${ text = `<strong>${noty.displayName}</strong> status is now <i>${noty.status}</i> ${noty.statusDescription}`;
noty.status
}</i> ${escapeTag(noty.statusDescription)}`;
break; break;
case 'invite': case 'invite':
text = `<strong>${ text = `<strong>${
noty.senderUsername noty.senderUsername
}</strong> has invited you to ${this.displayLocation( }</strong> has invited you to ${this.displayLocation(
noty.details.worldId, noty.details.worldId,
escapeTag(noty.details.worldName) noty.details.worldName
)}${message}`; )}${message}`;
break; break;
case 'requestInvite': case 'requestInvite':
@@ -571,19 +583,19 @@ Vue.component('marquee-text', MarqueeText);
text = `<strong>${noty.previousDisplayName}</strong> changed their name to ${noty.displayName}`; text = `<strong>${noty.previousDisplayName}</strong> changed their name to ${noty.displayName}`;
break; break;
case 'group.announcement': case 'group.announcement':
text = escapeTag(noty.message); text = noty.message;
break; break;
case 'group.informative': case 'group.informative':
text = escapeTag(noty.message); text = noty.message;
break; break;
case 'group.invite': case 'group.invite':
text = escapeTag(noty.message); text = noty.message;
break; break;
case 'group.joinRequest': case 'group.joinRequest':
text = escapeTag(noty.message); text = noty.message;
break; break;
case 'group.queueReady': case 'group.queueReady':
text = escapeTag(noty.message); text = noty.message;
break; break;
case 'PortalSpawn': case 'PortalSpawn':
if (noty.displayName) { if (noty.displayName) {
@@ -591,33 +603,27 @@ Vue.component('marquee-text', MarqueeText);
noty.displayName noty.displayName
}</strong> has spawned a portal to ${this.displayLocation( }</strong> has spawned a portal to ${this.displayLocation(
noty.instanceId, noty.instanceId,
escapeTag(noty.worldName), noty.worldName,
escapeTag(noty.groupName) noty.groupName
)}`; )}`;
} else { } else {
text = 'User has spawned a portal'; text = 'User has spawned a portal';
} }
break; break;
case 'AvatarChange': case 'AvatarChange':
text = `<strong>${ text = `<strong>${noty.displayName}</strong> changed into avatar ${noty.name}`;
noty.displayName
}</strong> changed into avatar ${escapeTag(noty.name)}`;
break; break;
case 'ChatBoxMessage': case 'ChatBoxMessage':
text = `<strong>${noty.displayName}</strong> said ${escapeTag( text = `<strong>${noty.displayName}</strong> said ${noty.text}`;
noty.text
)}`;
break; break;
case 'Event': case 'Event':
text = escapeTag(noty.data); text = noty.data;
break; break;
case 'External': case 'External':
text = escapeTag(noty.message); text = noty.message;
break; break;
case 'VideoPlay': case 'VideoPlay':
text = `<strong>Now playing:</strong> ${escapeTag( text = `<strong>Now playing:</strong> ${noty.notyName}`;
noty.notyName
)}`;
break; break;
case 'BlockedOnPlayerJoined': case 'BlockedOnPlayerJoined':
text = `Blocked user <strong>${noty.displayName}</strong> has joined`; text = `Blocked user <strong>${noty.displayName}</strong> has joined`;
@@ -766,10 +772,10 @@ Vue.component('marquee-text', MarqueeText);
this.hudTimeout = JSON.parse(json); this.hudTimeout = JSON.parse(json);
}; };
$app.data.currentCulture = await AppApi.CurrentCulture(); $app.data.currentCulture = await AppApiVr.CurrentCulture();
$app.methods.setDatetimeFormat = async function () { $app.methods.setDatetimeFormat = async function () {
this.currentCulture = await AppApi.CurrentCulture(); this.currentCulture = await AppApiVr.CurrentCulture();
var formatDate = function (date) { var formatDate = function (date) {
if (!date) { if (!date) {
return ''; return '';