New mod: PlayerAvatarHistory

Incremented version for nightly to prevent rollback by auto-updater
Minor fixes
This commit is contained in:
SDraw 2025-07-03 16:15:47 +03:00
parent 7f29079109
commit 9f78aa4620
No known key found for this signature in database
GPG key ID: BB95B4DAB2BB8BB5
23 changed files with 575 additions and 23 deletions

View file

@ -121,9 +121,11 @@ namespace ml_bft
Animator l_animator = PlayerSetup.Instance.Animator;
if(l_animator.isHuman)
{
Utils.SetAvatarTPose();
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
foreach(var l_tuple in ms_fingersChains)
{
ReorientateTowards(
@ -221,14 +223,14 @@ namespace ml_bft
{
if(m_ready && MetaPort.Instance.isUsingVr && (p_handler != null) && Settings.SkeletalInput)
{
if(CVRInputManager.Instance._leftController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None)
if(CVRInputManager.Instance.IsLeftControllerTracking())
{
Quaternion l_turnBack = (m_leftHandOffset.m_source.rotation * m_leftHandOffset.m_offset) * Quaternion.Inverse(m_leftHandOffset.m_target.rotation);
foreach(var l_offset in m_leftFingerOffsets)
l_offset.m_target.rotation = l_turnBack * (l_offset.m_source.rotation * l_offset.m_offset);
}
if(CVRInputManager.Instance._rightController != ABI_RC.Systems.InputManagement.XR.eXRControllerType.None)
if(CVRInputManager.Instance.IsRightControllerTracking())
{
Quaternion l_turnBack = (m_rightHandOffset.m_source.rotation * m_rightHandOffset.m_offset) * Quaternion.Inverse(m_rightHandOffset.m_target.rotation);
foreach(var l_offset in m_rightFingerOffsets)

View file

@ -17,12 +17,5 @@ namespace ml_bft
public static bool IsInVR() => ((MetaPort.Instance != null) && MetaPort.Instance.isUsingVr);
public static bool AreKnucklesInUse() => ((CVRInputManager.Instance._leftController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index) || (CVRInputManager.Instance._rightController == ABI_RC.Systems.InputManagement.XR.eXRControllerType.Index));
public static void SetAvatarTPose()
{
IKSystem.Instance.SetAvatarPose(IKSystem.AvatarPose.TPose);
PlayerSetup.Instance.AvatarTransform.localPosition = Vector3.zero;
PlayerSetup.Instance.AvatarTransform.localRotation = Quaternion.identity;
}
}
}

View file

@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_ppu", "ml_ppu\ml_ppu.csp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ml_vet", "ml_vet\ml_vet.csproj", "{8DB32590-FC5B-46A8-9747-344E86B18ACF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ml_pah", "ml_pah\ml_pah.csproj", "{C4659F60-3FED-4F43-88E4-969907D4C7A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -83,6 +85,9 @@ Global
{8DB32590-FC5B-46A8-9747-344E86B18ACF}.Debug|x64.Build.0 = Debug|x64
{8DB32590-FC5B-46A8-9747-344E86B18ACF}.Release|x64.ActiveCfg = Release|x64
{8DB32590-FC5B-46A8-9747-344E86B18ACF}.Release|x64.Build.0 = Release|x64
{C4659F60-3FED-4F43-88E4-969907D4C7A6}.Debug|x64.ActiveCfg = Debug|x64
{C4659F60-3FED-4F43-88E4-969907D4C7A6}.Release|x64.ActiveCfg = Release|x64
{C4659F60-3FED-4F43-88E4-969907D4C7A6}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

14
ml_pah/AvatarEntry.cs Normal file
View file

@ -0,0 +1,14 @@
using System;
namespace ml_pah
{
[Serializable]
class AvatarEntry
{
public string m_id;
public string m_name;
public string m_imageUrl;
public DateTime m_lastUsageDate;
public bool m_cached = false;
}
}

205
ml_pah/HistoryManager.cs Normal file
View file

@ -0,0 +1,205 @@
using ABI_RC.Core.Networking.API;
using ABI_RC.Core.Networking.API.Responses;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace ml_pah
{
static class HistoryManager
{
internal class EntriesUpdateEvent
{
event Action m_action;
public void AddListener(Action p_listener) => m_action += p_listener;
public void RemoveListener(Action p_listener) => m_action -= p_listener;
public void Invoke() => m_action?.Invoke();
}
public static readonly EntriesUpdateEvent OnEntriesUpdated = new EntriesUpdateEvent();
static bool ms_initialized = false;
static string ms_historyPath;
readonly static List<AvatarEntry> ms_avatarEntries = new List<AvatarEntry>();
static int ms_lastTick = 0;
// Init
internal static void Initialize()
{
if(!ms_initialized)
{
ms_historyPath = Path.Combine(MelonLoader.Utils.MelonEnvironment.UserDataDirectory, "PlayerAvatarHistory.json");
try
{
if(File.Exists(ms_historyPath))
{
string l_json = File.ReadAllText(ms_historyPath);
List<AvatarEntry> l_entries = JsonConvert.DeserializeObject<List<AvatarEntry>>(l_json);
if(l_entries != null)
{
ms_avatarEntries.AddRange(l_entries);
LimitEntries();
ms_avatarEntries.Sort((a, b) => a.m_lastUsageDate.CompareTo(b.m_lastUsageDate));
}
}
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
ms_lastTick = Environment.TickCount;
Settings.OnAutosaveTimeChanged.AddListener(OnAutosaveTimeChanged);
ms_initialized = true;
}
}
internal static void Shutdown()
{
if(ms_initialized)
{
SaveHistory();
Settings.OnAutosaveTimeChanged.RemoveListener(OnAutosaveTimeChanged);
ms_initialized = false;
}
}
// Update
public static void Update()
{
if(ms_initialized && (Settings.AutosaveTime > 0))
{
int l_tick = Environment.TickCount;
if((l_tick - ms_lastTick) >= (Settings.AutosaveTime * 60000))
{
MelonLoader.MelonCoroutines.Start(AutosaveCoroutine());
ms_lastTick = l_tick;
}
}
}
// Entries
internal static List<AvatarEntry> GetAvatarEntries() => ms_avatarEntries;
internal static void AddEntry(string p_id)
{
if(ms_initialized)
{
int l_index = ms_avatarEntries.FindIndex(l_entry => l_entry.m_id == p_id);
if(l_index != -1)
{
ms_avatarEntries[l_index].m_lastUsageDate = DateTime.Now;
if(l_index != 0)
{
// Move in list
AvatarEntry l_entry = ms_avatarEntries[l_index];
ms_avatarEntries.RemoveAt(l_index);
ms_avatarEntries.Insert(0, l_entry);
OnEntriesUpdated?.Invoke();
}
}
else
{
AvatarEntry l_entry = new AvatarEntry();
l_entry.m_id = p_id;
l_entry.m_name = "Loading ...";
l_entry.m_lastUsageDate = DateTime.Now;
MelonLoader.MelonCoroutines.Start(RequestAvatarInfo(l_entry));
}
}
}
// History
internal static void ClearHistory() => ms_avatarEntries.Clear();
internal static void SaveHistory()
{
if(ms_initialized)
{
try
{
string l_json = JsonConvert.SerializeObject(ms_avatarEntries, Formatting.Indented);
File.WriteAllText(ms_historyPath, l_json);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
static IEnumerator AutosaveCoroutine()
{
List<AvatarEntry> l_listCopy = new List<AvatarEntry>();
l_listCopy.AddRange(ms_avatarEntries);
Task l_task = Task.Run(() => AutosaveTask(l_listCopy));
while(!l_task.IsCompleted)
yield return null;
}
static async Task AutosaveTask(List<AvatarEntry> p_entries)
{
try
{
string l_json = JsonConvert.SerializeObject(p_entries, Formatting.Indented);
File.WriteAllText(ms_historyPath, l_json);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
await Task.Delay(1);
}
// Network request
static IEnumerator RequestAvatarInfo(AvatarEntry p_entry)
{
Task l_task = Task.Run(() => RequestAvatarInfoTask(p_entry));
while(!l_task.IsCompleted)
yield return null;
ms_avatarEntries.Insert(0, p_entry);
LimitEntries();
OnEntriesUpdated?.Invoke();
}
static async Task RequestAvatarInfoTask(AvatarEntry p_entry)
{
BaseResponse<AvatarDetailsResponse> l_baseResponse = await ApiConnection.MakeRequest<AvatarDetailsResponse>(ApiConnection.ApiOperation.AvatarDetail, new { avatarID = p_entry.m_id });
if(l_baseResponse != null)
{
if(!l_baseResponse.IsSuccessStatusCode) return;
p_entry.m_name = l_baseResponse.Data.Name;
p_entry.m_imageUrl = l_baseResponse.Data.ImageUrl;
p_entry.m_cached = true;
}
}
// Settings
static void OnAutosaveTimeChanged(int p_value)
{
ms_lastTick = Environment.TickCount;
}
// Utility
static void LimitEntries()
{
int l_currentLimit = Settings.AvatarsLimit;
if(ms_avatarEntries.Count > l_currentLimit)
ms_avatarEntries.RemoveRange(l_currentLimit, ms_avatarEntries.Count - (l_currentLimit - 1));
}
}
}

59
ml_pah/Main.cs Normal file
View file

@ -0,0 +1,59 @@
using ABI.CCK.Components;
using ABI_RC.Core;
using System;
using System.Collections;
using ABI_RC.Systems.GameEventSystem;
namespace ml_pah
{
public class PlayerAvatarHistory : MelonLoader.MelonMod
{
public override void OnInitializeMelon()
{
Settings.Init();
HistoryManager.Initialize();
ModUi.Initialize();
MelonLoader.MelonCoroutines.Start(WaitForRootLogic());
}
public override void OnDeinitializeMelon()
{
CVRGameEventSystem.Avatar.OnLocalAvatarLoad.RemoveListener(this.OnLocalAvatarLoad);
HistoryManager.OnEntriesUpdated.RemoveListener(this.OnHistoryEntriesUpdated);
ModUi.Shutdown();
HistoryManager.Shutdown();
}
IEnumerator WaitForRootLogic()
{
while(RootLogic.Instance == null)
yield return null;
CVRGameEventSystem.Avatar.OnLocalAvatarLoad.AddListener(this.OnLocalAvatarLoad);
HistoryManager.OnEntriesUpdated.AddListener(this.OnHistoryEntriesUpdated);
}
public override void OnUpdate()
{
HistoryManager.Update();
}
// Game events
void OnLocalAvatarLoad(CVRAvatar p_avatar)
{
try
{
if((p_avatar.AssetInfo != null) && (p_avatar.AssetInfo.objectId.Length > 0))
HistoryManager.AddEntry(p_avatar.AssetInfo.objectId);
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
// Mod events
void OnHistoryEntriesUpdated() => ModUi.UpdateAvatarsList();
}
}

131
ml_pah/ModUi.cs Normal file
View file

@ -0,0 +1,131 @@
using ABI_RC.Core.EventSystem;
using ABI_RC.Core.InteractionSystem;
using BTKUILib.UIObjects;
using BTKUILib.UIObjects.Components;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace ml_pah
{
static class ModUi
{
readonly static string ms_namespace = typeof(ModUi).Namespace;
static bool ms_initialized = false;
static Page ms_page = null;
static Category ms_settingsCategory = null;
static Button ms_settingsClearButton = null;
static Button ms_settingSaveButton = null;
static SliderFloat ms_settingsEntriesLimit = null;
static SliderFloat ms_settingsAutosaveTime = null;
static Category ms_buttonsCategory = null;
static readonly List<Button> ms_avatarButtons = new List<Button>();
// Init
internal static void Initialize()
{
if(!ms_initialized)
{
BTKUILib.QuickMenuAPI.PrepareIcon("PlayerAvatarHistory", "guardian", GetIconStream("guardian.png"));
BTKUILib.QuickMenuAPI.PrepareIcon("PlayerAvatarHistory", "delete", GetIconStream("delete.png"));
BTKUILib.QuickMenuAPI.PrepareIcon("PlayerAvatarHistory", "save", GetIconStream("save.png"));
ms_page = new Page("PlayerAvatarHistory", "MainPage", true, "guardian");
ms_page.MenuTitle = "Player Avatar History";
ms_page.MenuSubtitle = "List of last used avatars";
ms_settingsCategory = ms_page.AddCategory("Settings");
ms_settingsClearButton = ms_settingsCategory.AddButton("Clear history", "delete", "Clear current history");
ms_settingsClearButton.OnPress += ClearHistory;
ms_settingSaveButton = ms_settingsCategory.AddButton("Save history", "save", "Manually save current history");
ms_settingSaveButton.OnPress += SaveHistory;
ms_settingsEntriesLimit = ms_settingsCategory.AddSlider("History limit", "Number of saved avatar history entries.<p>Warning: Large value can impact performance.", Settings.AvatarsLimit, 10f, 100f, 0);
ms_settingsEntriesLimit.OnValueUpdated += OnAvatarLimitChange;
ms_settingsAutosaveTime = ms_settingsCategory.AddSlider("Autosave period", "Automatic history saving in minutes.", Settings.AutosaveTime, 0f, 60f, 0);
ms_settingsAutosaveTime.OnValueUpdated += OnAutosaveTimeChange;
ms_buttonsCategory = ms_page.AddCategory("Avatars");
RegenerateAvatarButtons();
ms_initialized = true;
}
}
internal static void Shutdown()
{
if(ms_initialized)
{
ms_page = null;
ms_buttonsCategory = null;
ms_avatarButtons.Clear();
ms_settingsCategory = null;
ms_settingSaveButton = null;
ms_settingsClearButton = null;
ms_initialized = false;
}
}
// History
static void ClearHistory()
{
BTKUILib.QuickMenuAPI.ShowConfirm(
"Clear history", "Are you sure want to clear all avatar history?",
() =>
{
HistoryManager.ClearHistory();
RegenerateAvatarButtons();
}
);
}
static void SaveHistory() => HistoryManager.SaveHistory();
// Update
public static void UpdateAvatarsList()
{
if(ms_initialized)
RegenerateAvatarButtons();
}
// Settings
static void OnAvatarLimitChange(float p_value) => Settings.SetSetting(Settings.ModSetting.AvatarsLimit, (int)p_value);
static void OnAutosaveTimeChange(float p_value) => Settings.SetSetting(Settings.ModSetting.AutosaveTime, (int)p_value);
// Utility
static void RegenerateAvatarButtons()
{
if(ms_avatarButtons.Count > 0)
{
foreach(Button l_button in ms_avatarButtons)
l_button.Delete();
ms_avatarButtons.Clear();
}
foreach(AvatarEntry l_entry in HistoryManager.GetAvatarEntries())
{
Button l_button = ms_buttonsCategory.AddButton("", "", "", ButtonStyle.FullSizeImage);
l_button.ButtonText = (l_entry.m_cached ? l_entry.m_name : "Loading ...");
l_button.ButtonIcon = (l_entry.m_cached ? l_entry.m_imageUrl : "");
l_button.ButtonTooltip = string.Format("Click to open avatar page, hold to switch avatar.<p>Last used time: {0}", l_entry.m_lastUsageDate.ToString("g"));
l_button.OnPress += () => ViewManager.Instance.RequestAvatarDetailsPage(l_entry.m_id);
l_button.OnHeld += () => AssetManagement.Instance.LoadLocalAvatarFromNetwork(l_entry.m_id);
ms_avatarButtons.Add(l_button);
}
}
static Stream GetIconStream(string p_name) => Assembly.GetExecutingAssembly().GetManifestResourceStream(ms_namespace + ".resources." + p_name);
}
}

View file

@ -0,0 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_pah.PlayerAvatarHistory), "PlayerAvatarHistory", "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)]

77
ml_pah/Settings.cs Normal file
View file

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace ml_pah
{
static class Settings
{
internal class SettingEvent<T>
{
event Action<T> m_action;
public void AddListener(Action<T> p_listener) => m_action += p_listener;
public void RemoveListener(Action<T> p_listener) => m_action -= p_listener;
public void Invoke(T p_value) => m_action?.Invoke(p_value);
}
public enum ModSetting
{
AvatarsLimit = 0,
AutosaveTime
}
public static int AvatarsLimit { get; private set; } = 12;
public static int AutosaveTime { get; private set; } = 15;
public static readonly SettingEvent<int> OnAvatarsLimitChanged = new SettingEvent<int>();
public static readonly SettingEvent<int> OnAutosaveTimeChanged = new SettingEvent<int>();
static MelonLoader.MelonPreferences_Category ms_category = null;
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
internal static void Init()
{
ms_category = MelonLoader.MelonPreferences.CreateCategory("PAH", "Player Avatar History");
ms_entries = new List<MelonLoader.MelonPreferences_Entry>()
{
ms_category.CreateEntry(ModSetting.AvatarsLimit.ToString(), AvatarsLimit),
ms_category.CreateEntry(ModSetting.AutosaveTime.ToString(), AutosaveTime)
};
AvatarsLimit = Mathf.Clamp((int)ms_entries[(int)ModSetting.AvatarsLimit].BoxedValue, 10, 100);
AutosaveTime = Mathf.Clamp((int)ms_entries[(int)ModSetting.AutosaveTime].BoxedValue, 0, 60);
}
public static void SetSetting(ModSetting p_settings, object p_value)
{
try
{
switch(p_settings)
{
// Booleans
case ModSetting.AvatarsLimit:
{
AvatarsLimit = (int)p_value;
OnAvatarsLimitChanged.Invoke(AvatarsLimit);
}
break;
case ModSetting.AutosaveTime:
{
AutosaveTime = (int)p_value;
OnAutosaveTimeChanged.Invoke(AutosaveTime);
}
break;
}
if(ms_entries != null)
ms_entries[(int)p_settings].BoxedValue = p_value;
}
catch(Exception e)
{
MelonLoader.MelonLogger.Error(e);
}
}
}
}

60
ml_pah/ml_pah.csproj Normal file
View file

@ -0,0 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>PlayerAvatarHistory</PackageId>
<AssemblyName>PlayerAvatarHistory</AssemblyName>
<Authors>SDraw</Authors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>embedded</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<None Remove="resources\delete.png" />
<None Remove="resources\guardian.png" />
<None Remove="resources\save.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="resources\delete.png" />
<EmbeddedResource Include="resources\guardian.png" />
<EmbeddedResource Include="resources\save.png" />
</ItemGroup>
<ItemGroup>
<Reference Include="Assembly-CSharp">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="BTKUILib">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\Mods\BTKUILib.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="MelonLoader">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\MelonLoader\net35\MelonLoader.dll</HintPath>
<Private>false</Private>
<SpecificVersion>false</SpecificVersion>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\Newtonsoft.Json.dll</HintPath>
<SpecificVersion>false</SpecificVersion>
<Private>false</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>D:\games\Steam\steamapps\common\ChilloutVR\ChilloutVR_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<SpecificVersion>false</SpecificVersion>
<Private>false</Private>
</Reference>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="copy /y &quot;$(TargetPath)&quot; &quot;D:\Games\Steam\steamapps\common\ChilloutVR\Mods\&quot;" />
</Target>
</Project>

BIN
ml_pah/resources/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
ml_pah/resources/save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.1.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_pmc.PlayerMovementCopycat), "PlayerMovementCopycat", "1.1.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(3)]
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]

View file

@ -1,4 +1,5 @@
using ABI.CCK.Components;
using ABI_RC.Core;
using ABI_RC.Core.Savior;
using ABI_RC.Systems.InputManagement;
using System.Collections.Generic;
@ -86,9 +87,9 @@ namespace ml_pmc
List<RaycastHit> l_hits = Physics.RaycastAll(l_ray, p_limit).ToList();
if(l_hits.Count > 0)
{
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("UI Internal")); // Somehow layer mask in RaycastAll just ignores players entirely
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerLocal"));
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == LayerMask.NameToLayer("PlayerClone"));
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == CVRLayers.UIInternal); // Somehow layer mask in RaycastAll just ignores players entirely
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == CVRLayers.PlayerLocal);
l_hits.RemoveAll(hit => hit.collider.gameObject.layer == CVRLayers.PlayerClone);
l_hits.Sort((a, b) => ((a.distance < b.distance) ? -1 : 1));
l_result = (l_hits[0].collider.gameObject.transform.root == p_target.transform.root);
}

View file

@ -7,7 +7,7 @@
<Authors>SDraw</Authors>
<Company>SDraw</Company>
<Product>PlayerMovementCopycat</Product>
<Version>1.1.1</Version>
<Version>1.1.2</Version>
<AssemblyName>PlayerMovementCopycat</AssemblyName>
</PropertyGroup>
@ -23,6 +23,7 @@
<ItemGroup>
<None Remove="resources\dancing.png" />
<None Remove="resources\dancing_on.png" />
<None Remove="Utils.cs~RFd8ec2a.TMP" />
</ItemGroup>
<ItemGroup>

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_ppu.PlayerPickUp), "PlayerPickUp", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_ppu.PlayerPickUp), "PlayerPickUp", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonOptionalDependencies("PlayerRagdollMod")]
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]

View file

@ -5,7 +5,7 @@
<Platforms>x64</Platforms>
<AssemblyName>PlayerPickUp</AssemblyName>
<Authors>SDraw</Authors>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.2.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_prm.PlayerRagdollMod), "PlayerRagdollMod", "1.2.4", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
[assembly: MelonLoader.MelonPriority(2)]
[assembly: MelonLoader.MelonAdditionalDependencies("BTKUILib")]

View file

@ -77,7 +77,7 @@ namespace ml_prm
void Start()
{
this.gameObject.layer = LayerMask.NameToLayer("PlayerLocal");
this.gameObject.layer = CVRLayers.PlayerLocal;
m_physicsMaterial = new PhysicMaterial("Ragdoll");
m_physicsMaterial.dynamicFriction = c_defaultFriction;

View file

@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<Platforms>x64</Platforms>
<PackageId>PlayerRagdollMod</PackageId>
<Version>1.2.3</Version>
<Version>1.2.4</Version>
<Authors>SDraw</Authors>
<Company>SDraw</Company>
<Product>PlayerRagdollMod</Product>

View file

@ -1,4 +1,4 @@
[assembly: MelonLoader.MelonInfo(typeof(ml_vpc.VideoPlayerCookies), "VideoPlayerCookies", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
[assembly: MelonLoader.MelonInfo(typeof(ml_vpc.VideoPlayerCookies), "VideoPlayerCookies", "1.0.2", "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)]

View file

@ -6,7 +6,7 @@
<AssemblyName>VideoPlayerCookies</AssemblyName>
<Authors>SDraw</Authors>
<Company>SDraw</Company>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">