diff --git a/Dotnet/AppApi/AppApi.cs b/Dotnet/AppApi/AppApi.cs
index 85e157a4..82dfb624 100644
--- a/Dotnet/AppApi/AppApi.cs
+++ b/Dotnet/AppApi/AppApi.cs
@@ -147,25 +147,6 @@ namespace VRCX
VRCXVR.Instance.Restart();
}
- ///
- /// Returns an array of arrays containing information about the connected VR devices.
- /// Each sub-array contains the type of device and its current state
- ///
- /// An array of arrays containing information about the connected VR devices.
- public string[][] GetVRDevices()
- {
- return VRCXVR.Instance.GetDevices();
- }
-
- ///
- /// Returns the current CPU usage as a percentage.
- ///
- /// The current CPU usage as a percentage.
- public float CpuUsage()
- {
- return CpuMonitor.Instance.CpuUsage;
- }
-
///
/// Retrieves an image from the VRChat API and caches it for future use. The function will return the cached image if it already exists.
///
@@ -352,19 +333,6 @@ namespace VRCX
WinformThemer.DoFunny();
}
- ///
- /// Returns the number of milliseconds that the system has been running.
- ///
- /// The number of milliseconds that the system has been running.
- public double GetUptime()
- {
- using (var uptime = new PerformanceCounter("System", "System Up Time"))
- {
- uptime.NextValue();
- return TimeSpan.FromSeconds(uptime.NextValue()).TotalMilliseconds;
- }
- }
-
///
/// Returns a color value derived from the given user ID.
/// This is, essentially, and is used for, random colors.
diff --git a/Dotnet/AppApi/AppApiVr.cs b/Dotnet/AppApi/AppApiVr.cs
new file mode 100644
index 00000000..82adf4c8
--- /dev/null
+++ b/Dotnet/AppApi/AppApiVr.cs
@@ -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", "");
+ }
+
+ ///
+ /// Returns the current CPU usage as a percentage.
+ ///
+ /// The current CPU usage as a percentage.
+ public float CpuUsage()
+ {
+ return CpuMonitor.Instance.CpuUsage;
+ }
+
+ ///
+ /// Returns an array of arrays containing information about the connected VR devices.
+ /// Each sub-array contains the type of device and its current state
+ ///
+ /// An array of arrays containing information about the connected VR devices.
+ public string[][] GetVRDevices()
+ {
+ return VRCXVR.Instance.GetDevices();
+ }
+
+ ///
+ /// Returns the number of milliseconds that the system has been running.
+ ///
+ /// The number of milliseconds that the system has been running.
+ public double GetUptime()
+ {
+ using var uptime = new PerformanceCounter("System", "System Up Time");
+ uptime.NextValue();
+ return TimeSpan.FromSeconds(uptime.NextValue()).TotalMilliseconds;
+ }
+
+ ///
+ /// Returns the current language of the operating system.
+ ///
+ /// The current language of the operating system.
+ public string CurrentCulture()
+ {
+ return CultureInfo.CurrentCulture.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Dotnet/AppApi/GameHandler.cs b/Dotnet/AppApi/GameHandler.cs
index 2cad61bb..75c72c3a 100644
--- a/Dotnet/AppApi/GameHandler.cs
+++ b/Dotnet/AppApi/GameHandler.cs
@@ -58,51 +58,52 @@ namespace VRCX
/// Starts the VRChat game process with the specified command-line arguments.
///
/// The command-line arguments to pass to the VRChat game.
- public void StartGame(string arguments)
+ public bool StartGame(string arguments)
{
// try stream first
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 match = Regex.Match(key.GetValue(string.Empty) as string, "^\"(.+?)\\\\steam.exe\"");
- if (match.Success)
- {
- var path = match.Groups[1].Value;
- // var _arguments = Uri.EscapeDataString(arguments);
- Process.Start(new ProcessStartInfo
+ var path = match.Groups[1].Value;
+ // var _arguments = Uri.EscapeDataString(arguments);
+ Process.Start(new ProcessStartInfo
{
WorkingDirectory = path,
FileName = $"{path}\\steam.exe",
UseShellExecute = false,
Arguments = $"-applaunch 438100 {arguments}"
- }).Close();
- return;
- }
+ })
+ ?.Close();
+ return true;
}
}
catch
{
+ logger.Warn("Failed to start VRChat from Steam");
}
// fallback
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 match = Regex.Match(key.GetValue(string.Empty) as string, "(?!\")(.+?\\\\VRChat.*)(!?\\\\launch.exe\")");
- if (match.Success)
- {
- var path = match.Groups[1].Value;
- StartGameFromPath(path, arguments);
- }
+ var path = match.Groups[1].Value;
+ return StartGameFromPath(path, arguments);
}
}
catch
{
+ logger.Warn("Failed to start VRChat from registry");
}
+
+ return false;
}
///
@@ -116,7 +117,7 @@ namespace VRCX
if (!path.EndsWith(".exe"))
path = Path.Combine(path, "launch.exe");
- if (!File.Exists(path))
+ if (!path.EndsWith("launch.exe") || !File.Exists(path))
return false;
Process.Start(new ProcessStartInfo
diff --git a/Dotnet/Util.cs b/Dotnet/JavascriptBindings.cs
similarity index 64%
rename from Dotnet/Util.cs
rename to Dotnet/JavascriptBindings.cs
index 73f1f60d..9105a654 100644
--- a/Dotnet/Util.cs
+++ b/Dotnet/JavascriptBindings.cs
@@ -1,11 +1,10 @@
-using System;
using CefSharp;
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.Register("AppApi", AppApi.Instance);
@@ -17,5 +16,11 @@ namespace VRCX
repository.Register("Discord", Discord.Instance);
repository.Register("AssetBundleCacher", AssetBundleCacher.Instance);
}
+
+ public static void ApplyVrJavascriptBindings(IJavascriptObjectRepository repository)
+ {
+ repository.NameConverter = null;
+ repository.Register("AppApiVr", AppApiVr.Instance);
+ }
}
}
diff --git a/Dotnet/MainForm.cs b/Dotnet/MainForm.cs
index 94d6dde8..bed4bb06 100644
--- a/Dotnet/MainForm.cs
+++ b/Dotnet/MainForm.cs
@@ -63,7 +63,7 @@ namespace VRCX
Browser.ShowDevTools();
};
- Util.ApplyJavascriptBindings(Browser.JavascriptObjectRepository);
+ JavascriptBindings.ApplyAppJavascriptBindings(Browser.JavascriptObjectRepository);
Browser.ConsoleMessage += (_, args) =>
{
jslogger.Debug(args.Message + " (" + args.Source + ":" + args.Line + ")");
diff --git a/Dotnet/Overlay/OffScreenBrowser.cs b/Dotnet/Overlay/OffScreenBrowser.cs
index 48c2f871..e2c2f42d 100644
--- a/Dotnet/Overlay/OffScreenBrowser.cs
+++ b/Dotnet/Overlay/OffScreenBrowser.cs
@@ -37,7 +37,7 @@ namespace VRCX
Size = new System.Drawing.Size(width, height);
RenderHandler = this;
- Util.ApplyJavascriptBindings(JavascriptObjectRepository);
+ JavascriptBindings.ApplyVrJavascriptBindings(JavascriptObjectRepository);
}
public new void Dispose()
diff --git a/Dotnet/Overlay/VRForm.cs b/Dotnet/Overlay/VRForm.cs
index 21bdcc3f..fe1f74ab 100644
--- a/Dotnet/Overlay/VRForm.cs
+++ b/Dotnet/Overlay/VRForm.cs
@@ -45,8 +45,8 @@ namespace VRCX
Dock = DockStyle.Fill
};
- Util.ApplyJavascriptBindings(_browser1.JavascriptObjectRepository);
- Util.ApplyJavascriptBindings(_browser2.JavascriptObjectRepository);
+ JavascriptBindings.ApplyVrJavascriptBindings(_browser1.JavascriptObjectRepository);
+ JavascriptBindings.ApplyVrJavascriptBindings(_browser2.JavascriptObjectRepository);
panel1.Controls.Add(_browser1);
panel2.Controls.Add(_browser2);
diff --git a/Dotnet/PWI/WorldDBManager.cs b/Dotnet/PWI/WorldDBManager.cs
index 15c2c0b5..68354428 100644
--- a/Dotnet/PWI/WorldDBManager.cs
+++ b/Dotnet/PWI/WorldDBManager.cs
@@ -13,26 +13,41 @@ namespace VRCX
{
public class WorldDBManager
{
- public static WorldDBManager Instance;
+ public static readonly WorldDBManager Instance;
private readonly HttpListener listener;
private readonly WorldDatabase worldDB;
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
+ private const string WorldDBServerUrl = "http://127.0.0.1:22500/";
private string lastError = null;
private bool debugWorld = false;
- public WorldDBManager(string url)
+ static WorldDBManager()
+ {
+ Instance = new WorldDBManager();
+ }
+
+ public WorldDBManager()
{
- Instance = this;
// http://localhost:22500
listener = new HttpListener();
- listener.Prefixes.Add(url);
+ listener.Prefixes.Add(WorldDBServerUrl);
worldDB = new WorldDatabase(Path.Combine(Program.AppDataDirectory, "VRCX-WorldData.db"));
-
}
- public async Task Start()
+ 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
try
@@ -223,9 +238,13 @@ namespace VRCX
}
var worldOverride = request.QueryString["world"];
+ if (worldOverride == "global")
+ {
+ TryInitializeWorld(worldOverride, out connectionKey);
+ }
if (worldOverride != null && worldId != worldOverride)
{
- var allowed = worldDB.GetWorldAllowExternalRead(worldOverride);
+ var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global";
if (!allowed)
{
return ConstructSuccessResponse(null, connectionKey);
@@ -262,9 +281,13 @@ namespace VRCX
}
var worldOverride = request.QueryString["world"];
+ if (worldOverride == "global")
+ {
+ TryInitializeWorld(worldOverride, out connectionKey);
+ }
if (worldOverride != null && worldId != worldOverride)
{
- var allowed = worldDB.GetWorldAllowExternalRead(worldOverride);
+ var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global";
if (!allowed)
{
return ConstructSuccessResponse(null, connectionKey);
@@ -319,9 +342,13 @@ namespace VRCX
}
var worldOverride = request.QueryString["world"];
+ if (worldOverride == "global")
+ {
+ TryInitializeWorld(worldOverride, out connectionKey);
+ }
if (worldOverride != null && worldId != worldOverride)
{
- var allowed = worldDB.GetWorldAllowExternalRead(worldOverride);
+ var allowed = worldDB.GetWorldAllowExternalRead(worldOverride) || worldOverride == "global";
if (!allowed)
{
return ConstructSuccessResponse(null, connectionKey);
@@ -526,8 +553,6 @@ namespace VRCX
return;
}
-
-
// 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 _))
{
@@ -539,6 +564,12 @@ namespace VRCX
// Get the world ID from the connection key
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).
if (worldId == null)
diff --git a/Dotnet/Program.cs b/Dotnet/Program.cs
index 755cb8d0..8c00ce3b 100644
--- a/Dotnet/Program.cs
+++ b/Dotnet/Program.cs
@@ -135,16 +135,14 @@ namespace VRCX
Application.SetCompatibleTextRenderingDefault(false);
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();
SQLiteLegacy.Instance.Init();
VRCXStorage.Load();
CpuMonitor.Instance.Init();
Discord.Instance.Init();
+ WorldDBManager.Instance.Init();
WebApi.Instance.Init();
LogWatcher.Instance.Init();
AutoAppLaunchManager.Instance.Init();
@@ -161,7 +159,7 @@ namespace VRCX
AutoAppLaunchManager.Instance.Exit();
LogWatcher.Instance.Exit();
WebApi.Instance.Exit();
- worldDBServer.Stop();
+ WorldDBManager.Instance.Stop();
Discord.Instance.Exit();
CpuMonitor.Instance.Exit();
diff --git a/VRCX.csproj b/VRCX.csproj
index df73160d..c2e9eddd 100644
--- a/VRCX.csproj
+++ b/VRCX.csproj
@@ -117,12 +117,12 @@
-
-
+
+
-
+
diff --git a/html/.eslintrc.json b/html/.eslintrc.json
index 426b210f..c8279f6a 100644
--- a/html/.eslintrc.json
+++ b/html/.eslintrc.json
@@ -29,6 +29,7 @@
"LogWatcher": "readonly",
"Discord": "readonly",
"AppApi": "readonly",
+ "AppApiVr": "readonly",
"SharedVariable": "readonly",
"WebApi": "readonly",
"AssetBundleCacher": "readonly"
diff --git a/html/src/app.js b/html/src/app.js
index b4ee7592..ecffdd3c 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -643,8 +643,8 @@ speechSynthesis.getVoices();
options.N > 0
? options.N > options.params.offset
: options.N < 0
- ? args.json.length
- : options.params.n === args.json.length)
+ ? args.json.length
+ : options.params.n === args.json.length)
) {
this.bulk(options);
} else if ('done' in options) {
@@ -4684,7 +4684,7 @@ speechSynthesis.getVoices();
}
this.errorNoty = new Noty({
type: 'error',
- text: `WebSocket Error: ${err}`
+ text: escapeTag(`WebSocket Error: ${err}`)
}).show();
return;
}
@@ -14687,14 +14687,10 @@ speechSynthesis.getVoices();
'VRCX_StartAtWindowsStartup',
false
);
- $app.data.isStartAsMinimizedState = false;
- $app.data.isCloseToTray = false;
- VRCXStorage.Get('VRCX_StartAsMinimizedState').then((result) => {
- $app.isStartAsMinimizedState = result === 'true';
- });
- VRCXStorage.Get('VRCX_CloseToTray').then((result) => {
- $app.isCloseToTray = result === 'true';
- });
+ $app.data.isStartAsMinimizedState =
+ (await VRCXStorage.Get('VRCX_StartAsMinimizedState')) === 'true';
+ $app.data.isCloseToTray =
+ (await VRCXStorage.Get('VRCX_CloseToTray')) === 'true';
if (await configRepository.getBool('VRCX_CloseToTray')) {
// move back to JSON
$app.data.isCloseToTray =
@@ -14702,6 +14698,8 @@ speechSynthesis.getVoices();
VRCXStorage.Set('VRCX_CloseToTray', $app.data.isCloseToTray.toString());
await configRepository.remove('VRCX_CloseToTray');
}
+ $app.data.disableWorldDatabase =
+ (await VRCXStorage.Get('VRCX_DisableWorldDatabase')) === 'true';
$app.methods.saveVRCXWindowOption = async function () {
await configRepository.setBool(
'VRCX_StartAtWindowsStartup',
@@ -14712,6 +14710,10 @@ speechSynthesis.getVoices();
this.isStartAsMinimizedState.toString()
);
VRCXStorage.Set('VRCX_CloseToTray', this.isCloseToTray.toString());
+ VRCXStorage.Set(
+ 'VRCX_DisableWorldDatabase',
+ this.disableWorldDatabase.toString()
+ );
AppApi.SetStartup(this.isStartAtWindowsStartup);
};
$app.data.photonEventOverlay = await configRepository.getBool(
@@ -16662,6 +16664,16 @@ speechSynthesis.getVoices();
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) => {
D.representedGroup = args1.json;
@@ -19541,14 +19553,25 @@ speechSynthesis.getVoices();
$app.launchOptionsDialog.visible = false;
});
- $app.methods.updateLaunchOptions = async function () {
+ $app.methods.updateLaunchOptions = function () {
var D = this.launchOptionsDialog;
- D.visible = false;
D.launchArguments = String(D.launchArguments)
.replace(/\s+/g, ' ')
.trim();
- await configRepository.setString('launchArguments', D.launchArguments);
- await configRepository.setString(
+ configRepository.setString('launchArguments', D.launchArguments);
+ 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',
D.vrcLaunchPathOverride
);
@@ -19556,6 +19579,7 @@ speechSynthesis.getVoices();
message: 'Updated launch options',
type: 'success'
});
+ D.visible = false;
};
$app.methods.showLaunchOptions = function () {
@@ -20101,10 +20125,19 @@ speechSynthesis.getVoices();
}
});
} else {
- AppApi.StartGame(args.join(' '));
- this.$message({
- message: 'VRChat launched',
- type: 'success'
+ AppApi.StartGame(args.join(' ')).then((result) => {
+ if (!result) {
+ this.$message({
+ 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);
diff --git a/html/src/index.pug b/html/src/index.pug
index df242651..91f9ea13 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -407,6 +407,14 @@ html
i.el-icon-warning
span.extra(v-if="userDialog.timeSpent === 0") -
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")
el-tooltip(placement="top")
template(#content)
@@ -1486,7 +1494,7 @@ html
el-button(type="primary" size="small" @click="createGroupInstance()" :disabled="!newInstanceDialog.groupId") {{ $t('dialog.new_instance.create_instance') }}
//- 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")
| {{ $t('dialog.launch_options.description') }} #[br]
| {{ $t('dialog.launch_options.example') }} #[el-tag(size="mini") --fps=144]
diff --git a/html/src/localization/en/en.json b/html/src/localization/en/en.json
index d1cf403a..cf321fd4 100644
--- a/html/src/localization/en/en.json
+++ b/html/src/localization/en/en.json
@@ -403,6 +403,10 @@
"header": "Automatically Manage Cache When Closing VRChat",
"description": "Auto delete old versions from cache"
},
+ "disable_local_world_persistence": {
+ "header": "Disable Local World Persistence",
+ "description": "Disable localhost webserver (requires restart)"
+ },
"remote_database": {
"header": "Remote Avatar Database",
"enable": "Enable",
@@ -582,6 +586,7 @@
"last_seen": "Last Seen",
"join_count": "Join Count",
"time_together": "Time Together",
+ "play_time": "Play Time",
"online_for": "Online For",
"offline_for": "Offline For",
"last_activity": "Last Activity",
@@ -592,7 +597,7 @@
"avatar_cloning": "Avatar Cloning",
"avatar_cloning_allow": "Allowed",
"avatar_cloning_deny": "Deny",
- "home_location": "Home Location",
+ "home_location": "Home World",
"id": "User ID",
"id_tooltip": "Copy to clipboard",
"copy_id": "Copy ID",
diff --git a/html/src/mixins/tabs/settings.pug b/html/src/mixins/tabs/settings.pug
index 1dee6990..8eed4827 100644
--- a/html/src/mixins/tabs/settings.pug
+++ b/html/src/mixins/tabs/settings.pug
@@ -415,6 +415,11 @@ mixin settingsTab()
div.options-container-item
span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.auto_cache_management.description') }}
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
div.options-container
span.header {{ $t('view.settings.advanced.advanced.remote_database.header') }}
diff --git a/html/src/vr.js b/html/src/vr.js
index 9885da01..7cd615e3 100644
--- a/html/src/vr.js
+++ b/html/src/vr.js
@@ -20,7 +20,7 @@ Vue.component('marquee-text', MarqueeText);
(async function () {
var $app = null;
- await CefSharp.BindObjectAsync('AppApi');
+ await CefSharp.BindObjectAsync('AppApiVr');
Noty.overrideDefaults({
animation: {
@@ -50,6 +50,18 @@ Vue.component('marquee-text', MarqueeText);
String(s).replace(/["&'<>]/gu, (c) => `${c.charCodeAt(0)};`);
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) =>
String(Number(n) || 0).replace(/(\d)(?=(\d{3})+(?!\d))/gu, '$1,');
Vue.filter('commaNumber', commaNumber);
@@ -216,10 +228,7 @@ Vue.component('marquee-text', MarqueeText);
watch: {},
el: '#x-app',
mounted() {
- workerTimers.setTimeout(
- () => AppApi.ExecuteAppFunction('vrInit', ''),
- 1000
- );
+ workerTimers.setTimeout(() => AppApiVr.VrInit(), 1000);
if (this.appType === '1') {
this.updateStatsLoop();
}
@@ -410,7 +419,7 @@ Vue.component('marquee-text', MarqueeText);
.replace(',', '');
if (!this.config.hideCpuUsageFromFeed) {
- var cpuUsage = await AppApi.CpuUsage();
+ var cpuUsage = await AppApiVr.CpuUsage();
this.cpuUsage = cpuUsage.toFixed(0);
}
if (this.lastLocation.date !== 0) {
@@ -429,7 +438,7 @@ Vue.component('marquee-text', MarqueeText);
}
if (!this.config.hideDevicesFromFeed) {
- AppApi.GetVRDevices().then((devices) => {
+ AppApiVr.GetVRDevices().then((devices) => {
var deviceList = [];
var baseStations = 0;
devices.forEach((device) => {
@@ -480,7 +489,7 @@ Vue.component('marquee-text', MarqueeText);
this.devices = [];
}
if (this.config.pcUptimeOnFeed) {
- AppApi.GetUptime().then((uptime) => {
+ AppApiVr.GetUptime().then((uptime) => {
this.pcUptime = timeToText(uptime);
});
} else {
@@ -494,7 +503,12 @@ Vue.component('marquee-text', MarqueeText);
$app.methods.playNoty = function (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 img = '';
if (image) {
@@ -515,8 +529,8 @@ Vue.component('marquee-text', MarqueeText);
noty.displayName
} is in ${this.displayLocation(
noty.location,
- escapeTag(noty.worldName),
- escapeTag(noty.groupName)
+ noty.worldName,
+ noty.groupName
)}`;
break;
case 'Online':
@@ -524,8 +538,8 @@ Vue.component('marquee-text', MarqueeText);
if (noty.worldName) {
locationName = ` to ${this.displayLocation(
noty.location,
- escapeTag(noty.worldName),
- escapeTag(noty.groupName)
+ noty.worldName,
+ noty.groupName
)}`;
}
text = `${noty.displayName} has logged in${locationName}`;
@@ -534,16 +548,14 @@ Vue.component('marquee-text', MarqueeText);
text = `${noty.displayName} has logged out`;
break;
case 'Status':
- text = `${noty.displayName} status is now ${
- noty.status
- } ${escapeTag(noty.statusDescription)}`;
+ text = `${noty.displayName} status is now ${noty.status} ${noty.statusDescription}`;
break;
case 'invite':
text = `${
noty.senderUsername
} has invited you to ${this.displayLocation(
noty.details.worldId,
- escapeTag(noty.details.worldName)
+ noty.details.worldName
)}${message}`;
break;
case 'requestInvite':
@@ -571,19 +583,19 @@ Vue.component('marquee-text', MarqueeText);
text = `${noty.previousDisplayName} changed their name to ${noty.displayName}`;
break;
case 'group.announcement':
- text = escapeTag(noty.message);
+ text = noty.message;
break;
case 'group.informative':
- text = escapeTag(noty.message);
+ text = noty.message;
break;
case 'group.invite':
- text = escapeTag(noty.message);
+ text = noty.message;
break;
case 'group.joinRequest':
- text = escapeTag(noty.message);
+ text = noty.message;
break;
case 'group.queueReady':
- text = escapeTag(noty.message);
+ text = noty.message;
break;
case 'PortalSpawn':
if (noty.displayName) {
@@ -591,33 +603,27 @@ Vue.component('marquee-text', MarqueeText);
noty.displayName
} has spawned a portal to ${this.displayLocation(
noty.instanceId,
- escapeTag(noty.worldName),
- escapeTag(noty.groupName)
+ noty.worldName,
+ noty.groupName
)}`;
} else {
text = 'User has spawned a portal';
}
break;
case 'AvatarChange':
- text = `${
- noty.displayName
- } changed into avatar ${escapeTag(noty.name)}`;
+ text = `${noty.displayName} changed into avatar ${noty.name}`;
break;
case 'ChatBoxMessage':
- text = `${noty.displayName} said ${escapeTag(
- noty.text
- )}`;
+ text = `${noty.displayName} said ${noty.text}`;
break;
case 'Event':
- text = escapeTag(noty.data);
+ text = noty.data;
break;
case 'External':
- text = escapeTag(noty.message);
+ text = noty.message;
break;
case 'VideoPlay':
- text = `Now playing: ${escapeTag(
- noty.notyName
- )}`;
+ text = `Now playing: ${noty.notyName}`;
break;
case 'BlockedOnPlayerJoined':
text = `Blocked user ${noty.displayName} has joined`;
@@ -766,10 +772,10 @@ Vue.component('marquee-text', MarqueeText);
this.hudTimeout = JSON.parse(json);
};
- $app.data.currentCulture = await AppApi.CurrentCulture();
+ $app.data.currentCulture = await AppApiVr.CurrentCulture();
$app.methods.setDatetimeFormat = async function () {
- this.currentCulture = await AppApi.CurrentCulture();
+ this.currentCulture = await AppApiVr.CurrentCulture();
var formatDate = function (date) {
if (!date) {
return '';