diff --git a/README.md b/README.md index c33cc9c..d0b4f7b 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ Merged set of MelonLoader mods for ChilloutVR. -**Table for game build 2023r172:** +**Table for game build 2023r172p1:** | Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) | |:---------:|:----------:|:--------------:| :----------------------------------------------------------------| -| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.2 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes | +| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.3 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes
:hourglass_flowing_sand: Update review | | [Desktop Head Tracking](/ml_dht/README.md)| ml_dht | - | ✔ Yes
:warning:Broken | -| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.2 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes | -| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.7 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes | +| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.3 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes
:hourglass_flowing_sand: Update review | +| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.0.8 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes
:hourglass_flowing_sand: Update review | | [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.3 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| ✔ Yes | | [Player Ragdoll Mod](/ml_prm/README.md)| ml_prm | 1.0.10 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes
:hourglass_flowing_sand: Update review | +| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| :question: Not planned yet | **Archived mods:** | Full name | Short name | Notes | diff --git a/js/ui_elements.js b/js/ui_elements.js new file mode 100644 index 0000000..104aa81 --- /dev/null +++ b/js/ui_elements.js @@ -0,0 +1,267 @@ +// Modified from original `inp` types, because I have no js knowledge to hook stuff + +if (typeof inp_toggle_mod === 'undefined') { + window.inp_toggle_mod = function (_obj, _callbackName) { + this.obj = _obj; + this.callbackName = _callbackName; + this.value = _obj.getAttribute('data-current'); + this.name = _obj.id; + this.type = _obj.getAttribute('data-type'); + + var self = this; + + this.mouseDown = function (_e) { + self.value = self.value == "True" ? "False" : "True"; + self.updateState(); + } + + this.updateState = function () { + self.obj.classList.remove("checked"); + if (self.value == "True") { + self.obj.classList.add("checked"); + } + + engine.call(self.callbackName, self.name, self.value); + } + + _obj.addEventListener('mousedown', this.mouseDown); + + this.getValue = function () { + return self.value; + } + + this.updateValue = function (value) { + self.value = value; + + self.obj.classList.remove("checked"); + if (self.value == "True") { + self.obj.classList.add("checked"); + } + } + + this.updateValue(this.value); + + return { + name: this.name, + value: this.getValue, + updateValue: this.updateValue + } + }; +} + +if (typeof inp_slider_mod === 'undefined') { + window.inp_slider_mod = function (_obj, _callbackName) { + this.obj = _obj; + this.callbackName = _callbackName; + this.minValue = parseFloat(_obj.getAttribute('data-min')); + this.maxValue = parseFloat(_obj.getAttribute('data-max')); + this.percent = 0; + this.value = parseFloat(_obj.getAttribute('data-current')); + this.dragActive = false; + this.name = _obj.id; + this.type = _obj.getAttribute('data-type'); + this.stepSize = _obj.getAttribute('data-stepSize') || 0; + this.format = _obj.getAttribute('data-format') || '{value}'; + + var self = this; + + if (this.stepSize != 0) + this.value = Math.round(this.value / this.stepSize) * this.stepSize; + else + this.value = Math.round(this.value); + + this.valueLabelBackground = document.createElement('div'); + this.valueLabelBackground.className = 'valueLabel background'; + this.valueLabelBackground.innerHTML = this.format.replace('{value}', this.value); + this.obj.appendChild(this.valueLabelBackground); + + this.valueBar = document.createElement('div'); + this.valueBar.className = 'valueBar'; + this.valueBar.setAttribute('style', 'width: ' + (((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); + this.obj.appendChild(this.valueBar); + + this.valueLabelForeground = document.createElement('div'); + this.valueLabelForeground.className = 'valueLabel foreground'; + this.valueLabelForeground.innerHTML = this.format.replace('{value}', this.value); + this.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / ((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); + this.valueBar.appendChild(this.valueLabelForeground); + + this.mouseDown = function (_e) { + self.dragActive = true; + self.mouseMove(_e, false); + } + + this.mouseMove = function (_e, _write) { + if (self.dragActive) { + var rect = _obj.getBoundingClientRect(); + var start = rect.left; + var end = rect.right; + self.percent = Math.min(Math.max((_e.clientX - start) / rect.width, 0), 1); + var value = self.percent; + value *= (self.maxValue - self.minValue); + value += self.minValue; + if (self.stepSize != 0) { + value = Math.round(value / self.stepSize); + self.value = value * self.stepSize; + self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); + } + else + self.value = Math.round(value); + + self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); + self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); + self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); + + engine.call(self.callbackName, self.name, "" + self.value); + self.displayImperial(); + } + } + + this.mouseUp = function (_e) { + self.mouseMove(_e, true); + self.dragActive = false; + } + + _obj.addEventListener('mousedown', this.mouseDown); + document.addEventListener('mousemove', this.mouseMove); + document.addEventListener('mouseup', this.mouseUp); + + this.getValue = function () { + return self.value; + } + + this.updateValue = function (value) { + if (self.stepSize != 0) + self.value = Math.round(value * self.stepSize) / self.stepSize; + else + self.value = Math.round(value); + self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); + self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); + self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); + self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); + self.displayImperial(); + } + + this.displayImperial = function () { + var displays = document.querySelectorAll('.imperialDisplay'); + for (var i = 0; i < displays.length; i++) { + var binding = displays[i].getAttribute('data-binding'); + if (binding == self.name) { + var realFeet = ((self.value * 0.393700) / 12); + var feet = Math.floor(realFeet); + var inches = Math.floor((realFeet - feet) * 12); + displays[i].innerHTML = feet + "'" + inches + ''''; + } + } + } + + return { + name: this.name, + value: this.getValue, + updateValue: this.updateValue + } + }; +} + +if (typeof inp_dropdown_mod === 'undefined') { + window.inp_dropdown_mod = function (_obj, _callbackName) { + this.obj = _obj; + this.callbackName = _callbackName; + this.value = _obj.getAttribute('data-current'); + this.options = _obj.getAttribute('data-options').split(','); + this.name = _obj.id; + this.opened = false; + this.keyValue = []; + this.type = _obj.getAttribute('data-type'); + + this.optionElements = []; + + var self = this; + + this.SelectValue = function (_e) { + self.value = _e.target.getAttribute('data-key'); + self.valueElement.innerHTML = _e.target.getAttribute('data-value'); + self.globalClose(); + + engine.call(self.callbackName, self.name, self.value); + } + + this.openClick = function (_e) { + if (self.obj.classList.contains('open')) { + self.obj.classList.remove('open'); + self.list.setAttribute('style', 'display: none;'); + } else { + self.obj.classList.add('open'); + self.list.setAttribute('style', 'display: block;'); + self.opened = true; + window.setTimeout(function () { self.opened = false; }, 10); + } + } + + this.globalClose = function (_e) { + if (self.opened) return; + self.obj.classList.remove('open'); + self.list.setAttribute('style', 'display: none;'); + } + + this.list = document.createElement('div'); + this.list.className = 'valueList'; + + this.updateOptions = function () { + self.list.innerHTML = ""; + for (var i = 0; i < self.options.length; i++) { + self.optionElements[i] = document.createElement('div'); + self.optionElements[i].className = 'listValue'; + var valuePair = Array.isArray(self.options[i]) ? self.options[i] : self.options[i].split(':'); + var key = ""; + var value = ""; + if (valuePair.length == 1) { + key = valuePair[0]; + value = valuePair[0]; + } else { + key = valuePair[0]; + value = valuePair[1]; + } + self.keyValue[key] = value; + self.optionElements[i].innerHTML = value; + self.optionElements[i].setAttribute('data-value', value); + self.optionElements[i].setAttribute('data-key', key); + self.list.appendChild(self.optionElements[i]); + self.optionElements[i].addEventListener('mousedown', self.SelectValue); + } + + self.valueElement.innerHTML = self.keyValue[self.value]; + } + + this.valueElement = document.createElement('div'); + this.valueElement.className = 'dropdown-value'; + + this.updateOptions(); + + this.obj.appendChild(this.valueElement); + this.obj.appendChild(this.list); + this.valueElement.addEventListener('mousedown', this.openClick); + document.addEventListener('mousedown', this.globalClose); + + this.getValue = function () { + return self.value; + } + + this.updateValue = function (value) { + self.value = value; + self.valueElement.innerHTML = self.keyValue[value]; + } + + this.setOptions = function (options) { + self.options = options; + } + + return { + name: this.name, + value: this.getValue, + updateValue: this.updateValue, + updateOptions: this.updateOptions, + setOptions: this.setOptions + } + }; +} diff --git a/ml_amt/Properties/AssemblyInfo.cs b/ml_amt/Properties/AssemblyInfo.cs index 38903a2..f4eb9c9 100644 --- a/ml_amt/Properties/AssemblyInfo.cs +++ b/ml_amt/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_amt.AvatarMotionTweaker), "AvatarMotionTweaker", "1.3.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonOptionalDependencies("ml_prm", "ml_pmc")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] diff --git a/ml_amt/Settings.cs b/ml_amt/Settings.cs index 25ab756..ecd8b2d 100644 --- a/ml_amt/Settings.cs +++ b/ml_amt/Settings.cs @@ -78,7 +78,8 @@ static System.Collections.IEnumerator WaitMainMenuUi() }; ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => { - ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("menu.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_elements.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_menu.js")); foreach(var l_entry in ms_entries) ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingAMT", l_entry.DisplayName, l_entry.GetValueAsString()); }; diff --git a/ml_amt/ml_amt.csproj b/ml_amt/ml_amt.csproj index 3917f0a..e1e1c85 100644 --- a/ml_amt/ml_amt.csproj +++ b/ml_amt/ml_amt.csproj @@ -1,4 +1,4 @@ - + netstandard2.1 @@ -6,7 +6,7 @@ None AvatarMotionTweaker AvatarMotionTweaker - 1.3.2 + 1.3.3 x64 ml_amt @@ -26,11 +26,15 @@ - + - + + + + + diff --git a/ml_amt/resources/menu.js b/ml_amt/resources/menu.js deleted file mode 100644 index 6df4b72..0000000 --- a/ml_amt/resources/menu.js +++ /dev/null @@ -1,245 +0,0 @@ -// Add settings -var g_modSettingsAMT = []; - -engine.on('updateModSettingAMT', function (_name, _value) { - for (var i = 0; i < g_modSettingsAMT.length; i++) { - if (g_modSettingsAMT[i].name == _name) { - g_modSettingsAMT[i].updateValue(_value); - break; - } - } -}); - -// Modified from original `inp` types, because I have no js knowledge to hook stuff -function inp_slider_mod_amt(_obj, _callbackName) { - this.obj = _obj; - this.callbackName = _callbackName; - this.minValue = parseFloat(_obj.getAttribute('data-min')); - this.maxValue = parseFloat(_obj.getAttribute('data-max')); - this.percent = 0; - this.value = parseFloat(_obj.getAttribute('data-current')); - this.dragActive = false; - this.name = _obj.id; - this.type = _obj.getAttribute('data-type'); - this.stepSize = _obj.getAttribute('data-stepSize') || 0; - this.format = _obj.getAttribute('data-format') || '{value}'; - - var self = this; - - if (this.stepSize != 0) - this.value = Math.round(this.value / this.stepSize) * this.stepSize; - else - this.value = Math.round(this.value); - - this.valueLabelBackground = document.createElement('div'); - this.valueLabelBackground.className = 'valueLabel background'; - this.valueLabelBackground.innerHTML = this.format.replace('{value}', this.value); - this.obj.appendChild(this.valueLabelBackground); - - this.valueBar = document.createElement('div'); - this.valueBar.className = 'valueBar'; - this.valueBar.setAttribute('style', 'width: ' + (((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); - this.obj.appendChild(this.valueBar); - - this.valueLabelForeground = document.createElement('div'); - this.valueLabelForeground.className = 'valueLabel foreground'; - this.valueLabelForeground.innerHTML = this.format.replace('{value}', this.value); - this.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / ((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); - this.valueBar.appendChild(this.valueLabelForeground); - - this.mouseDown = function (_e) { - self.dragActive = true; - self.mouseMove(_e, false); - } - - this.mouseMove = function (_e, _write) { - if (self.dragActive) { - var rect = _obj.getBoundingClientRect(); - var start = rect.left; - var end = rect.right; - self.percent = Math.min(Math.max((_e.clientX - start) / rect.width, 0), 1); - var value = self.percent; - value *= (self.maxValue - self.minValue); - value += self.minValue; - if (self.stepSize != 0) { - value = Math.round(value / self.stepSize); - self.value = value * self.stepSize; - self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); - } - else - self.value = Math.round(value); - - self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); - self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); - self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); - - engine.call(self.callbackName, self.name, "" + self.value); - self.displayImperial(); - } - } - - this.mouseUp = function (_e) { - self.mouseMove(_e, true); - self.dragActive = false; - } - - _obj.addEventListener('mousedown', this.mouseDown); - document.addEventListener('mousemove', this.mouseMove); - document.addEventListener('mouseup', this.mouseUp); - - this.getValue = function () { - return self.value; - } - - this.updateValue = function (value) { - if (self.stepSize != 0) - self.value = Math.round(value * self.stepSize) / self.stepSize; - else - self.value = Math.round(value); - self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); - self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); - self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); - self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); - self.displayImperial(); - } - - this.displayImperial = function () { - var displays = document.querySelectorAll('.imperialDisplay'); - for (var i = 0; i < displays.length; i++) { - var binding = displays[i].getAttribute('data-binding'); - if (binding == self.name) { - var realFeet = ((self.value * 0.393700) / 12); - var feet = Math.floor(realFeet); - var inches = Math.floor((realFeet - feet) * 12); - displays[i].innerHTML = feet + "'" + inches + ''''; - } - } - } - - return { - name: this.name, - value: this.getValue, - updateValue: this.updateValue - } -} - -// Modified from original `inp` types, because I have no js knowledge to hook stuff -function inp_toggle_mod_amt(_obj, _callbackName) { - this.obj = _obj; - this.callbackName = _callbackName; - this.value = _obj.getAttribute('data-current'); - this.name = _obj.id; - this.type = _obj.getAttribute('data-type'); - - var self = this; - - this.mouseDown = function (_e) { - self.value = self.value == "True" ? "False" : "True"; - self.updateState(); - } - - this.updateState = function () { - self.obj.classList.remove("checked"); - if (self.value == "True") { - self.obj.classList.add("checked"); - } - - engine.call(self.callbackName, self.name, self.value); - } - - _obj.addEventListener('mousedown', this.mouseDown); - - this.getValue = function () { - return self.value; - } - - this.updateValue = function (value) { - self.value = value; - - self.obj.classList.remove("checked"); - if (self.value == "True") { - self.obj.classList.add("checked"); - } - } - - this.updateValue(this.value); - - return { - name: this.name, - value: this.getValue, - updateValue: this.updateValue - } -} - -// Add own menu -{ - let l_block = document.createElement('div'); - l_block.innerHTML = ` -
-
Avatar Motion Tweaker
-
-
- -
-
Crouch limit:
-
-
-
-
- -
-
Prone limit:
-
-
-
-
- -
-
IK override while flying:
-
-
-
-
- -
-
IK override while jumping:
-
-
-
-
- -
-
Follow hips on IK override:
-
-
-
-
- -
-
Detect animations emote tag:
-
-
-
-
- -
-
Adjusted locomotion mass center:
-
-
-
-
- `; - document.getElementById('settings-ik').appendChild(l_block); - - // Update sliders in new menu block - let l_sliders = l_block.querySelectorAll('.inp_slider'); - for (var i = 0; i < l_sliders.length; i++) { - g_modSettingsAMT[g_modSettingsAMT.length] = new inp_slider_mod_amt(l_sliders[i], 'MelonMod_AMT_Call_InpSlider'); - } - - // Update toggles in new menu block - let l_toggles = l_block.querySelectorAll('.inp_toggle'); - for (var i = 0; i < l_toggles.length; i++) { - g_modSettingsAMT[g_modSettingsAMT.length] = new inp_toggle_mod_amt(l_toggles[i], 'MelonMod_AMT_Call_InpToggle'); - } -} diff --git a/ml_amt/resources/ui_menu.js b/ml_amt/resources/ui_menu.js new file mode 100644 index 0000000..c31bac4 --- /dev/null +++ b/ml_amt/resources/ui_menu.js @@ -0,0 +1,84 @@ +// Add settings +var g_modSettingsAMT = []; + +engine.on('updateModSettingAMT', function (_name, _value) { + for (var i = 0; i < g_modSettingsAMT.length; i++) { + if (g_modSettingsAMT[i].name == _name) { + g_modSettingsAMT[i].updateValue(_value); + break; + } + } +}); + +// Add own menu +{ + let l_block = document.createElement('div'); + l_block.innerHTML = ` +
+
Avatar Motion Tweaker
+
+
+ +
+
Crouch limit:
+
+
+
+
+ +
+
Prone limit:
+
+
+
+
+ +
+
IK override while flying:
+
+
+
+
+ +
+
IK override while jumping:
+
+
+
+
+ +
+
Follow hips on IK override:
+
+
+
+
+ +
+
Detect animations emote tag:
+
+
+
+
+ +
+
Adjusted locomotion mass center:
+
+
+
+
+ `; + document.getElementById('settings-ik').appendChild(l_block); + + // Update sliders in new menu block + let l_sliders = l_block.querySelectorAll('.inp_slider'); + for (var i = 0; i < l_sliders.length; i++) { + g_modSettingsAMT[g_modSettingsAMT.length] = new inp_slider_mod(l_sliders[i], 'MelonMod_AMT_Call_InpSlider'); + } + + // Update toggles in new menu block + let l_toggles = l_block.querySelectorAll('.inp_toggle'); + for (var i = 0; i < l_toggles.length; i++) { + g_modSettingsAMT[g_modSettingsAMT.length] = new inp_toggle_mod(l_toggles[i], 'MelonMod_AMT_Call_InpToggle'); + } +} diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index 06beec0..b7c503d 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] diff --git a/ml_lme/Settings.cs b/ml_lme/Settings.cs index a37e087..facb477 100644 --- a/ml_lme/Settings.cs +++ b/ml_lme/Settings.cs @@ -1,5 +1,4 @@ using ABI_RC.Core.InteractionSystem; -using cohtml; using System; using System.Collections.Generic; using UnityEngine; @@ -122,7 +121,8 @@ static System.Collections.IEnumerator WaitMainMenuUi() }; ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => { - ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("menu.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_elements.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_menu.js")); foreach(var l_entry in ms_entries) ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingLME", l_entry.DisplayName, l_entry.GetValueAsString()); }; diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index 5f94567..d7e99a8 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 LeapMotionExtension - 1.4.2 + 1.4.3 SDraw None LeapMotionExtension @@ -25,13 +25,13 @@ - +
- + resources/LeapC.dll @@ -91,6 +91,10 @@ + + + + diff --git a/ml_lme/resources/menu.js b/ml_lme/resources/menu.js deleted file mode 100644 index 417a929..0000000 --- a/ml_lme/resources/menu.js +++ /dev/null @@ -1,442 +0,0 @@ -// Add settings -var g_modSettingsLME = []; - -engine.on('updateModSettingLME', function (_name, _value) { - for (var i = 0; i < g_modSettingsLME.length; i++) { - if (g_modSettingsLME[i].name == _name) { - g_modSettingsLME[i].updateValue(_value); - break; - } - } -}); - -// Modified from original `inp` types, because I have no js knowledge to hook stuff -function inp_toggle_mod_lme(_obj, _callbackName) { - this.obj = _obj; - this.callbackName = _callbackName; - this.value = _obj.getAttribute('data-current'); - this.name = _obj.id; - this.type = _obj.getAttribute('data-type'); - - var self = this; - - this.mouseDown = function (_e) { - self.value = self.value == "True" ? "False" : "True"; - self.updateState(); - } - - this.updateState = function () { - self.obj.classList.remove("checked"); - if (self.value == "True") { - self.obj.classList.add("checked"); - } - - engine.call(self.callbackName, self.name, self.value); - } - - _obj.addEventListener('mousedown', this.mouseDown); - - this.getValue = function () { - return self.value; - } - - this.updateValue = function (value) { - self.value = value; - - self.obj.classList.remove("checked"); - if (self.value == "True") { - self.obj.classList.add("checked"); - } - } - - this.updateValue(this.value); - - return { - name: this.name, - value: this.getValue, - updateValue: this.updateValue - } -} - -function inp_slider_mod_lme(_obj, _callbackName) { - this.obj = _obj; - this.callbackName = _callbackName; - this.minValue = parseFloat(_obj.getAttribute('data-min')); - this.maxValue = parseFloat(_obj.getAttribute('data-max')); - this.percent = 0; - this.value = parseFloat(_obj.getAttribute('data-current')); - this.dragActive = false; - this.name = _obj.id; - this.type = _obj.getAttribute('data-type'); - this.stepSize = _obj.getAttribute('data-stepSize') || 0; - this.format = _obj.getAttribute('data-format') || '{value}'; - - var self = this; - - if (this.stepSize != 0) - this.value = Math.round(this.value / this.stepSize) * this.stepSize; - else - this.value = Math.round(this.value); - - this.valueLabelBackground = document.createElement('div'); - this.valueLabelBackground.className = 'valueLabel background'; - this.valueLabelBackground.innerHTML = this.format.replace('{value}', this.value); - this.obj.appendChild(this.valueLabelBackground); - - this.valueBar = document.createElement('div'); - this.valueBar.className = 'valueBar'; - this.valueBar.setAttribute('style', 'width: ' + (((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); - this.obj.appendChild(this.valueBar); - - this.valueLabelForeground = document.createElement('div'); - this.valueLabelForeground.className = 'valueLabel foreground'; - this.valueLabelForeground.innerHTML = this.format.replace('{value}', this.value); - this.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / ((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); - this.valueBar.appendChild(this.valueLabelForeground); - - this.mouseDown = function (_e) { - self.dragActive = true; - self.mouseMove(_e, false); - } - - this.mouseMove = function (_e, _write) { - if (self.dragActive) { - var rect = _obj.getBoundingClientRect(); - var start = rect.left; - var end = rect.right; - self.percent = Math.min(Math.max((_e.clientX - start) / rect.width, 0), 1); - var value = self.percent; - value *= (self.maxValue - self.minValue); - value += self.minValue; - if (self.stepSize != 0) { - value = Math.round(value / self.stepSize); - self.value = value * self.stepSize; - self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); - } - else - self.value = Math.round(value); - - self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); - self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); - self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); - - engine.call(self.callbackName, self.name, "" + self.value); - self.displayImperial(); - } - } - - this.mouseUp = function (_e) { - self.mouseMove(_e, true); - self.dragActive = false; - } - - _obj.addEventListener('mousedown', this.mouseDown); - document.addEventListener('mousemove', this.mouseMove); - document.addEventListener('mouseup', this.mouseUp); - - this.getValue = function () { - return self.value; - } - - this.updateValue = function (value) { - if (self.stepSize != 0) - self.value = Math.round(value * self.stepSize) / self.stepSize; - else - self.value = Math.round(value); - self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); - self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); - self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); - self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); - self.displayImperial(); - } - - this.displayImperial = function () { - var displays = document.querySelectorAll('.imperialDisplay'); - for (var i = 0; i < displays.length; i++) { - var binding = displays[i].getAttribute('data-binding'); - if (binding == self.name) { - var realFeet = ((self.value * 0.393700) / 12); - var feet = Math.floor(realFeet); - var inches = Math.floor((realFeet - feet) * 12); - displays[i].innerHTML = feet + "'" + inches + ''''; - } - } - } - - return { - name: this.name, - value: this.getValue, - updateValue: this.updateValue - } -} - -function inp_dropdown_mod_lme(_obj, _callbackName) { - this.obj = _obj; - this.callbackName = _callbackName; - this.value = _obj.getAttribute('data-current'); - this.options = _obj.getAttribute('data-options').split(','); - this.name = _obj.id; - this.opened = false; - this.keyValue = []; - this.type = _obj.getAttribute('data-type'); - - this.optionElements = []; - - var self = this; - - this.SelectValue = function (_e) { - self.value = _e.target.getAttribute('data-key'); - self.valueElement.innerHTML = _e.target.getAttribute('data-value'); - self.globalClose(); - - engine.call(self.callbackName, self.name, self.value); - } - - this.openClick = function (_e) { - if (self.obj.classList.contains('open')) { - self.obj.classList.remove('open'); - self.list.setAttribute('style', 'display: none;'); - } else { - self.obj.classList.add('open'); - self.list.setAttribute('style', 'display: block;'); - self.opened = true; - window.setTimeout(function () { self.opened = false; }, 10); - } - } - - this.globalClose = function (_e) { - if (self.opened) return; - self.obj.classList.remove('open'); - self.list.setAttribute('style', 'display: none;'); - } - - this.list = document.createElement('div'); - this.list.className = 'valueList'; - - this.updateOptions = function () { - self.list.innerHTML = ""; - for (var i = 0; i < self.options.length; i++) { - self.optionElements[i] = document.createElement('div'); - self.optionElements[i].className = 'listValue'; - var valuePair = Array.isArray(self.options[i]) ? self.options[i] : self.options[i].split(':'); - var key = ""; - var value = ""; - if (valuePair.length == 1) { - key = valuePair[0]; - value = valuePair[0]; - } else { - key = valuePair[0]; - value = valuePair[1]; - } - self.keyValue[key] = value; - self.optionElements[i].innerHTML = value; - self.optionElements[i].setAttribute('data-value', value); - self.optionElements[i].setAttribute('data-key', key); - self.list.appendChild(self.optionElements[i]); - self.optionElements[i].addEventListener('mousedown', self.SelectValue); - } - - self.valueElement.innerHTML = self.keyValue[self.value]; - } - - this.valueElement = document.createElement('div'); - this.valueElement.className = 'dropdown-value'; - - this.updateOptions(); - - this.obj.appendChild(this.valueElement); - this.obj.appendChild(this.list); - this.valueElement.addEventListener('mousedown', this.openClick); - document.addEventListener('mousedown', this.globalClose); - - this.getValue = function () { - return self.value; - } - - this.updateValue = function (value) { - self.value = value; - self.valueElement.innerHTML = self.keyValue[value]; - } - - this.setOptions = function (options) { - self.options = options; - } - - return { - name: this.name, - value: this.getValue, - updateValue: this.updateValue, - updateOptions: this.updateOptions, - setOptions: this.setOptions - } -} - -// Add own menu -{ - let l_block = document.createElement('div'); - l_block.innerHTML = ` -
-
Leap Motion tracking
-
-
- -
-
Enable tracking:
-
-
-
-
- -
-
Tracking mode:
-
-
-
-
- -
-
Desktop offset X:
-
-
-
-
- -
-
Desktop offset Y:
-
-
-
-
- -
-
Desktop offset Z:
-
-
-
-
- -
-
Attach to head:
-
- -
-
- -
-
Head offset X:
-
-
-
-
- -
-
Head offset Y:
-
-
-
-
- -
-
Head offset Z:
-
-
-
-
- -
-
Offset angle X:
-
-
-
-
- -
-
Offset angle Y:
-
-
-
-
- -
-
Offset angle Z:
-
-
-
-
- -
-
Track elbows:
-
-
-
-
- -
-
Fingers tracking only:
-
-
-
-
- -
-
Model visibility:
-
-
-
-
- -
-
Visualize hands:
-
-
-
-
- -
-
Interaction input:
-
-
-
-
- -
-
Recognize gestures:
-
-
-
-
- -
-
Interact gesture threadhold:
-
-
-
-
- -
-
Grip gesture threadhold:
-
-
-
-
- `; - document.getElementById('settings-implementation').appendChild(l_block); - - // Update toggles in new menu block - let l_toggles = l_block.querySelectorAll('.inp_toggle'); - for (var i = 0; i < l_toggles.length; i++) { - g_modSettingsLME[g_modSettingsLME.length] = new inp_toggle_mod_lme(l_toggles[i], 'MelonMod_LME_Call_InpToggle'); - } - - // Update sliders in new menu block - let l_sliders = l_block.querySelectorAll('.inp_slider'); - for (var i = 0; i < l_sliders.length; i++) { - g_modSettingsLME[g_modSettingsLME.length] = new inp_slider_mod_lme(l_sliders[i], 'MelonMod_LME_Call_InpSlider'); - } - - //Update dropdowns in new menu block - let l_dropdowns = l_block.querySelectorAll('.inp_dropdown'); - for (var i = 0; i < l_dropdowns.length; i++) { - g_modSettingsLME[g_modSettingsLME.length] = new inp_dropdown_mod_lme(l_dropdowns[i], 'MelonMod_LME_Call_InpDropdown'); - } -} diff --git a/ml_lme/resources/ui_menu.js b/ml_lme/resources/ui_menu.js new file mode 100644 index 0000000..0f0f193 --- /dev/null +++ b/ml_lme/resources/ui_menu.js @@ -0,0 +1,181 @@ +// Add settings +var g_modSettingsLME = []; + +engine.on('updateModSettingLME', function (_name, _value) { + for (var i = 0; i < g_modSettingsLME.length; i++) { + if (g_modSettingsLME[i].name == _name) { + g_modSettingsLME[i].updateValue(_value); + break; + } + } +}); + +// Add own menu +{ + let l_block = document.createElement('div'); + l_block.innerHTML = ` +
+
Leap Motion tracking
+
+
+ +
+
Enable tracking:
+
+
+
+
+ +
+
Tracking mode:
+
+
+
+
+ +
+
Desktop offset X:
+
+
+
+
+ +
+
Desktop offset Y:
+
+
+
+
+ +
+
Desktop offset Z:
+
+
+
+
+ +
+
Attach to head:
+
+ +
+
+ +
+
Head offset X:
+
+
+
+
+ +
+
Head offset Y:
+
+
+
+
+ +
+
Head offset Z:
+
+
+
+
+ +
+
Offset angle X:
+
+
+
+
+ +
+
Offset angle Y:
+
+
+
+
+ +
+
Offset angle Z:
+
+
+
+
+ +
+
Track elbows:
+
+
+
+
+ +
+
Fingers tracking only:
+
+
+
+
+ +
+
Model visibility:
+
+
+
+
+ +
+
Visualize hands:
+
+
+
+
+ +
+
Interaction input:
+
+
+
+
+ +
+
Recognize gestures:
+
+
+
+
+ +
+
Interact gesture threadhold:
+
+
+
+
+ +
+
Grip gesture threadhold:
+
+
+
+
+ `; + document.getElementById('settings-implementation').appendChild(l_block); + + // Update toggles in new menu block + let l_toggles = l_block.querySelectorAll('.inp_toggle'); + for (var i = 0; i < l_toggles.length; i++) { + g_modSettingsLME[g_modSettingsLME.length] = new inp_toggle_mod(l_toggles[i], 'MelonMod_LME_Call_InpToggle'); + } + + // Update sliders in new menu block + let l_sliders = l_block.querySelectorAll('.inp_slider'); + for (var i = 0; i < l_sliders.length; i++) { + g_modSettingsLME[g_modSettingsLME.length] = new inp_slider_mod(l_sliders[i], 'MelonMod_LME_Call_InpSlider'); + } + + //Update dropdowns in new menu block + let l_dropdowns = l_block.querySelectorAll('.inp_dropdown'); + for (var i = 0; i < l_dropdowns.length; i++) { + g_modSettingsLME[g_modSettingsLME.length] = new inp_dropdown_mod(l_dropdowns[i], 'MelonMod_LME_Call_InpDropdown'); + } +} diff --git a/ml_pam/Properties/AssemblyInfo.cs b/ml_pam/Properties/AssemblyInfo.cs index d79a0db..ca105d1 100644 --- a/ml_pam/Properties/AssemblyInfo.cs +++ b/ml_pam/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_pam.PickupArmMovement), "PickupArmMovement", "1.0.8", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPriority(1)] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] diff --git a/ml_pam/README.md b/ml_pam/README.md index e2fe1c9..358f5d3 100644 --- a/ml_pam/README.md +++ b/ml_pam/README.md @@ -7,6 +7,6 @@ This mod adds arm tracking upon holding pickup in desktop mode. * Put `ml_pam.dll` in `Mods` folder of game # Usage -Available mod's settings in `Settings - Interactions`: +Available mod's settings in `Settings - Interactions - Pickup Arm Movement`: * **Enable hand movement:** enables/disables arm tracking; default value - `true`. * **Grab offset:** offset from pickup grab point; defalut value - `25`. diff --git a/ml_pam/Settings.cs b/ml_pam/Settings.cs index 433cdab..fd2e8d2 100644 --- a/ml_pam/Settings.cs +++ b/ml_pam/Settings.cs @@ -1,5 +1,4 @@ using ABI_RC.Core.InteractionSystem; -using cohtml; using System; using System.Collections.Generic; @@ -53,7 +52,8 @@ static System.Collections.IEnumerator WaitMainMenuUi() }; ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => { - ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("menu.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_elements.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_menu.js")); foreach(var l_entry in ms_entries) ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingPAM", l_entry.DisplayName, l_entry.GetValueAsString()); }; diff --git a/ml_pam/ml_pam.csproj b/ml_pam/ml_pam.csproj index 68e8a2c..22497fb 100644 --- a/ml_pam/ml_pam.csproj +++ b/ml_pam/ml_pam.csproj @@ -4,7 +4,7 @@ netstandard2.1 x64 PickupArmMovement - 1.0.7 + 1.0.8 SDraw None PickupArmMovement @@ -17,11 +17,15 @@ - + - + + + + + diff --git a/ml_pam/resources/menu.js b/ml_pam/resources/menu.js deleted file mode 100644 index c4b41b2..0000000 --- a/ml_pam/resources/menu.js +++ /dev/null @@ -1,209 +0,0 @@ -// Add settings -var g_modSettingsPAM = []; - -engine.on('updateModSettingPAM', function (_name, _value) { - for (var i = 0; i < g_modSettingsPAM.length; i++) { - if (g_modSettingsPAM[i].name == _name) { - g_modSettingsPAM[i].updateValue(_value); - break; - } - } -}); - -// Modified from original `inp` types, because I have no js knowledge to hook stuff -function inp_toggle_mod_pam(_obj, _callbackName) { - this.obj = _obj; - this.callbackName = _callbackName; - this.value = _obj.getAttribute('data-current'); - this.name = _obj.id; - this.type = _obj.getAttribute('data-type'); - - var self = this; - - this.mouseDown = function (_e) { - self.value = self.value == "True" ? "False" : "True"; - self.updateState(); - } - - this.updateState = function () { - self.obj.classList.remove("checked"); - if (self.value == "True") { - self.obj.classList.add("checked"); - } - - engine.call(self.callbackName, self.name, self.value); - } - - _obj.addEventListener('mousedown', this.mouseDown); - - this.getValue = function () { - return self.value; - } - - this.updateValue = function (value) { - self.value = value; - - self.obj.classList.remove("checked"); - if (self.value == "True") { - self.obj.classList.add("checked"); - } - } - - this.updateValue(this.value); - - return { - name: this.name, - value: this.getValue, - updateValue: this.updateValue - } -} - -function inp_slider_mod_pam(_obj, _callbackName) { - this.obj = _obj; - this.callbackName = _callbackName; - this.minValue = parseFloat(_obj.getAttribute('data-min')); - this.maxValue = parseFloat(_obj.getAttribute('data-max')); - this.percent = 0; - this.value = parseFloat(_obj.getAttribute('data-current')); - this.dragActive = false; - this.name = _obj.id; - this.type = _obj.getAttribute('data-type'); - this.stepSize = _obj.getAttribute('data-stepSize') || 0; - this.format = _obj.getAttribute('data-format') || '{value}'; - - var self = this; - - if (this.stepSize != 0) - this.value = Math.round(this.value / this.stepSize) * this.stepSize; - else - this.value = Math.round(this.value); - - this.valueLabelBackground = document.createElement('div'); - this.valueLabelBackground.className = 'valueLabel background'; - this.valueLabelBackground.innerHTML = this.format.replace('{value}', this.value); - this.obj.appendChild(this.valueLabelBackground); - - this.valueBar = document.createElement('div'); - this.valueBar.className = 'valueBar'; - this.valueBar.setAttribute('style', 'width: ' + (((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); - this.obj.appendChild(this.valueBar); - - this.valueLabelForeground = document.createElement('div'); - this.valueLabelForeground.className = 'valueLabel foreground'; - this.valueLabelForeground.innerHTML = this.format.replace('{value}', this.value); - this.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / ((this.value - this.minValue) / (this.maxValue - this.minValue)) * 100) + '%;'); - this.valueBar.appendChild(this.valueLabelForeground); - - this.mouseDown = function (_e) { - self.dragActive = true; - self.mouseMove(_e, false); - } - - this.mouseMove = function (_e, _write) { - if (self.dragActive) { - var rect = _obj.getBoundingClientRect(); - var start = rect.left; - var end = rect.right; - self.percent = Math.min(Math.max((_e.clientX - start) / rect.width, 0), 1); - var value = self.percent; - value *= (self.maxValue - self.minValue); - value += self.minValue; - if (self.stepSize != 0) { - value = Math.round(value / self.stepSize); - self.value = value * self.stepSize; - self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); - } - else - self.value = Math.round(value); - - self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); - self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); - self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); - - engine.call(self.callbackName, self.name, "" + self.value); - self.displayImperial(); - } - } - - this.mouseUp = function (_e) { - self.mouseMove(_e, true); - self.dragActive = false; - } - - _obj.addEventListener('mousedown', this.mouseDown); - document.addEventListener('mousemove', this.mouseMove); - document.addEventListener('mouseup', this.mouseUp); - - this.getValue = function () { - return self.value; - } - - this.updateValue = function (value) { - if (self.stepSize != 0) - self.value = Math.round(value * self.stepSize) / self.stepSize; - else - self.value = Math.round(value); - self.percent = (self.value - self.minValue) / (self.maxValue - self.minValue); - self.valueBar.setAttribute('style', 'width: ' + (self.percent * 100) + '%;'); - self.valueLabelForeground.setAttribute('style', 'width: ' + (1.0 / self.percent * 100) + '%;'); - self.valueLabelBackground.innerHTML = self.valueLabelForeground.innerHTML = self.format.replace('{value}', self.value); - self.displayImperial(); - } - - this.displayImperial = function () { - var displays = document.querySelectorAll('.imperialDisplay'); - for (var i = 0; i < displays.length; i++) { - var binding = displays[i].getAttribute('data-binding'); - if (binding == self.name) { - var realFeet = ((self.value * 0.393700) / 12); - var feet = Math.floor(realFeet); - var inches = Math.floor((realFeet - feet) * 12); - displays[i].innerHTML = feet + "'" + inches + ''''; - } - } - } - - return { - name: this.name, - value: this.getValue, - updateValue: this.updateValue - } -} - -// Add own menu -{ - let l_block = document.createElement('div'); - l_block.innerHTML = ` -
-
Pickup Arm Mover
-
-
- -
-
Enable hand movement:
-
-
-
-
- -
-
Grab offset:
-
-
-
-
- `; - document.getElementById('settings-interaction').appendChild(l_block); - - // Update toggles in new menu block - let l_toggles = l_block.querySelectorAll('.inp_toggle'); - for (var i = 0; i < l_toggles.length; i++) { - g_modSettingsPAM[g_modSettingsPAM.length] = new inp_toggle_mod_pam(l_toggles[i], 'MelonMod_PAM_Call_InpToggle'); - } - - // Update sliders in new menu block - let l_sliders = l_block.querySelectorAll('.inp_slider'); - for (var i = 0; i < l_sliders.length; i++) { - g_modSettingsPAM[g_modSettingsPAM.length] = new inp_slider_mod_pam(l_sliders[i], 'MelonMod_PAM_Call_InpSlider'); - } -} diff --git a/ml_pam/resources/ui_menu.js b/ml_pam/resources/ui_menu.js new file mode 100644 index 0000000..488bb8d --- /dev/null +++ b/ml_pam/resources/ui_menu.js @@ -0,0 +1,49 @@ +// Add settings +var g_modSettingsPAM = []; + +engine.on('updateModSettingPAM', function (_name, _value) { + for (var i = 0; i < g_modSettingsPAM.length; i++) { + if (g_modSettingsPAM[i].name == _name) { + g_modSettingsPAM[i].updateValue(_value); + break; + } + } +}); + +// Add own menu +{ + let l_block = document.createElement('div'); + l_block.innerHTML = ` +
+
Pickup Arm Movement
+
+
+ +
+
Enable hand movement:
+
+
+
+
+ +
+
Grab offset:
+
+
+
+
+ `; + document.getElementById('settings-interaction').appendChild(l_block); + + // Update toggles in new menu block + let l_toggles = l_block.querySelectorAll('.inp_toggle'); + for (var i = 0; i < l_toggles.length; i++) { + g_modSettingsPAM[g_modSettingsPAM.length] = new inp_toggle_mod(l_toggles[i], 'MelonMod_PAM_Call_InpToggle'); + } + + // Update sliders in new menu block + let l_sliders = l_block.querySelectorAll('.inp_slider'); + for (var i = 0; i < l_sliders.length; i++) { + g_modSettingsPAM[g_modSettingsPAM.length] = new inp_slider_mod(l_sliders[i], 'MelonMod_PAM_Call_InpSlider'); + } +} diff --git a/ml_vei/Main.cs b/ml_vei/Main.cs new file mode 100644 index 0000000..b942fd7 --- /dev/null +++ b/ml_vei/Main.cs @@ -0,0 +1,49 @@ +using ABI_RC.Systems.InputManagement; +using ABI_RC.Systems.InputManagement.XR; +using System; +using System.Reflection; + +namespace ml_vei +{ + public class ViveExtendedInput : MelonLoader.MelonMod + { + public override void OnInitializeMelon() + { + Settings.Init(); + + HarmonyInstance.Patch( + typeof(CVRXRModule).GetMethod("Update_Gestures_Vive", BindingFlags.NonPublic | BindingFlags.Instance), + null, + new HarmonyLib.HarmonyMethod(typeof(ViveExtendedInput).GetMethod(nameof(OnViveGesturesUpdate_Postfix), BindingFlags.Static | BindingFlags.NonPublic)) + ); + } + + static void OnViveGesturesUpdate_Postfix(ref CVRXRModule __instance) + { + try + { + if(Settings.Gestures) + { + float l_mag = ((!__instance.HasEmoteOverride) ? __instance.Primary2DAxis : __instance.EmoteOverride).magnitude; + if(__instance.ViveDirectionPressed && (l_mag >= CVRInputManager.VrViveGestureDeadZone)) + { + if(__instance.Grip > 0.5f) + { + __instance.GestureRaw = -1f; + __instance.Gesture = -1f; + } + else + { + __instance.GestureRaw = __instance.Trigger; + __instance.Gesture = __instance.Trigger; + } + } + } + } + catch(Exception e) + { + MelonLoader.MelonLogger.Error(e); + } + } + } +} diff --git a/ml_vei/Properties/AssemblyInfo.cs b/ml_vei/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..73d71dd --- /dev/null +++ b/ml_vei/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +[assembly: MelonLoader.MelonInfo(typeof(ml_vei.ViveExtendedInput), "ViveExtendedInput", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonGame(null, "ChilloutVR")] +[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] +[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] diff --git a/ml_vei/README.md b/ml_vei/README.md new file mode 100644 index 0000000..1da3abd --- /dev/null +++ b/ml_vei/README.md @@ -0,0 +1,11 @@ +# Vive Extended Input +This mod changes input behaviour for Vive controllers. + +# Installation +* Install [latest MelonLoader](https://github.com/LavaGang/MelonLoader) +* Get [latest release DLL](../../../releases/latest): + * Put `ml_vei.dll` in `Mods` folder of game + +# Usage +Available mod's settings in `Settings - Input & Key-Bindings - Vive Extended Input`: +* **Disable gestures while moving:** disables gestures while moving and sets gesture according to grip and trigger; grip has higher priority over trigger. diff --git a/ml_vei/Scripts.cs b/ml_vei/Scripts.cs new file mode 100644 index 0000000..82ef9de --- /dev/null +++ b/ml_vei/Scripts.cs @@ -0,0 +1,26 @@ +using System; +using System.IO; +using System.Reflection; + +namespace ml_vei +{ + static class Scripts + { + public static string GetEmbeddedScript(string p_name) + { + string l_result = ""; + Assembly l_assembly = Assembly.GetExecutingAssembly(); + string l_assemblyName = l_assembly.GetName().Name; + + try + { + Stream l_libraryStream = l_assembly.GetManifestResourceStream(l_assemblyName + ".resources." + p_name); + StreamReader l_streadReader = new StreamReader(l_libraryStream); + l_result = l_streadReader.ReadToEnd(); + } + catch(Exception) { } + + return l_result; + } + } +} diff --git a/ml_vei/Settings.cs b/ml_vei/Settings.cs new file mode 100644 index 0000000..25176f3 --- /dev/null +++ b/ml_vei/Settings.cs @@ -0,0 +1,80 @@ +using ABI_RC.Core.InteractionSystem; +using System; +using System.Collections.Generic; + +namespace ml_vei +{ + static class Settings + { + public enum ModSetting + { + Gestures = 0 + } + + public static bool Gestures { get; private set; } = true; + + static MelonLoader.MelonPreferences_Category ms_category = null; + static List ms_entries = null; + + static public event Action GesturesChange; + + internal static void Init() + { + ms_category = MelonLoader.MelonPreferences.CreateCategory("VEI", null, true); + + ms_entries = new List() + { + ms_category.CreateEntry(ModSetting.Gestures.ToString(), Gestures), + }; + + Load(); + + MelonLoader.MelonCoroutines.Start(WaitMainMenuUi()); + } + + static System.Collections.IEnumerator WaitMainMenuUi() + { + while(ViewManager.Instance == null) + yield return null; + while(ViewManager.Instance.gameMenuView == null) + yield return null; + while(ViewManager.Instance.gameMenuView.Listener == null) + yield return null; + + ViewManager.Instance.gameMenuView.Listener.ReadyForBindings += () => + { + ViewManager.Instance.gameMenuView.View.BindCall("MelonMod_VEI_Call_InpToggle", new Action(OnToggleUpdate)); + }; + ViewManager.Instance.gameMenuView.Listener.FinishLoad += (_) => + { + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_elements.js")); + ViewManager.Instance.gameMenuView.View.ExecuteScript(Scripts.GetEmbeddedScript("ui_menu.js")); + foreach(var l_entry in ms_entries) + ViewManager.Instance.gameMenuView.View.TriggerEvent("updateModSettingVEI", l_entry.DisplayName, l_entry.GetValueAsString()); + }; + } + + static void Load() + { + Gestures = (bool)ms_entries[(int)ModSetting.Gestures].BoxedValue; + } + + static void OnToggleUpdate(string p_name, string p_value) + { + if(Enum.TryParse(p_name, out ModSetting l_setting)) + { + switch(l_setting) + { + case ModSetting.Gestures: + { + Gestures = bool.Parse(p_value); + GesturesChange?.Invoke(Gestures); + } + break; + } + + ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); + } + } + } +} diff --git a/ml_vei/Utils.cs b/ml_vei/Utils.cs new file mode 100644 index 0000000..ad1851f --- /dev/null +++ b/ml_vei/Utils.cs @@ -0,0 +1,12 @@ +using ABI_RC.Core.UI; +using System.Reflection; + +namespace ml_vei +{ + static class Utils + { + static readonly FieldInfo ms_view = typeof(CohtmlControlledViewWrapper).GetField("_view", BindingFlags.NonPublic | BindingFlags.Instance); + + static public void ExecuteScript(this CohtmlControlledViewWrapper p_instance, string p_script) => ((cohtml.Net.View)ms_view.GetValue(p_instance)).ExecuteScript(p_script); + } +} diff --git a/ml_vei/ml_vei.csproj b/ml_vei/ml_vei.csproj new file mode 100644 index 0000000..2e147ab --- /dev/null +++ b/ml_vei/ml_vei.csproj @@ -0,0 +1,64 @@ + + + + netstandard2.1 + x64 + ViveExtendedInput + 1.0.0 + SDraw + None + ViveExtendedInput + + + + + + + + + + D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\0Harmony.dll + false + + + D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll + false + + + D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\cohtml.Net.dll + + + D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Cohtml.Runtime.dll + + + D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll + false + + + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Unity.Postprocessing.Runtime.dll + false + + + D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.dll + false + + + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.AnimationModule.dll + false + + + D:\Games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll + false + + + + + + + + + + + + + diff --git a/ml_vei/resources/ui_menu.js b/ml_vei/resources/ui_menu.js new file mode 100644 index 0000000..8506252 --- /dev/null +++ b/ml_vei/resources/ui_menu.js @@ -0,0 +1,36 @@ +// Add settings +var g_modSettingsVEI = []; + +engine.on('updateModSettingVEI', function (_name, _value) { + for (var i = 0; i < g_modSettingsVEI.length; i++) { + if (g_modSettingsVEI[i].name == _name) { + g_modSettingsVEI[i].updateValue(_value); + break; + } + } +}); + +// Add own menu +{ + let l_block = document.createElement('div'); + l_block.innerHTML = ` +
+
Vive Extended Input
+
+
+ +
+
Disable gestures while moving:
+
+
+
+
+ `; + document.getElementById('settings-input').appendChild(l_block); + + // Update toggles in new menu block + let l_toggles = l_block.querySelectorAll('.inp_toggle'); + for (var i = 0; i < l_toggles.length; i++) { + g_modSettingsVEI[g_modSettingsVEI.length] = new inp_toggle_mod(l_toggles[i], 'MelonMod_VEI_Call_InpToggle'); + } +}