CVRLuaToolsExtension: Fixed tracking of lua components on multiple of same asset with same Instance Id

This commit is contained in:
NotAKidoS 2024-08-17 07:33:20 -05:00
parent 6810bcf021
commit db87288da6
5 changed files with 55 additions and 62 deletions

View file

@ -9,79 +9,64 @@ namespace NAK.CVRLuaToolsExtension;
public static class LuaHotReloadManager public static class LuaHotReloadManager
{ {
private static readonly Dictionary<string, List<int>> s_AssetIdToLuaClientBehaviourIds = new(); // (asset id + lua component id) -> index is component reference
private static readonly Dictionary<int, CVRLuaClientBehaviour> s_LuaComponentIdsToLuaClientBehaviour = new(); private static readonly List<int> s_CombinedKeys = new();
private static readonly List<CVRLuaClientBehaviour> s_LuaComponentInstances = new();
#region Game Events #region Game Events
public static void OnCVRLuaBaseBehaviourLoadAndRunScript(CVRLuaClientBehaviour clientBehaviour) public static void OnCVRLuaBaseBehaviourLoadAndRunScript(CVRLuaClientBehaviour clientBehaviour)
{ {
//CVRLuaToolsExtensionMod.Logger.Msg($"[LuaHotReloadManager] Script awake: {clientBehaviour.name}");
if (!clientBehaviour.IsScriptEligibleForHotReload()) if (!clientBehaviour.IsScriptEligibleForHotReload())
return; return;
var assetId = clientBehaviour.GetAssetIdFromScript(); // check if the component is already in the list (shouldn't happen)
if (!s_AssetIdToLuaClientBehaviourIds.ContainsKey(assetId)) if (s_LuaComponentInstances.Contains(clientBehaviour))
s_AssetIdToLuaClientBehaviourIds[assetId] = new List<int>();
var luaComponentId = GetGameObjectPathHashCode(clientBehaviour.transform);
if (s_AssetIdToLuaClientBehaviourIds[assetId].Contains(luaComponentId))
{ {
CVRLuaToolsExtensionMod.Logger.Warning( CVRLuaToolsExtensionMod.Logger.Warning($"[LuaHotReloadManager] Script already added: {clientBehaviour.name}");
$"[LuaHotReloadManager] Script already exists: {clientBehaviour.name}");
return; return;
} }
s_AssetIdToLuaClientBehaviourIds[assetId].Add(luaComponentId); // combine the assetId and instanceId into a single key, so multiple instances of the same script can be tracked
s_LuaComponentIdsToLuaClientBehaviour[luaComponentId] = clientBehaviour; string assetId = clientBehaviour.GetAssetIdFromScript();
int instanceId = GetGameObjectPathHashCode(clientBehaviour.transform);
int combinedKey = GenerateCombinedKey(assetId.GetHashCode(), instanceId);
s_CombinedKeys.Add(combinedKey);
s_LuaComponentInstances.Add(clientBehaviour);
CVRLuaToolsExtensionMod.Logger.Msg($"[LuaHotReloadManager] Added script: {clientBehaviour.name}"); CVRLuaToolsExtensionMod.Logger.Msg($"[LuaHotReloadManager] Added script: {clientBehaviour.name}");
} }
public static void OnCVRLuaBaseBehaviourDestroy(CVRLuaClientBehaviour clientBehaviour) public static void OnCVRLuaBaseBehaviourDestroy(CVRLuaClientBehaviour clientBehaviour)
{ {
//CVRLuaToolsExtensionMod.Logger.Msg($"[LuaHotReloadManager] Script destroy: {clientBehaviour.name}"); if (!clientBehaviour.IsScriptEligibleForHotReload())
var assetId = clientBehaviour.GetAssetIdFromScript();
if (!s_AssetIdToLuaClientBehaviourIds.ContainsKey(assetId))
return; return;
var luaClientBehaviourIds = s_AssetIdToLuaClientBehaviourIds[assetId]; if (!s_LuaComponentInstances.Contains(clientBehaviour))
foreach (var luaComponentId in luaClientBehaviourIds)
{ {
if (!s_LuaComponentIdsToLuaClientBehaviour.TryGetValue(luaComponentId, CVRLuaToolsExtensionMod.Logger.Warning($"[LuaHotReloadManager] Eligible for Hot Reload script destroyed without being tracked first: {clientBehaviour.name}");
out CVRLuaClientBehaviour luaClientBehaviour)) return;
continue;
if (luaClientBehaviour != clientBehaviour)
continue;
s_LuaComponentIdsToLuaClientBehaviour.Remove(luaComponentId);
luaClientBehaviourIds.Remove(luaComponentId);
if (luaClientBehaviourIds.Count == 0) s_AssetIdToLuaClientBehaviourIds.Remove(assetId);
CVRLuaToolsExtensionMod.Logger.Msg($"[LuaHotReloadManager] Removed script: {clientBehaviour.name}");
break;
} }
int index = s_LuaComponentInstances.IndexOf(clientBehaviour);
s_CombinedKeys.RemoveAt(index);
s_LuaComponentInstances.RemoveAt(index);
CVRLuaToolsExtensionMod.Logger.Msg($"[LuaHotReloadManager] Removed script: {clientBehaviour.name}");
} }
public static void OnReceiveUpdatedScript(ScriptInfo info) public static void OnReceiveUpdatedScript(ScriptInfo info)
{ {
if (!s_AssetIdToLuaClientBehaviourIds.TryGetValue(info.AssetId, out var luaComponentIds)) int combinedKey = GenerateCombinedKey(info.AssetId.GetHashCode(), info.LuaComponentId);
{
CVRLuaToolsExtensionMod.Logger.Warning(
$"[LuaHotReloadManager] No scripts found for asset id: {info.AssetId}");
return;
}
bool found = false; bool found = false;
foreach (var luaComponentId in luaComponentIds) for (int i = 0; i < s_CombinedKeys.Count; i++)
{ {
if (!s_LuaComponentIdsToLuaClientBehaviour.TryGetValue(luaComponentId, if (combinedKey != s_CombinedKeys[i])
out CVRLuaClientBehaviour clientBehaviour))
continue; continue;
found = true; CVRLuaClientBehaviour clientBehaviour = s_LuaComponentInstances[i];
//CVRLuaToolsExtensionMod.Logger.Msg($"[LuaHotReloadManager] Reloading script: {info.ScriptName} for {clientBehaviour.name}");
if (clientBehaviour.asset.m_ScriptPath == info.ScriptPath) if (clientBehaviour.asset.m_ScriptPath == info.ScriptPath)
{ {
@ -89,6 +74,7 @@ public static class LuaHotReloadManager
clientBehaviour.asset.name = info.ScriptName; clientBehaviour.asset.name = info.ScriptName;
clientBehaviour.asset.m_ScriptText = info.ScriptText; clientBehaviour.asset.m_ScriptText = info.ScriptText;
clientBehaviour.Restart(); clientBehaviour.Restart();
found = true;
} }
else else
{ {
@ -102,25 +88,31 @@ public static class LuaHotReloadManager
clientBehaviour.asset.m_ScriptText = info.ScriptText; clientBehaviour.asset.m_ScriptText = info.ScriptText;
clientBehaviour.Restart(); clientBehaviour.Restart();
found = true;
} }
} }
if (found) CohtmlHud.Instance.ViewDropTextImmediate("(Local) CVRLuaTools", "Received script update", "Reloaded script: " + info.ScriptName); if (found)
{
CohtmlHud.Instance.ViewDropTextImmediate("(Local) CVRLuaTools", "Received script update", "Reloaded script: " + info.ScriptName);
}
} }
#endregion Game Events #endregion Game Events
#region Private Methods #region Private Methods
private static int GenerateCombinedKey(int assetId, int instanceId)
{
return (assetId << 16) | instanceId; // yes
}
private static int GetGameObjectPathHashCode(Transform transform) private static int GetGameObjectPathHashCode(Transform transform)
{ {
// Attempt to find the root component transform in one step
Transform rootComponentTransform = null;
// both CVRAvatar & CVRSpawnable *should* have an asset info component // both CVRAvatar & CVRSpawnable *should* have an asset info component
Transform rootComponentTransform = null;
CVRAssetInfo rootComponent = transform.GetComponentInParent<CVRAssetInfo>(true); CVRAssetInfo rootComponent = transform.GetComponentInParent<CVRAssetInfo>(true);
if (rootComponent != null && rootComponent.type != CVRAssetInfo.AssetType.World) if (rootComponent != null && rootComponent.type != CVRAssetInfo.AssetType.World) // ignore if under world instance
rootComponentTransform = rootComponent.transform; rootComponentTransform = rootComponent.transform;
// easy case, no need to crawl up the hierarchy // easy case, no need to crawl up the hierarchy

View file

@ -4,6 +4,7 @@ using ABI.CCK.Components;
using HarmonyLib; using HarmonyLib;
using MelonLoader; using MelonLoader;
using NAK.CVRLuaToolsExtension.NamedPipes; using NAK.CVRLuaToolsExtension.NamedPipes;
using UnityEngine;
namespace NAK.CVRLuaToolsExtension; namespace NAK.CVRLuaToolsExtension;

View file

@ -27,6 +27,6 @@ using System.Reflection;
namespace NAK.CVRLuaToolsExtension.Properties; namespace NAK.CVRLuaToolsExtension.Properties;
internal static class AssemblyInfoParams internal static class AssemblyInfoParams
{ {
public const string Version = "1.0.0"; public const string Version = "1.0.1";
public const string Author = "NotAKidoS"; public const string Author = "NotAKidoS";
} }

View file

@ -1,6 +1,6 @@
# IKSimulatedRootAngleFix # CVRLuaToolsExtension
Fixes a small issue with Desktop & HalfBody root angle being incorrectly calculated while on rotating Movement Parents. If you've ever noticed your body/feet insisting on facing opposite of the direction you are rotating, this fixes that. Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality.
--- ---

View file

@ -1,24 +1,24 @@
{ {
"_id": -1, "_id": -1,
"name": "AASDefaultProfileFix", "name": "CVRLuaToolsExtension",
"modversion": "1.0.0", "modversion": "1.0.0",
"gameversion": "2024r175", "gameversion": "2024r175",
"loaderversion": "0.6.1", "loaderversion": "0.6.1",
"modtype": "Mod", "modtype": "Mod",
"author": "NotAKidoS", "author": "NotAKidoS",
"description": "Fixes the Default AAS profile not being applied when loading into an avatar without a profile selected.\n\nBy default, the game will not apply anything and the avatar will default to the state found within the Controller parameters.", "description": "Extension mod for [CVRLuaTools](https://github.com/NotAKidoS/CVRLuaTools) Hot Reload functionality.",
"searchtags": [ "searchtags": [
"aas", "lua",
"profile", "scripting",
"default", "hotreload",
"fix", "reload",
"meow" "development"
], ],
"requirements": [ "requirements": [
"None" "None"
], ],
"downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r33/AASDefaultProfileFix.dll", "downloadlink": "https://github.com/NotAKidoS/NAK_CVR_Mods/releases/download/r33/CVRLuaToolsExtension.dll",
"sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AASDefaultProfileFix/", "sourcelink": "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/CVRLuaToolsExtension/",
"changelog": "- Initial release", "changelog": "- Initial release",
"embedcolor": "#f61963" "embedcolor": "#f61963"
} }