mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-07 16:49:17 +00:00
Compare commits
149 commits
Author | SHA1 | Date | |
---|---|---|---|
|
226b369537 | ||
|
e54e50e76d | ||
|
6bef1d0c96 | ||
|
1496c25184 | ||
|
c368daab4f | ||
|
30c069388c | ||
|
c9acb00088 | ||
|
4123a1f25d | ||
|
7f5ca4b29d | ||
|
6dc7f8a267 | ||
|
6ad23e6fc5 | ||
|
2f668b289c | ||
|
6d28f734da | ||
|
969bd00df3 | ||
|
7deddd88ea | ||
|
1a591749c6 | ||
|
218344a121 | ||
|
07daceea44 | ||
|
aaeb187b9e | ||
|
e378a717d3 | ||
|
a0a859aa86 | ||
|
13e206cd58 | ||
|
548fcf72bc | ||
|
ee4df06d2e | ||
|
faf9d48fb6 | ||
|
c455d20f9c | ||
|
0cdef04a53 | ||
|
e96a0e164d | ||
|
bf877124c1 | ||
|
cc7762293d | ||
|
b75dce1d02 | ||
|
0a01534aa4 | ||
|
8b34359d1b | ||
|
d54ec06190 | ||
|
daf2d7db0f | ||
|
bdf6b0e51a | ||
|
abd7b9d674 | ||
|
da6520beb0 | ||
|
3521453010 | ||
|
0f6006db83 | ||
|
e85c1e2f25 | ||
|
ece15e0dfc | ||
|
47b69dfbc7 | ||
|
63948ddf69 | ||
|
f6afea3c44 | ||
|
8343d6c5bb | ||
|
6e37bcbabb | ||
|
c4ab9cce47 | ||
|
88f3b1a41f | ||
|
9606b10c9d | ||
|
d5d4e3eddd | ||
|
377b365cdc | ||
|
21b791083b | ||
|
8ad74b5ef6 | ||
|
134c8e7878 | ||
|
1f8435edb9 | ||
|
446a89f35d | ||
|
1f99312c22 | ||
|
a6fa59d24c | ||
|
89b8f19288 | ||
|
8764339ac8 | ||
|
a8e0553e53 | ||
|
2af27cc81d | ||
|
784249a08b | ||
|
1fbfcd80cd | ||
|
d5eb9ae1a0 | ||
|
88faf93b3b | ||
|
a2e29149e2 | ||
|
8f8f2ad1fb | ||
|
a2aa3b9871 | ||
|
febd9f2741 | ||
|
b246f71e6e | ||
|
0cde9ecb21 | ||
|
964d6009b7 | ||
|
392390cde7 | ||
|
ba26a1faae | ||
|
c13e48638c | ||
|
77426c4235 | ||
|
ef6ad34a4e | ||
|
e67d571971 | ||
|
d63fb02026 | ||
|
d5480e32b4 | ||
|
21aa646359 | ||
|
02be4ec445 | ||
|
dafff6a9a2 | ||
|
68d7c22b7c | ||
|
3c81f71d15 | ||
|
0564de3ebf | ||
|
7030ed8650 | ||
|
364de89b30 | ||
|
fea10ac221 | ||
|
6249696efa | ||
|
ea5a9eef97 | ||
|
063669e8a6 | ||
|
9133c6b161 | ||
|
84dcf35362 | ||
|
0fdbcdec34 | ||
|
72b690365b | ||
|
e540628db1 | ||
|
018112d6b9 | ||
|
138c9a9856 | ||
|
aad4276f88 | ||
|
a9cebb85e9 | ||
|
f99a22499c | ||
|
c35d03b1ec | ||
|
16fb070e8b | ||
|
bf89ee24f5 | ||
|
cdcb70a4b1 | ||
|
697ad77f5f | ||
|
940777d9e5 | ||
|
73d76010bc | ||
|
75de6d33a0 | ||
|
9d2c3ed244 | ||
|
bddc21ec08 | ||
|
e24eae5a22 | ||
|
d0504fef91 | ||
|
ef3ecde553 | ||
|
200e174b3f | ||
|
4b5c19676d | ||
|
c0ba230fa5 | ||
|
736dc71eec | ||
|
61f56b2f84 | ||
|
915253972d | ||
|
8cffe8a5be | ||
|
7ad549b0bb | ||
|
323eb92f2e | ||
|
4f8dcb0cd0 | ||
|
0042590aa6 | ||
|
5e822cec8d | ||
|
3660b8f683 | ||
|
f90b83706b | ||
|
6d30fe1f41 | ||
|
ac9af46bd6 | ||
|
40bc88586e | ||
|
621321c498 | ||
|
1282b2ca48 | ||
|
5d77eb61a5 | ||
|
5c8c724b58 | ||
|
3a00ff104a | ||
|
39da88d3d3 | ||
|
e5ee4631c7 | ||
|
d4dc8fba44 | ||
|
94515efbe3 | ||
|
3d6b1bbd59 | ||
|
19d7eb1c7c | ||
|
e027829103 | ||
|
3d42301f24 | ||
|
70a54b632c | ||
|
04c4a4590d |
692 changed files with 10277 additions and 6184 deletions
|
@ -0,0 +1,229 @@
|
||||||
|
using ABI.CCK.Components;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public partial class AvatarClone
|
||||||
|
{
|
||||||
|
#region Exclusions
|
||||||
|
|
||||||
|
private FPRExclusion[] _exclusions;
|
||||||
|
|
||||||
|
private void AddExclusionToHeadIfNeeded()
|
||||||
|
{
|
||||||
|
if (!TryGetComponent(out Animator animator)
|
||||||
|
|| !animator.isHuman
|
||||||
|
|| !animator.avatar
|
||||||
|
|| !animator.avatar.isValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Transform head = animator.GetBoneTransform(HumanBodyBones.Head);
|
||||||
|
if (!head)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GameObject headGo = head.gameObject;
|
||||||
|
if (headGo.TryGetComponent(out FPRExclusion exclusion))
|
||||||
|
return;
|
||||||
|
|
||||||
|
exclusion = headGo.AddComponent<FPRExclusion>();
|
||||||
|
exclusion.target = head;
|
||||||
|
exclusion.isShown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeExclusions()
|
||||||
|
{
|
||||||
|
_exclusions = GetComponentsInChildren<FPRExclusion>(true);
|
||||||
|
var exclusionRoots = new Dictionary<Transform, AvatarCloneExclusion>(_exclusions.Length);
|
||||||
|
|
||||||
|
// **1. Precompute Exclusions**
|
||||||
|
foreach (FPRExclusion exclusion in _exclusions)
|
||||||
|
{
|
||||||
|
Transform target = exclusion.target ??= exclusion.transform;
|
||||||
|
if (exclusionRoots.ContainsKey(target) || !target.gameObject.scene.IsValid())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AvatarCloneExclusion behaviour = new AvatarCloneExclusion(this, target);
|
||||||
|
exclusion.behaviour = behaviour;
|
||||||
|
exclusionRoots.Add(target, behaviour);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process Exclusion Transforms
|
||||||
|
Renderer ourRenderer;
|
||||||
|
|
||||||
|
void ProcessTransformHierarchy(Transform current, Transform root, AvatarCloneExclusion behaviour)
|
||||||
|
{
|
||||||
|
if (exclusionRoots.ContainsKey(current) && current != root) return;
|
||||||
|
|
||||||
|
behaviour.affectedTransforms.Add(current);
|
||||||
|
if (current.TryGetComponent(out ourRenderer))
|
||||||
|
behaviour.affectedRenderers.Add(ourRenderer);
|
||||||
|
|
||||||
|
for (int i = 0; i < current.childCount; i++)
|
||||||
|
{
|
||||||
|
Transform child = current.GetChild(i);
|
||||||
|
if (!exclusionRoots.ContainsKey(child))
|
||||||
|
ProcessTransformHierarchy(child, root, behaviour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entry in exclusionRoots)
|
||||||
|
{
|
||||||
|
Transform rootTransform = entry.Key;
|
||||||
|
AvatarCloneExclusion behaviour = entry.Value;
|
||||||
|
ProcessTransformHierarchy(rootTransform, rootTransform, behaviour);
|
||||||
|
behaviour.affectedTransformSet = new HashSet<Transform>(behaviour.affectedTransforms);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------
|
||||||
|
// **OPTIMIZED EXCLUSION BONE MAPPING**
|
||||||
|
// ------------------------------
|
||||||
|
|
||||||
|
Dictionary<Transform, AvatarCloneExclusion>.ValueCollection exclusionBehaviours = exclusionRoots.Values;
|
||||||
|
int skinnedCount = _skinnedClones.Count;
|
||||||
|
|
||||||
|
// **2. Precompute Bone-to-Exclusion Mapping**
|
||||||
|
int estimatedBoneCount = skinnedCount * 20; // Estimated bones per skinned mesh
|
||||||
|
var boneToExclusion = new Dictionary<Transform, List<AvatarCloneExclusion>>(estimatedBoneCount);
|
||||||
|
|
||||||
|
foreach (AvatarCloneExclusion behaviour in exclusionBehaviours)
|
||||||
|
{
|
||||||
|
foreach (Transform bone in behaviour.affectedTransformSet)
|
||||||
|
{
|
||||||
|
if (!boneToExclusion.TryGetValue(bone, out var list))
|
||||||
|
{
|
||||||
|
list = new List<AvatarCloneExclusion>(2);
|
||||||
|
boneToExclusion[bone] = list;
|
||||||
|
}
|
||||||
|
list.Add(behaviour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **3. Process Skinned Mesh Renderers**
|
||||||
|
for (int s = 0; s < skinnedCount; s++)
|
||||||
|
{
|
||||||
|
SkinnedMeshRenderer source = _skinnedRenderers[s];
|
||||||
|
var bones = source.bones; // Cache bones array
|
||||||
|
|
||||||
|
SkinnedMeshRenderer smr = _skinnedClones[s];
|
||||||
|
int boneCount = bones.Length;
|
||||||
|
|
||||||
|
for (int i = 0; i < boneCount; i++)
|
||||||
|
{
|
||||||
|
Transform bone = bones[i];
|
||||||
|
|
||||||
|
// **Skip if the bone isn't mapped to exclusions**
|
||||||
|
if (!bone // Skip null bones
|
||||||
|
|| !boneToExclusion.TryGetValue(bone, out var behaviours))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// **Avoid redundant dictionary lookups**
|
||||||
|
for (int j = 0; j < behaviours.Count; j++)
|
||||||
|
{
|
||||||
|
AvatarCloneExclusion behaviour = behaviours[j];
|
||||||
|
|
||||||
|
if (!behaviour.skinnedToBoneIndex.TryGetValue(smr, out var indices))
|
||||||
|
{
|
||||||
|
indices = new List<int>(4);
|
||||||
|
behaviour.skinnedToBoneIndex[smr] = indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
indices.Add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplyInitialExclusionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyInitialExclusionState()
|
||||||
|
{
|
||||||
|
foreach (FPRExclusion exclusion in _exclusions)
|
||||||
|
{
|
||||||
|
exclusion._wasShown = exclusion.isShown;
|
||||||
|
if (!exclusion.isShown) exclusion.UpdateExclusions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleExclusionUpdate(AvatarCloneExclusion exclusion, bool isShown)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_UpdateExclusions.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// **1. Update Renderer Visibility**
|
||||||
|
foreach (Renderer renderer in exclusion.affectedRenderers)
|
||||||
|
{
|
||||||
|
if (renderer is SkinnedMeshRenderer skinned)
|
||||||
|
{
|
||||||
|
int index = _skinnedRenderers.IndexOf(skinned);
|
||||||
|
if (index >= 0) _skinnedClones[index].gameObject.SetActive(isShown);
|
||||||
|
}
|
||||||
|
else if (renderer is MeshRenderer mesh)
|
||||||
|
{
|
||||||
|
int index = _meshRenderers.IndexOf(mesh);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
if (Setting_CloneMeshRenderers)
|
||||||
|
{
|
||||||
|
_meshClones[index].gameObject.SetActive(isShown);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Other renderer (never cloned) - update shadow casting state
|
||||||
|
_sourceShouldBeHiddenFromFPR[index] = !isShown; // When hidden, use for shadows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (renderer)
|
||||||
|
{
|
||||||
|
int index = _otherRenderers.IndexOf(renderer);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
int shadowIndex = index + (Setting_CloneMeshRenderers ? _meshRenderers.Count : 0);
|
||||||
|
_sourceShouldBeHiddenFromFPR[shadowIndex] = !isShown; // When hidden, use for shadows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **2. Update Bone References in Skinned Mesh Renderers**
|
||||||
|
UpdateSkinnedMeshBones(exclusion, exclusion._shrinkBone, isShown);
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_UpdateExclusions.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSkinnedMeshBones(AvatarCloneExclusion exclusion, Transform shrinkBone, bool isShown)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_HandleBoneUpdates.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
foreach (var smrEntry in exclusion.skinnedToBoneIndex)
|
||||||
|
{
|
||||||
|
SkinnedMeshRenderer smr = smrEntry.Key;
|
||||||
|
var indices = smrEntry.Value;
|
||||||
|
bool needsUpdate = false;
|
||||||
|
|
||||||
|
var parentBones = smr.transform.parent.GetComponent<SkinnedMeshRenderer>().bones;
|
||||||
|
var cloneBones = smr.bones;
|
||||||
|
Array.Resize(ref cloneBones, parentBones.Length);
|
||||||
|
|
||||||
|
// Only modify our bones, other exclusions may have modified others
|
||||||
|
for (int i = 0; i < indices.Count; i++)
|
||||||
|
{
|
||||||
|
int index = indices[i];
|
||||||
|
if (!isShown) cloneBones[index] = shrinkBone;
|
||||||
|
else cloneBones[index] = parentBones[index];
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
|
if (needsUpdate) smr.bones = cloneBones;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_HandleBoneUpdates.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Exclusions
|
||||||
|
}
|
304
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs
Normal file
304
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Init.cs
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
using ABI_RC.Core.Player.ShadowClone;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public partial class AvatarClone
|
||||||
|
{
|
||||||
|
#region Initialization
|
||||||
|
|
||||||
|
private void InitializeCollections()
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_InitializeData.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialize source collections
|
||||||
|
_skinnedRenderers = new List<SkinnedMeshRenderer>();
|
||||||
|
_blendShapeWeights = new List<List<float>>();
|
||||||
|
|
||||||
|
_meshRenderers = new List<MeshRenderer>();
|
||||||
|
_meshFilters = new List<MeshFilter>();
|
||||||
|
|
||||||
|
_otherRenderers = new List<Renderer>();
|
||||||
|
|
||||||
|
// Initialize clone collections
|
||||||
|
_skinnedClones = new List<SkinnedMeshRenderer>();
|
||||||
|
_skinnedCloneMaterials = new List<Material[]>();
|
||||||
|
_skinnedCloneCullingMaterials = new List<Material[]>();
|
||||||
|
|
||||||
|
if (Setting_CloneMeshRenderers)
|
||||||
|
{
|
||||||
|
_meshClones = new List<MeshRenderer>();
|
||||||
|
_meshCloneFilters = new List<MeshFilter>();
|
||||||
|
_meshCloneMaterials = new List<Material[]>();
|
||||||
|
_meshCloneCullingMaterials = new List<Material[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize shared resources
|
||||||
|
_materialWorkingList = new List<Material>();
|
||||||
|
_propertyBlock = new MaterialPropertyBlock();
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_InitializeData.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CollectRenderers()
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_InitializeData.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var renderers = GetComponentsInChildren<Renderer>(true);
|
||||||
|
var currentIndex = 0;
|
||||||
|
var nonCloned = 0;
|
||||||
|
|
||||||
|
// Single pass: directly categorize renderers
|
||||||
|
foreach (Renderer renderer in renderers)
|
||||||
|
{
|
||||||
|
switch (renderer)
|
||||||
|
{
|
||||||
|
case SkinnedMeshRenderer skinned when skinned.sharedMesh != null:
|
||||||
|
AddSkinnedRenderer(skinned);
|
||||||
|
currentIndex++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MeshRenderer mesh:
|
||||||
|
MeshFilter filter = mesh.GetComponent<MeshFilter>();
|
||||||
|
if (filter != null && filter.sharedMesh != null)
|
||||||
|
{
|
||||||
|
if (Setting_CloneMeshRenderers)
|
||||||
|
{
|
||||||
|
AddMeshRenderer(mesh, filter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddMeshRenderer(mesh, filter);
|
||||||
|
nonCloned++;
|
||||||
|
}
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
AddOtherRenderer(renderer);
|
||||||
|
currentIndex++;
|
||||||
|
nonCloned++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_rendererActiveStates = new bool[currentIndex];
|
||||||
|
_originalShadowCastingMode = new ShadowCastingMode[currentIndex];
|
||||||
|
_sourceShouldBeHiddenFromFPR = new bool[nonCloned];
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_InitializeData.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddSkinnedRenderer(SkinnedMeshRenderer renderer)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_AddRenderer.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_skinnedRenderers.Add(renderer);
|
||||||
|
|
||||||
|
// Clone materials array for clone renderer
|
||||||
|
var materials = renderer.sharedMaterials;
|
||||||
|
var cloneMaterials = new Material[materials.Length];
|
||||||
|
for (int i = 0; i < materials.Length; i++) cloneMaterials[i] = materials[i];
|
||||||
|
_skinnedCloneMaterials.Add(cloneMaterials);
|
||||||
|
|
||||||
|
// Cache culling materials
|
||||||
|
var cullingMaterialArray = new Material[materials.Length];
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = ShadowCloneUtils.cullingMaterial;
|
||||||
|
#else
|
||||||
|
for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = cullingMaterial;
|
||||||
|
#endif
|
||||||
|
_skinnedCloneCullingMaterials.Add(cullingMaterialArray);
|
||||||
|
|
||||||
|
// Cache blend shape weights
|
||||||
|
var weights = new List<float>(renderer.sharedMesh.blendShapeCount);
|
||||||
|
for (int i = 0; i < renderer.sharedMesh.blendShapeCount; i++) weights.Add(0f);
|
||||||
|
_blendShapeWeights.Add(weights);
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_AddRenderer.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddMeshRenderer(MeshRenderer renderer, MeshFilter filter)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_AddRenderer.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_meshRenderers.Add(renderer);
|
||||||
|
_meshFilters.Add(filter);
|
||||||
|
|
||||||
|
if (!Setting_CloneMeshRenderers) return;
|
||||||
|
|
||||||
|
// Clone materials array for clone renderer
|
||||||
|
var materials = renderer.sharedMaterials;
|
||||||
|
var cloneMaterials = new Material[materials.Length];
|
||||||
|
for (int i = 0; i < materials.Length; i++) cloneMaterials[i] = materials[i];
|
||||||
|
_meshCloneMaterials.Add(cloneMaterials);
|
||||||
|
|
||||||
|
// Cache culling materials
|
||||||
|
var cullingMaterialArray = new Material[materials.Length];
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = ShadowCloneUtils.cullingMaterial;
|
||||||
|
#else
|
||||||
|
for (int i = 0; i < materials.Length; i++) cullingMaterialArray[i] = cullingMaterial;
|
||||||
|
#endif
|
||||||
|
_meshCloneCullingMaterials.Add(cullingMaterialArray);
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_AddRenderer.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddOtherRenderer(Renderer renderer)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_AddRenderer.Begin();
|
||||||
|
#endif
|
||||||
|
_otherRenderers.Add(renderer);
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_AddRenderer.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateClones()
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_InitializeData.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Always create skinned mesh clones
|
||||||
|
int skinnedCount = _skinnedRenderers.Count;
|
||||||
|
for (int i = 0; i < skinnedCount; i++)
|
||||||
|
{
|
||||||
|
CreateSkinnedClone(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally create mesh clones
|
||||||
|
if (Setting_CloneMeshRenderers)
|
||||||
|
{
|
||||||
|
int meshCount = _meshRenderers.Count;
|
||||||
|
for (int i = 0; i < meshCount; i++)
|
||||||
|
{
|
||||||
|
CreateMeshClone(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_InitializeData.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSkinnedClone(int index)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CreateClone.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SkinnedMeshRenderer source = _skinnedRenderers[index];
|
||||||
|
|
||||||
|
GameObject clone = new(source.name + "_Clone")
|
||||||
|
{
|
||||||
|
layer = CLONE_LAYER
|
||||||
|
};
|
||||||
|
|
||||||
|
clone.transform.SetParent(source.transform, false);
|
||||||
|
|
||||||
|
SkinnedMeshRenderer cloneRenderer = clone.AddComponent<SkinnedMeshRenderer>();
|
||||||
|
|
||||||
|
// Basic setup
|
||||||
|
cloneRenderer.sharedMaterials = _skinnedCloneMaterials[index];
|
||||||
|
cloneRenderer.shadowCastingMode = ShadowCastingMode.Off;
|
||||||
|
cloneRenderer.probeAnchor = source.probeAnchor;
|
||||||
|
cloneRenderer.sharedMesh = source.sharedMesh;
|
||||||
|
cloneRenderer.rootBone = source.rootBone;
|
||||||
|
cloneRenderer.bones = source.bones;
|
||||||
|
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
cloneRenderer.localBounds = new Bounds(source.localBounds.center, source.localBounds.size * 2f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Quality settings
|
||||||
|
cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
|
||||||
|
cloneRenderer.allowOcclusionWhenDynamic = false;
|
||||||
|
cloneRenderer.updateWhenOffscreen = false;
|
||||||
|
cloneRenderer.skinnedMotionVectors = false;
|
||||||
|
cloneRenderer.forceMatrixRecalculationPerRender = false;
|
||||||
|
cloneRenderer.quality = SkinQuality.Bone4;
|
||||||
|
|
||||||
|
source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
|
||||||
|
source.allowOcclusionWhenDynamic = false;
|
||||||
|
source.updateWhenOffscreen = false;
|
||||||
|
source.skinnedMotionVectors = false;
|
||||||
|
source.forceMatrixRecalculationPerRender = false;
|
||||||
|
source.quality = SkinQuality.Bone4;
|
||||||
|
|
||||||
|
// Add to clone list
|
||||||
|
_skinnedClones.Add(cloneRenderer);
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CreateClone.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateMeshClone(int index)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CreateClone.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MeshRenderer source = _meshRenderers[index];
|
||||||
|
MeshFilter sourceFilter = _meshFilters[index];
|
||||||
|
|
||||||
|
GameObject clone = new(source.name + "_Clone")
|
||||||
|
{
|
||||||
|
layer = CLONE_LAYER
|
||||||
|
};
|
||||||
|
|
||||||
|
clone.transform.SetParent(source.transform, false);
|
||||||
|
|
||||||
|
MeshRenderer cloneRenderer = clone.AddComponent<MeshRenderer>();
|
||||||
|
MeshFilter cloneFilter = clone.AddComponent<MeshFilter>();
|
||||||
|
|
||||||
|
// Basic setup
|
||||||
|
cloneRenderer.sharedMaterials = _meshCloneMaterials[index];
|
||||||
|
cloneRenderer.shadowCastingMode = ShadowCastingMode.Off;
|
||||||
|
cloneRenderer.probeAnchor = source.probeAnchor;
|
||||||
|
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
cloneRenderer.localBounds = new Bounds(source.localBounds.center, source.localBounds.size * 2f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cloneFilter.sharedMesh = sourceFilter.sharedMesh;
|
||||||
|
|
||||||
|
// Quality settings
|
||||||
|
cloneRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
|
||||||
|
cloneRenderer.allowOcclusionWhenDynamic = false;
|
||||||
|
|
||||||
|
source.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
|
||||||
|
source.allowOcclusionWhenDynamic = false;
|
||||||
|
|
||||||
|
// Add to clone lists
|
||||||
|
_meshClones.Add(cloneRenderer);
|
||||||
|
_meshCloneFilters.Add(cloneFilter);
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CreateClone.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Initialization
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public partial class AvatarClone
|
||||||
|
{
|
||||||
|
#region Render State Management
|
||||||
|
|
||||||
|
private void MyOnPreCull(Camera cam)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
// Scene & Preview cameras are not needed
|
||||||
|
if (cam.cameraType != CameraType.Game)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_PreCullUpdate.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool isOurUiCamera = IsUIInternalCamera(cam);
|
||||||
|
bool rendersOurPlayerLayer = CameraRendersPlayerLocalLayer(cam);
|
||||||
|
bool rendersOurCloneLayer = CameraRendersPlayerCloneLayer(cam);
|
||||||
|
|
||||||
|
bool rendersBothPlayerLayers = rendersOurPlayerLayer && rendersOurCloneLayer;
|
||||||
|
|
||||||
|
// Handle shadow casting when camera renders both layers
|
||||||
|
if (!_sourcesSetForShadowCasting
|
||||||
|
&& rendersBothPlayerLayers)
|
||||||
|
{
|
||||||
|
ConfigureSourceShadowCasting(true);
|
||||||
|
_sourcesSetForShadowCasting = true;
|
||||||
|
}
|
||||||
|
else if (_sourcesSetForShadowCasting && !rendersBothPlayerLayers)
|
||||||
|
{
|
||||||
|
ConfigureSourceShadowCasting(false);
|
||||||
|
_sourcesSetForShadowCasting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle UI culling for clone layer
|
||||||
|
if (!_clonesSetForUiCulling
|
||||||
|
&& isOurUiCamera && rendersOurCloneLayer)
|
||||||
|
{
|
||||||
|
ConfigureCloneUICulling(true);
|
||||||
|
_clonesSetForUiCulling = true;
|
||||||
|
}
|
||||||
|
else if (_clonesSetForUiCulling)
|
||||||
|
{
|
||||||
|
ConfigureCloneUICulling(false);
|
||||||
|
_clonesSetForUiCulling = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_PreCullUpdate.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigureSourceShadowCasting(bool setSourcesToShadowCast)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_ConfigureShadowCasting.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int currentIndex = 0;
|
||||||
|
int shadowArrayIndex = 0;
|
||||||
|
|
||||||
|
// Handle skinned mesh renderers (always have clones)
|
||||||
|
int skinnedCount = _skinnedRenderers.Count;
|
||||||
|
for (int i = 0; i < skinnedCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex]) continue;
|
||||||
|
|
||||||
|
SkinnedMeshRenderer source = _skinnedRenderers[i];
|
||||||
|
|
||||||
|
if (setSourcesToShadowCast)
|
||||||
|
{
|
||||||
|
ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode;
|
||||||
|
if (originalMode == ShadowCastingMode.Off)
|
||||||
|
source.forceRenderingOff = true;
|
||||||
|
else
|
||||||
|
source.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.shadowCastingMode = _originalShadowCastingMode[currentIndex];
|
||||||
|
source.forceRenderingOff = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle mesh renderers based on clone setting
|
||||||
|
if (Setting_CloneMeshRenderers)
|
||||||
|
{
|
||||||
|
int meshCount = _meshRenderers.Count;
|
||||||
|
for (int i = 0; i < meshCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex]) continue;
|
||||||
|
|
||||||
|
MeshRenderer source = _meshRenderers[i];
|
||||||
|
|
||||||
|
if (setSourcesToShadowCast)
|
||||||
|
{
|
||||||
|
ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode;
|
||||||
|
if (originalMode == ShadowCastingMode.Off)
|
||||||
|
source.forceRenderingOff = true;
|
||||||
|
else
|
||||||
|
source.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.shadowCastingMode = _originalShadowCastingMode[currentIndex];
|
||||||
|
source.forceRenderingOff = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// When not cloned, mesh renderers use the shadow casting array
|
||||||
|
int meshCount = _meshRenderers.Count;
|
||||||
|
for (int i = 0; i < meshCount; i++, shadowArrayIndex++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex]) continue;
|
||||||
|
if (!_sourceShouldBeHiddenFromFPR[shadowArrayIndex]) continue;
|
||||||
|
|
||||||
|
MeshRenderer source = _meshRenderers[i];
|
||||||
|
|
||||||
|
if (setSourcesToShadowCast)
|
||||||
|
{
|
||||||
|
ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode;
|
||||||
|
if (originalMode == ShadowCastingMode.Off)
|
||||||
|
source.forceRenderingOff = true;
|
||||||
|
else
|
||||||
|
source.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.shadowCastingMode = _originalShadowCastingMode[currentIndex];
|
||||||
|
source.forceRenderingOff = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle other renderers (never cloned)
|
||||||
|
int otherCount = _otherRenderers.Count;
|
||||||
|
for (int i = 0; i < otherCount; i++, shadowArrayIndex++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex]) continue;
|
||||||
|
if (!_sourceShouldBeHiddenFromFPR[shadowArrayIndex]) continue;
|
||||||
|
|
||||||
|
Renderer source = _otherRenderers[i];
|
||||||
|
|
||||||
|
if (setSourcesToShadowCast)
|
||||||
|
{
|
||||||
|
ShadowCastingMode originalMode = _originalShadowCastingMode[currentIndex] = source.shadowCastingMode;
|
||||||
|
if (originalMode == ShadowCastingMode.Off)
|
||||||
|
source.forceRenderingOff = true;
|
||||||
|
else
|
||||||
|
source.shadowCastingMode = ShadowCastingMode.ShadowsOnly;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.shadowCastingMode = _originalShadowCastingMode[currentIndex];
|
||||||
|
source.forceRenderingOff = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_ConfigureShadowCasting.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigureCloneUICulling(bool enableCulling)
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_ConfigureUICulling.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set the materials to our culling materials
|
||||||
|
int currentIndex = 0;
|
||||||
|
|
||||||
|
int skinnedCount = _skinnedRenderers.Count;
|
||||||
|
for (int i = 0; i < skinnedCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_skinnedClones[i].sharedMaterials = enableCulling ?
|
||||||
|
_skinnedCloneCullingMaterials[i] :
|
||||||
|
_skinnedCloneMaterials[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Setting_CloneMeshRenderers)
|
||||||
|
{
|
||||||
|
int meshCount = _meshRenderers.Count;
|
||||||
|
for (int i = 0; i < meshCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_meshClones[i].sharedMaterials = enableCulling ?
|
||||||
|
_meshCloneCullingMaterials[i] :
|
||||||
|
_meshCloneMaterials[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_ConfigureUICulling.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Render State Management
|
||||||
|
}
|
156
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs
Normal file
156
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.StateSync.cs
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public partial class AvatarClone
|
||||||
|
{
|
||||||
|
#region State Syncing
|
||||||
|
|
||||||
|
private void SyncEnabledState()
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CopyEnabledState.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int currentIndex = 0;
|
||||||
|
|
||||||
|
// Update skinned mesh renderers
|
||||||
|
int skinnedCount = _skinnedRenderers.Count;
|
||||||
|
for (int i = 0; i < skinnedCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
SkinnedMeshRenderer source = _skinnedRenderers[i];
|
||||||
|
_skinnedClones[i].enabled = _rendererActiveStates[currentIndex] = IsRendererActive(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update mesh renderers
|
||||||
|
int meshCount = _meshRenderers.Count;
|
||||||
|
for (int i = 0; i < meshCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
MeshRenderer source = _meshRenderers[i];
|
||||||
|
if (Setting_CloneMeshRenderers) _meshClones[i].enabled = _rendererActiveStates[currentIndex] = IsRendererActive(source);
|
||||||
|
else _rendererActiveStates[currentIndex] = IsRendererActive(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update other renderers
|
||||||
|
int otherCount = _otherRenderers.Count;
|
||||||
|
for (int i = 0; i < otherCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
Renderer source = _otherRenderers[i];
|
||||||
|
_rendererActiveStates[currentIndex] = IsRendererActive(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CopyEnabledState.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncMaterials()
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CopyMaterials.Begin();
|
||||||
|
#endif
|
||||||
|
int currentIndex = 0;
|
||||||
|
|
||||||
|
// Sync skinned mesh materials
|
||||||
|
int skinnedCount = _skinnedRenderers.Count;
|
||||||
|
for (int i = 0; i < skinnedCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CopyMaterialsAndProperties(
|
||||||
|
_skinnedRenderers[i],
|
||||||
|
_skinnedClones[i],
|
||||||
|
_propertyBlock,
|
||||||
|
_materialWorkingList,
|
||||||
|
_skinnedCloneMaterials[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync mesh materials if enabled
|
||||||
|
if (Setting_CloneMeshRenderers)
|
||||||
|
{
|
||||||
|
int meshCount = _meshRenderers.Count;
|
||||||
|
for (int i = 0; i < meshCount; i++, currentIndex++)
|
||||||
|
{
|
||||||
|
if (!_rendererActiveStates[currentIndex])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CopyMaterialsAndProperties(
|
||||||
|
_meshRenderers[i],
|
||||||
|
_meshClones[i],
|
||||||
|
_propertyBlock,
|
||||||
|
_materialWorkingList,
|
||||||
|
_meshCloneMaterials[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CopyMaterials.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncBlendShapes()
|
||||||
|
{
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CopyBlendShapes.Begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int skinnedCount = _skinnedRenderers.Count;
|
||||||
|
for (int i = 0; i < skinnedCount; i++)
|
||||||
|
{
|
||||||
|
SkinnedMeshRenderer source = _skinnedRenderers[i];
|
||||||
|
if (!_rendererActiveStates[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CopyBlendShapes(
|
||||||
|
source,
|
||||||
|
_skinnedClones[i],
|
||||||
|
_blendShapeWeights[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
s_CopyBlendShapes.End();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyMaterialsAndProperties(
|
||||||
|
Renderer source,
|
||||||
|
Renderer clone,
|
||||||
|
MaterialPropertyBlock propertyBlock,
|
||||||
|
List<Material> workingList,
|
||||||
|
Material[] cloneMaterials)
|
||||||
|
{
|
||||||
|
source.GetSharedMaterials(workingList);
|
||||||
|
|
||||||
|
int matCount = workingList.Count;
|
||||||
|
bool hasChanged = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < matCount; i++)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(workingList[i], cloneMaterials[i])) continue;
|
||||||
|
cloneMaterials[i] = workingList[i];
|
||||||
|
hasChanged = true;
|
||||||
|
}
|
||||||
|
if (hasChanged) clone.sharedMaterials = cloneMaterials;
|
||||||
|
|
||||||
|
source.GetPropertyBlock(propertyBlock);
|
||||||
|
clone.SetPropertyBlock(propertyBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyBlendShapes(
|
||||||
|
SkinnedMeshRenderer source,
|
||||||
|
SkinnedMeshRenderer clone,
|
||||||
|
List<float> weights)
|
||||||
|
{
|
||||||
|
int weightCount = weights.Count;
|
||||||
|
for (int i = 0; i < weightCount; i++)
|
||||||
|
{
|
||||||
|
float weight = source.GetBlendShapeWeight(i);
|
||||||
|
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||||
|
if (weight == weights[i]) continue; // Halves the work
|
||||||
|
clone.SetBlendShapeWeight(i, weights[i] = weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion State Syncing
|
||||||
|
}
|
81
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs
Normal file
81
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.Util.cs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
using ABI_RC.Core.Player;
|
||||||
|
using MagicaCloth;
|
||||||
|
using MagicaCloth2;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public partial class AvatarClone
|
||||||
|
{
|
||||||
|
#region Utilities
|
||||||
|
|
||||||
|
private static bool IsRendererActive(Renderer renderer)
|
||||||
|
=> renderer && renderer.enabled && renderer.gameObject.activeInHierarchy;
|
||||||
|
|
||||||
|
private static bool CameraRendersPlayerLocalLayer(Camera cam)
|
||||||
|
=> (cam.cullingMask & (1 << LOCAL_LAYER)) != 0;
|
||||||
|
|
||||||
|
private static bool CameraRendersPlayerCloneLayer(Camera cam)
|
||||||
|
=> (cam.cullingMask & (1 << CLONE_LAYER)) != 0;
|
||||||
|
|
||||||
|
private static bool IsUIInternalCamera(Camera cam)
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
=> cam == PlayerSetup.Instance.activeUiCam;
|
||||||
|
#else
|
||||||
|
=> cam.gameObject.layer == 15;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endregion Utilities
|
||||||
|
|
||||||
|
#region Magica Cloth Support
|
||||||
|
|
||||||
|
private void SetupMagicaClothSupport()
|
||||||
|
{
|
||||||
|
var magicaCloths1 = GetComponentsInChildren<BaseCloth>(true);
|
||||||
|
foreach (BaseCloth magicaCloth1 in magicaCloths1)
|
||||||
|
magicaCloth1.SetCullingMode(PhysicsTeam.TeamCullingMode.Off);
|
||||||
|
|
||||||
|
var magicaCloths2 = base.GetComponentsInChildren<MagicaCloth2.MagicaCloth>(true);
|
||||||
|
foreach (MagicaCloth2.MagicaCloth magicaCloth2 in magicaCloths2)
|
||||||
|
magicaCloth2.serializeData.cullingSettings.cameraCullingMode = CullingSettings.CameraCullingMode.AnimatorLinkage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnMagicaClothMeshSwapped(Renderer render, Mesh newMesh)
|
||||||
|
{
|
||||||
|
switch (render)
|
||||||
|
{
|
||||||
|
case MeshRenderer mesh:
|
||||||
|
{
|
||||||
|
int index = _meshRenderers.IndexOf(mesh);
|
||||||
|
if (index != -1) _meshCloneFilters[index].sharedMesh = newMesh;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SkinnedMeshRenderer skinned:
|
||||||
|
{
|
||||||
|
int index = _skinnedRenderers.IndexOf(skinned);
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
// Copy the mesh
|
||||||
|
_skinnedClones[index].sharedMesh = newMesh;
|
||||||
|
|
||||||
|
// Copy appended bones if count is different
|
||||||
|
var cloneBones = _skinnedClones[index].bones; // alloc
|
||||||
|
var sourceBones = skinned.bones; // alloc
|
||||||
|
|
||||||
|
int cloneBoneCount = cloneBones.Length;
|
||||||
|
int sourceBoneCount = sourceBones.Length;
|
||||||
|
if (cloneBoneCount != sourceBoneCount)
|
||||||
|
{
|
||||||
|
// Copy the new bones only
|
||||||
|
Array.Resize(ref cloneBones, sourceBoneCount);
|
||||||
|
for (int i = cloneBoneCount; i < sourceBoneCount; i++) cloneBones[i] = sourceBones[i];
|
||||||
|
_skinnedClones[index].bones = cloneBones;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Magica Cloth Support
|
||||||
|
}
|
147
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.cs
Normal file
147
.Deprecated/AvatarCloneTest/AvatarClone/AvatarClone.cs
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
using NAK.AvatarCloneTest;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public partial class AvatarClone : MonoBehaviour
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const int LOCAL_LAYER = 8;
|
||||||
|
private const int CLONE_LAYER = 9;
|
||||||
|
|
||||||
|
#endregion Constants
|
||||||
|
|
||||||
|
#region Profiler Markers
|
||||||
|
|
||||||
|
#if ENABLE_PROFILER
|
||||||
|
private static readonly ProfilerMarker s_CopyEnabledState = new($"{nameof(AvatarClone)}.{nameof(SyncEnabledState)}");
|
||||||
|
private static readonly ProfilerMarker s_CopyMaterials = new($"{nameof(AvatarClone)}.{nameof(CopyMaterialsAndProperties)}");
|
||||||
|
private static readonly ProfilerMarker s_CopyBlendShapes = new($"{nameof(AvatarClone)}.{nameof(CopyBlendShapes)}");
|
||||||
|
private static readonly ProfilerMarker s_InitializeData = new($"{nameof(AvatarClone)}.Initialize");
|
||||||
|
private static readonly ProfilerMarker s_UpdateExclusions = new($"{nameof(AvatarClone)}.{nameof(HandleExclusionUpdate)}");
|
||||||
|
private static readonly ProfilerMarker s_CollectExclusionData = new($"{nameof(AvatarClone)}.{nameof(CollectExclusionData)}");
|
||||||
|
private static readonly ProfilerMarker s_HandleBoneUpdates = new($"{nameof(AvatarClone)}.{nameof(UpdateSkinnedMeshBones)}");
|
||||||
|
private static readonly ProfilerMarker s_PreCullUpdate = new($"{nameof(AvatarClone)}.{nameof(MyOnPreCull)}");
|
||||||
|
private static readonly ProfilerMarker s_ConfigureShadowCasting = new($"{nameof(AvatarClone)}.{nameof(ConfigureSourceShadowCasting)}");
|
||||||
|
private static readonly ProfilerMarker s_ConfigureUICulling = new($"{nameof(AvatarClone)}.{nameof(ConfigureCloneUICulling)}");
|
||||||
|
private static readonly ProfilerMarker s_AddRenderer = new($"{nameof(AvatarClone)}.AddRenderer");
|
||||||
|
private static readonly ProfilerMarker s_CreateClone = new($"{nameof(AvatarClone)}.CreateClone");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endregion Profiler Markers
|
||||||
|
|
||||||
|
#region Settings
|
||||||
|
|
||||||
|
public bool Setting_CloneMeshRenderers;
|
||||||
|
public bool Setting_CopyMaterials = true;
|
||||||
|
public bool Setting_CopyBlendShapes = true;
|
||||||
|
|
||||||
|
#endregion Settings
|
||||||
|
|
||||||
|
#region Source Collections - Cloned Renderers
|
||||||
|
|
||||||
|
// Skinned mesh renderers (always cloned)
|
||||||
|
private List<SkinnedMeshRenderer> _skinnedRenderers;
|
||||||
|
private List<List<float>> _blendShapeWeights;
|
||||||
|
|
||||||
|
// Mesh renderers (optionally cloned)
|
||||||
|
private List<MeshRenderer> _meshRenderers;
|
||||||
|
private List<MeshFilter> _meshFilters;
|
||||||
|
|
||||||
|
#endregion Source Collections - Cloned Renderers
|
||||||
|
|
||||||
|
#region Source Collections - Non-Cloned Renderers
|
||||||
|
|
||||||
|
// All other renderers (never cloned)
|
||||||
|
private List<Renderer> _otherRenderers;
|
||||||
|
|
||||||
|
// True if source renderer should hide. False if source renderer should show.
|
||||||
|
// Only used for non-cloned renderers (MeshRenderers and other Renderers).
|
||||||
|
private bool[] _sourceShouldBeHiddenFromFPR;
|
||||||
|
// Three states: On, ShadowsOnly, Off
|
||||||
|
private ShadowCastingMode[] _originalShadowCastingMode;
|
||||||
|
|
||||||
|
#endregion Source Collections - Non-Cloned Renderers
|
||||||
|
|
||||||
|
#region Clone Collections
|
||||||
|
|
||||||
|
// Skinned mesh clones
|
||||||
|
private List<SkinnedMeshRenderer> _skinnedClones;
|
||||||
|
private List<Material[]> _skinnedCloneMaterials;
|
||||||
|
private List<Material[]> _skinnedCloneCullingMaterials;
|
||||||
|
|
||||||
|
// Mesh clones (optional)
|
||||||
|
private List<MeshRenderer> _meshClones;
|
||||||
|
private List<MeshFilter> _meshCloneFilters;
|
||||||
|
private List<Material[]> _meshCloneMaterials;
|
||||||
|
private List<Material[]> _meshCloneCullingMaterials;
|
||||||
|
|
||||||
|
#endregion Clone Collections
|
||||||
|
|
||||||
|
#region Shared Resources
|
||||||
|
|
||||||
|
private List<Material> _materialWorkingList; // Used for GetSharedMaterials
|
||||||
|
private MaterialPropertyBlock _propertyBlock;
|
||||||
|
|
||||||
|
#endregion Shared Resources
|
||||||
|
|
||||||
|
#region State
|
||||||
|
|
||||||
|
private bool _sourcesSetForShadowCasting;
|
||||||
|
private bool _clonesSetForUiCulling;
|
||||||
|
private bool[] _rendererActiveStates;
|
||||||
|
|
||||||
|
#endregion State
|
||||||
|
|
||||||
|
#region Unity Events
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
Setting_CloneMeshRenderers = AvatarCloneTestMod.EntryCloneMeshRenderers.Value;
|
||||||
|
|
||||||
|
InitializeCollections();
|
||||||
|
CollectRenderers();
|
||||||
|
CreateClones();
|
||||||
|
AddExclusionToHeadIfNeeded();
|
||||||
|
InitializeExclusions();
|
||||||
|
SetupMagicaClothSupport();
|
||||||
|
|
||||||
|
// bool animatesClone = transform.Find("[ExplicitlyAnimatesVisualClones]") != null;
|
||||||
|
// Setting_CopyMaterials = !animatesClone;
|
||||||
|
// Setting_CopyBlendShapes = !animatesClone;
|
||||||
|
// Animator animator = GetComponent<Animator>();
|
||||||
|
// if (animator && animatesClone) animator.Rebind();
|
||||||
|
|
||||||
|
// Likely a Unity bug with where we can touch shadowCastingMode & forceRenderingOff
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
Camera.onPreCull += MyOnPreCull;
|
||||||
|
#else
|
||||||
|
Camera.onPreRender += MyOnPreCull;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LateUpdate()
|
||||||
|
{
|
||||||
|
SyncEnabledState();
|
||||||
|
|
||||||
|
if (Setting_CopyMaterials && AvatarCloneTestMod.EntryCopyMaterials.Value)
|
||||||
|
SyncMaterials();
|
||||||
|
|
||||||
|
if (Setting_CopyBlendShapes && AvatarCloneTestMod.EntryCopyBlendShapes.Value)
|
||||||
|
SyncBlendShapes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
// Likely a Unity bug with where we can touch shadowCastingMode & forceRenderingOff
|
||||||
|
#if !UNITY_EDITOR
|
||||||
|
Camera.onPreCull -= MyOnPreCull;
|
||||||
|
#else
|
||||||
|
Camera.onPreRender -= MyOnPreCull;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Unity Events
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using ABI.CCK.Components;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public class AvatarCloneExclusion : IExclusionBehaviour
|
||||||
|
{
|
||||||
|
public readonly Dictionary<SkinnedMeshRenderer, List<int>> skinnedToBoneIndex = new();
|
||||||
|
public readonly List<Transform> affectedTransforms = new();
|
||||||
|
public readonly List<Renderer> affectedRenderers = new();
|
||||||
|
public HashSet<Transform> affectedTransformSet = new();
|
||||||
|
|
||||||
|
private readonly AvatarClone _cloneSystem;
|
||||||
|
private readonly Transform _target;
|
||||||
|
internal Transform _shrinkBone;
|
||||||
|
|
||||||
|
public bool isImmuneToGlobalState { get; set; }
|
||||||
|
|
||||||
|
public AvatarCloneExclusion(AvatarClone cloneSystem, Transform target)
|
||||||
|
{
|
||||||
|
_cloneSystem = cloneSystem;
|
||||||
|
_target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateExclusions(bool isShown, bool shrinkToZero)
|
||||||
|
{
|
||||||
|
if (_shrinkBone == null)
|
||||||
|
{
|
||||||
|
// Create shrink bone parented directly to target
|
||||||
|
_shrinkBone = new GameObject($"{_target.name}_Shrink").transform;
|
||||||
|
_shrinkBone.SetParent(_target, false);
|
||||||
|
}
|
||||||
|
// Set scale based on shrink mode
|
||||||
|
_shrinkBone.localScale = shrinkToZero ? Vector3.zero : Vector3.positiveInfinity;
|
||||||
|
|
||||||
|
// Replace the bone references with the shrink bone for the indicies we modify
|
||||||
|
_cloneSystem.HandleExclusionUpdate(this, isShown);
|
||||||
|
}
|
||||||
|
}
|
9
.Deprecated/AvatarCloneTest/AvatarCloneTest.csproj
Normal file
9
.Deprecated/AvatarCloneTest/AvatarCloneTest.csproj
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>LocalCloneFix</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<DefineConstants>TRACE;TRACE;</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
81
.Deprecated/AvatarCloneTest/Main.cs
Normal file
81
.Deprecated/AvatarCloneTest/Main.cs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
using ABI_RC.Core;
|
||||||
|
using ABI_RC.Core.EventSystem;
|
||||||
|
using ABI_RC.Core.Savior;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public class AvatarCloneTestMod : MelonMod
|
||||||
|
{
|
||||||
|
#region Melon Preferences
|
||||||
|
|
||||||
|
private static readonly MelonPreferences_Category Category =
|
||||||
|
MelonPreferences.CreateCategory(nameof(AvatarCloneTest));
|
||||||
|
|
||||||
|
internal static readonly MelonPreferences_Entry<bool> EntryUseAvatarCloneTest =
|
||||||
|
Category.CreateEntry("use_avatar_clone_test", true,
|
||||||
|
"Use Avatar Clone", description: "Uses the Avatar Clone setup for the local avatar.");
|
||||||
|
|
||||||
|
internal static readonly MelonPreferences_Entry<bool> EntryCloneMeshRenderers =
|
||||||
|
Category.CreateEntry("clone_mesh_renderers", false,
|
||||||
|
"Clone Mesh Renderers", description: "Clones the mesh renderers from the original avatar to the clone.");
|
||||||
|
|
||||||
|
internal static readonly MelonPreferences_Entry<bool> EntryCopyBlendShapes =
|
||||||
|
Category.CreateEntry("copy_blend_shapes", true,
|
||||||
|
"Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone.");
|
||||||
|
|
||||||
|
internal static readonly MelonPreferences_Entry<bool> EntryCopyMaterials =
|
||||||
|
Category.CreateEntry("copy_materials", true,
|
||||||
|
"Copy Materials", description: "Copies the materials from the original avatar to the clone.");
|
||||||
|
|
||||||
|
#endregion Melon Preferences
|
||||||
|
|
||||||
|
#region Melon Events
|
||||||
|
|
||||||
|
public override void OnInitializeMelon()
|
||||||
|
{
|
||||||
|
ApplyPatches(typeof(Patches)); // slapped together a fix cause HarmonyInstance.Patch was null ref for no reason?
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnUpdate()
|
||||||
|
{
|
||||||
|
// press f1 to find all cameras that arent tagged main and set them tno not render CVRLayers.PlayerClone
|
||||||
|
if (Input.GetKeyDown(KeyCode.F1))
|
||||||
|
{
|
||||||
|
foreach (var camera in UnityEngine.Object.FindObjectsOfType<UnityEngine.Camera>())
|
||||||
|
{
|
||||||
|
if (camera.tag != "MainCamera")
|
||||||
|
{
|
||||||
|
camera.cullingMask &= ~(1 << CVRLayers.PlayerClone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if pressing ctrl + r, reload avatar
|
||||||
|
if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.R))
|
||||||
|
{
|
||||||
|
var player = MetaPort.Instance.currentAvatarGuid;
|
||||||
|
AssetManagement.Instance.LoadLocalAvatar(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Melon Events
|
||||||
|
|
||||||
|
#region Melon Mod Utilities
|
||||||
|
|
||||||
|
private void ApplyPatches(Type type)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HarmonyInstance.PatchAll(type);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LoggerInstance.Msg($"Failed while patching {type.Name}!");
|
||||||
|
LoggerInstance.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Melon Mod Utilities
|
||||||
|
}
|
22
.Deprecated/AvatarCloneTest/Patches.cs
Normal file
22
.Deprecated/AvatarCloneTest/Patches.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using ABI_RC.Core;
|
||||||
|
using ABI_RC.Core.Player;
|
||||||
|
using ABI_RC.Core.Player.TransformHider;
|
||||||
|
using ABI_RC.Core.Savior;
|
||||||
|
using ABI_RC.Systems.Camera;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
|
public static class Patches
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(TransformHiderUtils), nameof(TransformHiderUtils.SetupAvatar))]
|
||||||
|
private static bool OnSetupAvatar(GameObject avatar)
|
||||||
|
{
|
||||||
|
if (!AvatarCloneTestMod.EntryUseAvatarCloneTest.Value) return true;
|
||||||
|
avatar.AddComponent<AvatarClone>();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
.Deprecated/AvatarCloneTest/Properties/AssemblyInfo.cs
Normal file
32
.Deprecated/AvatarCloneTest/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using MelonLoader;
|
||||||
|
using NAK.AvatarCloneTest.Properties;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
[assembly: AssemblyVersion(AssemblyInfoParams.Version)]
|
||||||
|
[assembly: AssemblyFileVersion(AssemblyInfoParams.Version)]
|
||||||
|
[assembly: AssemblyInformationalVersion(AssemblyInfoParams.Version)]
|
||||||
|
[assembly: AssemblyTitle(nameof(NAK.AvatarCloneTest))]
|
||||||
|
[assembly: AssemblyCompany(AssemblyInfoParams.Author)]
|
||||||
|
[assembly: AssemblyProduct(nameof(NAK.AvatarCloneTest))]
|
||||||
|
|
||||||
|
[assembly: MelonInfo(
|
||||||
|
typeof(NAK.AvatarCloneTest.AvatarCloneTestMod),
|
||||||
|
nameof(NAK.AvatarCloneTest),
|
||||||
|
AssemblyInfoParams.Version,
|
||||||
|
AssemblyInfoParams.Author,
|
||||||
|
downloadLink: "https://github.com/NotAKidoS/NAK_CVR_Mods/tree/main/AvatarCloneTest"
|
||||||
|
)]
|
||||||
|
|
||||||
|
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||||
|
[assembly: MelonPlatform(MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||||
|
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||||
|
[assembly: MelonColor(255, 246, 25, 99)] // red-pink
|
||||||
|
[assembly: MelonAuthorColor(255, 158, 21, 32)] // red
|
||||||
|
[assembly: HarmonyDontPatchAll]
|
||||||
|
|
||||||
|
namespace NAK.AvatarCloneTest.Properties;
|
||||||
|
internal static class AssemblyInfoParams
|
||||||
|
{
|
||||||
|
public const string Version = "1.0.3";
|
||||||
|
public const string Author = "NotAKidoS";
|
||||||
|
}
|
|
@ -211,7 +211,7 @@ public class AvatarScaleManager : MonoBehaviour
|
||||||
public float GetHeight()
|
public float GetHeight()
|
||||||
{
|
{
|
||||||
if (_localAvatarScaler == null)
|
if (_localAvatarScaler == null)
|
||||||
return PlayerAvatarPoint.defaultAvatarHeight;
|
return PlayerAvatarPoint.DefaultAvatarHeight;
|
||||||
|
|
||||||
if (!_localAvatarScaler.IsForcingHeight())
|
if (!_localAvatarScaler.IsForcingHeight())
|
||||||
return PlayerSetup.Instance.GetAvatarHeight();
|
return PlayerSetup.Instance.GetAvatarHeight();
|
||||||
|
@ -222,7 +222,7 @@ public class AvatarScaleManager : MonoBehaviour
|
||||||
public float GetAnimationClipHeight()
|
public float GetAnimationClipHeight()
|
||||||
{
|
{
|
||||||
if (_localAvatarScaler == null)
|
if (_localAvatarScaler == null)
|
||||||
return PlayerAvatarPoint.defaultAvatarHeight;
|
return PlayerAvatarPoint.DefaultAvatarHeight;
|
||||||
|
|
||||||
if (!_localAvatarScaler.IsForcingHeight())
|
if (!_localAvatarScaler.IsForcingHeight())
|
||||||
return PlayerSetup.Instance.GetAvatarHeight();
|
return PlayerSetup.Instance.GetAvatarHeight();
|
|
@ -1,4 +1,5 @@
|
||||||
using ABI_RC.Core.Player;
|
using ABI_RC.Core;
|
||||||
|
using ABI_RC.Core.Player;
|
||||||
using ABI_RC.Core.UI;
|
using ABI_RC.Core.UI;
|
||||||
using NAK.AvatarScaleMod.AvatarScaling;
|
using NAK.AvatarScaleMod.AvatarScaling;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
@ -72,7 +73,7 @@ public class LocalScaler : BaseScaler
|
||||||
}
|
}
|
||||||
|
|
||||||
// animation scale changed, record it!
|
// animation scale changed, record it!
|
||||||
Vector3 scaleDifference = PlayerSetup.DivideVectors(localScale - _initialScale, _initialScale);
|
Vector3 scaleDifference = CVRTools.DivideVectors(localScale - _initialScale, _initialScale);
|
||||||
_animatedScaleFactor = scaleDifference.y;
|
_animatedScaleFactor = scaleDifference.y;
|
||||||
_animatedHeight = (_initialHeight * _animatedScaleFactor) + _initialHeight;
|
_animatedHeight = (_initialHeight * _animatedScaleFactor) + _initialHeight;
|
||||||
_animatedScale = localScale;
|
_animatedScale = localScale;
|
|
@ -3,8 +3,8 @@ using BTKUILib;
|
||||||
using BTKUILib.UIObjects;
|
using BTKUILib.UIObjects;
|
||||||
using NAK.AvatarScaleMod.AvatarScaling;
|
using NAK.AvatarScaleMod.AvatarScaling;
|
||||||
|
|
||||||
namespace NAK.AvatarScaleMod.Integrations
|
namespace NAK.AvatarScaleMod.Integrations;
|
||||||
{
|
|
||||||
public static partial class BtkUiAddon
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
private static Page _asmRootPage;
|
private static Page _asmRootPage;
|
||||||
|
@ -97,4 +97,3 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
using BTKUILib.UIObjects;
|
using BTKUILib.UIObjects;
|
||||||
|
|
||||||
namespace NAK.AvatarScaleMod.Integrations
|
namespace NAK.AvatarScaleMod.Integrations;
|
||||||
{
|
|
||||||
public static partial class BtkUiAddon
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
private static void Setup_AvatarScaleModCategory(Page page)
|
private static void Setup_AvatarScaleModCategory(Page page)
|
||||||
|
@ -14,4 +14,3 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistThroughRestart);
|
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistThroughRestart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
using BTKUILib.UIObjects;
|
using BTKUILib.UIObjects;
|
||||||
using BTKUILib.UIObjects.Components;
|
using BTKUILib.UIObjects.Components;
|
||||||
|
|
||||||
namespace NAK.AvatarScaleMod.Integrations
|
namespace NAK.AvatarScaleMod.Integrations;
|
||||||
{
|
|
||||||
public static partial class BtkUiAddon
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
private static void Setup_AvatarScaleToolCategory(Page page)
|
private static void Setup_AvatarScaleToolCategory(Page page)
|
||||||
|
@ -20,4 +20,3 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
using BTKUILib.UIObjects;
|
using BTKUILib.UIObjects;
|
||||||
|
|
||||||
namespace NAK.AvatarScaleMod.Integrations
|
namespace NAK.AvatarScaleMod.Integrations;
|
||||||
{
|
|
||||||
public static partial class BtkUiAddon
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
private static void Setup_DebugOptionsCategory(Page page)
|
private static void Setup_DebugOptionsCategory(Page page)
|
||||||
|
@ -13,4 +13,3 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
AddMelonToggle(ref debugCategory, ModSettings.Debug_ComponentSearchTime);
|
AddMelonToggle(ref debugCategory, ModSettings.Debug_ComponentSearchTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -4,8 +4,8 @@ using BTKUILib.UIObjects.Components;
|
||||||
using NAK.AvatarScaleMod.AvatarScaling;
|
using NAK.AvatarScaleMod.AvatarScaling;
|
||||||
using System.Collections.Generic; // Added for list support
|
using System.Collections.Generic; // Added for list support
|
||||||
|
|
||||||
namespace NAK.AvatarScaleMod.Integrations
|
namespace NAK.AvatarScaleMod.Integrations;
|
||||||
{
|
|
||||||
public static partial class BtkUiAddon
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
private static readonly List<QMUIElement> USM_QmUiElements = new();
|
private static readonly List<QMUIElement> USM_QmUiElements = new();
|
||||||
|
@ -72,4 +72,3 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -3,8 +3,8 @@ using BTKUILib.UIObjects;
|
||||||
using BTKUILib.UIObjects.Components;
|
using BTKUILib.UIObjects.Components;
|
||||||
using NAK.AvatarScaleMod.AvatarScaling;
|
using NAK.AvatarScaleMod.AvatarScaling;
|
||||||
|
|
||||||
namespace NAK.AvatarScaleMod.Integrations
|
namespace NAK.AvatarScaleMod.Integrations;
|
||||||
{
|
|
||||||
public static partial class BtkUiAddon
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
private static Button _playerHasModElement;
|
private static Button _playerHasModElement;
|
||||||
|
@ -62,4 +62,3 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using BTKUILib;
|
||||||
|
using BTKUILib.UIObjects;
|
||||||
|
using BTKUILib.UIObjects.Components;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NAK.AvatarScaleMod.Integrations;
|
||||||
|
|
||||||
|
public static partial class BtkUiAddon
|
||||||
|
{
|
||||||
|
#region Melon Preference Helpers
|
||||||
|
|
||||||
|
private static ToggleButton AddMelonToggle(ref Category category, MelonPreferences_Entry<bool> entry)
|
||||||
|
{
|
||||||
|
ToggleButton toggle = category.AddToggle(entry.DisplayName, entry.Description, entry.Value);
|
||||||
|
toggle.OnValueUpdated += b => entry.Value = b;
|
||||||
|
return toggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SliderFloat AddMelonSlider(ref Category category, MelonPreferences_Entry<float> entry, float min,
|
||||||
|
float max, int decimalPlaces = 2, bool allowReset = true)
|
||||||
|
{
|
||||||
|
SliderFloat slider = category.AddSlider(entry.DisplayName, entry.Description,
|
||||||
|
Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset);
|
||||||
|
slider.OnValueUpdated += f => entry.Value = f;
|
||||||
|
return slider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Button AddMelonStringInput(ref Category category, MelonPreferences_Entry<string> entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly)
|
||||||
|
{
|
||||||
|
Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle);
|
||||||
|
button.OnPress += () => QuickMenuAPI.OpenKeyboard(entry.Value, s => entry.Value = s);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Button AddMelonNumberInput(ref Category category, MelonPreferences_Entry<float> entry, string buttonIcon = "", ButtonStyle buttonStyle = ButtonStyle.TextOnly)
|
||||||
|
{
|
||||||
|
Button button = category.AddButton(entry.DisplayName, buttonIcon, entry.Description, buttonStyle);
|
||||||
|
button.OnPress += () => QuickMenuAPI.OpenNumberInput(entry.DisplayName, entry.Value, f => entry.Value = f);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private static SliderFloat AddMelonSlider(ref Page page, MelonPreferences_Entry<float> entry, float min, float max, int decimalPlaces = 2, bool allowReset = true)
|
||||||
|
// {
|
||||||
|
// SliderFloat slider = page.AddSlider(entry.DisplayName, entry.Description, Mathf.Clamp(entry.Value, min, max), min, max, decimalPlaces, entry.DefaultValue, allowReset);
|
||||||
|
// slider.OnValueUpdated += f => entry.Value = f;
|
||||||
|
// return slider;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper method to create a category that saves its collapsed state to a MelonPreferences entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="page"></param>
|
||||||
|
/// <param name="entry"></param>
|
||||||
|
/// <param name="showHeader"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static Category AddMelonCategory(ref Page page, MelonPreferences_Entry<bool> entry, bool showHeader = true)
|
||||||
|
{
|
||||||
|
Category category = page.AddCategory(entry.DisplayName, showHeader, true, entry.Value);
|
||||||
|
category.OnCollapse += b => entry.Value = b;
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Icon Utils
|
||||||
|
|
||||||
|
private static Stream GetIconStream(string iconName)
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
|
string assemblyName = assembly.GetName().Name;
|
||||||
|
return assembly.GetManifestResourceStream($"{assemblyName}.resources.{iconName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
|
@ -3,8 +3,8 @@ using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
// https://github.com/SDraw/ml_mods_cvr/blob/master/ml_amt/Scripts.cs
|
// https://github.com/SDraw/ml_mods_cvr/blob/master/ml_amt/Scripts.cs
|
||||||
namespace NAK.AvatarScaleMod
|
namespace NAK.AvatarScaleMod;
|
||||||
{
|
|
||||||
static class Scripts
|
static class Scripts
|
||||||
{
|
{
|
||||||
public static string GetEmbeddedScript(string p_name)
|
public static string GetEmbeddedScript(string p_name)
|
||||||
|
@ -24,4 +24,3 @@ namespace NAK.AvatarScaleMod
|
||||||
return l_result;
|
return l_result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue