mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-04 23:39:22 +00:00
Compare commits
37 commits
5e822cec8d
...
6249696efa
Author | SHA1 | Date | |
---|---|---|---|
|
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 |
645 changed files with 5459 additions and 3794 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
|
||||||
|
}
|
|
@ -5,9 +5,14 @@ namespace NAK.AvatarCloneTest;
|
||||||
|
|
||||||
public class AvatarCloneExclusion : IExclusionBehaviour
|
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 AvatarClone _cloneSystem;
|
||||||
private readonly Transform _target;
|
private readonly Transform _target;
|
||||||
private Transform _shrinkBone;
|
internal Transform _shrinkBone;
|
||||||
|
|
||||||
public bool isImmuneToGlobalState { get; set; }
|
public bool isImmuneToGlobalState { get; set; }
|
||||||
|
|
||||||
|
@ -19,20 +24,16 @@ public class AvatarCloneExclusion : IExclusionBehaviour
|
||||||
|
|
||||||
public void UpdateExclusions(bool isShown, bool shrinkToZero)
|
public void UpdateExclusions(bool isShown, bool shrinkToZero)
|
||||||
{
|
{
|
||||||
Debug.Log($"[AvatarClone2] Updating exclusion for {_target.name}: isShown={isShown}, shrinkToZero={shrinkToZero}");
|
|
||||||
|
|
||||||
if (_shrinkBone == null)
|
if (_shrinkBone == null)
|
||||||
{
|
{
|
||||||
// Create shrink bone parented directly to target
|
// Create shrink bone parented directly to target
|
||||||
_shrinkBone = new GameObject($"{_target.name}_Shrink").transform;
|
_shrinkBone = new GameObject($"{_target.name}_Shrink").transform;
|
||||||
_shrinkBone.SetParent(_target, false);
|
_shrinkBone.SetParent(_target, false);
|
||||||
Debug.Log($"[AvatarClone2] Created shrink bone for {_target.name}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set scale based on shrink mode
|
// Set scale based on shrink mode
|
||||||
_shrinkBone.localScale = shrinkToZero ? Vector3.zero : Vector3.positiveInfinity;
|
_shrinkBone.localScale = shrinkToZero ? Vector3.zero : Vector3.positiveInfinity;
|
||||||
|
|
||||||
// Let the clone system handle the update
|
// Replace the bone references with the shrink bone for the indicies we modify
|
||||||
_cloneSystem.HandleExclusionUpdate(_target, _shrinkBone, isShown);
|
_cloneSystem.HandleExclusionUpdate(this, isShown);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
using ABI_RC.Core;
|
using ABI_RC.Core;
|
||||||
|
using ABI_RC.Core.EventSystem;
|
||||||
|
using ABI_RC.Core.Savior;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
|
@ -15,17 +17,17 @@ public class AvatarCloneTestMod : MelonMod
|
||||||
Category.CreateEntry("use_avatar_clone_test", true,
|
Category.CreateEntry("use_avatar_clone_test", true,
|
||||||
"Use Avatar Clone", description: "Uses the Avatar Clone setup for the local avatar.");
|
"Use Avatar Clone", description: "Uses the Avatar Clone setup for the local avatar.");
|
||||||
|
|
||||||
// internal static readonly MelonPreferences_Entry<bool> EntryCopyBlendShapes =
|
internal static readonly MelonPreferences_Entry<bool> EntryCloneMeshRenderers =
|
||||||
// Category.CreateEntry("copy_blend_shapes", true,
|
Category.CreateEntry("clone_mesh_renderers", false,
|
||||||
// "Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone.");
|
"Clone Mesh Renderers", description: "Clones the mesh renderers from the original avatar to the clone.");
|
||||||
//
|
|
||||||
// internal static readonly MelonPreferences_Entry<bool> EntryCopyMaterials =
|
internal static readonly MelonPreferences_Entry<bool> EntryCopyBlendShapes =
|
||||||
// Category.CreateEntry("copy_materials", true,
|
Category.CreateEntry("copy_blend_shapes", true,
|
||||||
// "Copy Materials", description: "Copies the materials from the original avatar to the clone.");
|
"Copy Blend Shapes", description: "Copies the blend shapes from the original avatar to the clone.");
|
||||||
//
|
|
||||||
// internal static readonly MelonPreferences_Entry<bool> EntryCopyMeshes =
|
internal static readonly MelonPreferences_Entry<bool> EntryCopyMaterials =
|
||||||
// Category.CreateEntry("copy_meshes", true,
|
Category.CreateEntry("copy_materials", true,
|
||||||
// "Copy Meshes", description: "Copies the meshes from the original avatar to the clone.");
|
"Copy Materials", description: "Copies the materials from the original avatar to the clone.");
|
||||||
|
|
||||||
#endregion Melon Preferences
|
#endregion Melon Preferences
|
||||||
|
|
||||||
|
@ -49,6 +51,13 @@ public class AvatarCloneTestMod : MelonMod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
#endregion Melon Events
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,6 @@ using System.Reflection;
|
||||||
namespace NAK.AvatarCloneTest.Properties;
|
namespace NAK.AvatarCloneTest.Properties;
|
||||||
internal static class AssemblyInfoParams
|
internal static class AssemblyInfoParams
|
||||||
{
|
{
|
||||||
public const string Version = "1.0.0";
|
public const string Version = "1.0.3";
|
||||||
public const string Author = "NotAKidoS";
|
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,32 +3,32 @@ 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
|
|
||||||
{
|
|
||||||
private static Page _asmRootPage;
|
|
||||||
private static string _rootPageElementID;
|
|
||||||
|
|
||||||
public static void Initialize()
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
|
private static Page _asmRootPage;
|
||||||
|
private static string _rootPageElementID;
|
||||||
|
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
Prepare_Icons();
|
Prepare_Icons();
|
||||||
Setup_AvatarScaleModTab();
|
Setup_AvatarScaleModTab();
|
||||||
Setup_PlayerSelectPage();
|
Setup_PlayerSelectPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Initialization
|
#region Initialization
|
||||||
|
|
||||||
private static void Prepare_Icons()
|
private static void Prepare_Icons()
|
||||||
{
|
{
|
||||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightConfig",
|
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightConfig",
|
||||||
GetIconStream("ASM_Icon_AvatarHeightConfig.png"));
|
GetIconStream("ASM_Icon_AvatarHeightConfig.png"));
|
||||||
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightCopy",
|
QuickMenuAPI.PrepareIcon(ModSettings.ModName, "ASM_Icon_AvatarHeightCopy",
|
||||||
GetIconStream("ASM_Icon_AvatarHeightCopy.png"));
|
GetIconStream("ASM_Icon_AvatarHeightCopy.png"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Setup_AvatarScaleModTab()
|
private static void Setup_AvatarScaleModTab()
|
||||||
{
|
{
|
||||||
_asmRootPage = new Page(ModSettings.ModName, ModSettings.ASM_SettingsCategory, true, "ASM_Icon_AvatarHeightConfig")
|
_asmRootPage = new Page(ModSettings.ModName, ModSettings.ASM_SettingsCategory, true, "ASM_Icon_AvatarHeightConfig")
|
||||||
{
|
{
|
||||||
MenuTitle = ModSettings.ASM_SettingsCategory,
|
MenuTitle = ModSettings.ASM_SettingsCategory,
|
||||||
|
@ -54,18 +54,18 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
Setup_DebugOptionsCategory(_asmRootPage);
|
Setup_DebugOptionsCategory(_asmRootPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Player Count Display
|
#region Player Count Display
|
||||||
|
|
||||||
private static void OnWorldLeave()
|
private static void OnWorldLeave()
|
||||||
=> UpdatePlayerCountDisplay();
|
=> UpdatePlayerCountDisplay();
|
||||||
|
|
||||||
private static void OnUserJoinLeave(CVRPlayerEntity _)
|
private static void OnUserJoinLeave(CVRPlayerEntity _)
|
||||||
=> UpdatePlayerCountDisplay();
|
=> UpdatePlayerCountDisplay();
|
||||||
|
|
||||||
private static void UpdatePlayerCountDisplay()
|
private static void UpdatePlayerCountDisplay()
|
||||||
{
|
{
|
||||||
if (_asmRootPage == null)
|
if (_asmRootPage == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -74,14 +74,14 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
_asmRootPage.MenuSubtitle = $"Everything Avatar Scaling! :: ({modUserCount}/{playerCount} players using ASM)";
|
_asmRootPage.MenuSubtitle = $"Everything Avatar Scaling! :: ({modUserCount}/{playerCount} players using ASM)";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Double-Click Reset Height
|
#region Double-Click Reset Height
|
||||||
|
|
||||||
private static DateTime lastTime = DateTime.Now;
|
private static DateTime lastTime = DateTime.Now;
|
||||||
|
|
||||||
private static void OnTabChange(string newTab, string previousTab)
|
private static void OnTabChange(string newTab, string previousTab)
|
||||||
{
|
{
|
||||||
if (newTab == _rootPageElementID)
|
if (newTab == _rootPageElementID)
|
||||||
{
|
{
|
||||||
UpdatePlayerCountDisplay();
|
UpdatePlayerCountDisplay();
|
||||||
|
@ -95,6 +95,5 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
lastTime = DateTime.Now;
|
lastTime = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
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)
|
|
||||||
{
|
|
||||||
Category avScaleModCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_ASM_SettingsCategory);
|
Category avScaleModCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_ASM_SettingsCategory);
|
||||||
|
|
||||||
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryScaleGestureEnabled);
|
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryScaleGestureEnabled);
|
||||||
|
@ -13,5 +13,4 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistentHeight);
|
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistentHeight);
|
||||||
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistThroughRestart);
|
AddMelonToggle(ref avScaleModCategory, ModSettings.EntryPersistThroughRestart);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
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)
|
|
||||||
{
|
|
||||||
Category avScaleToolCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_AST_SettingsCategory);
|
Category avScaleToolCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_AST_SettingsCategory);
|
||||||
|
|
||||||
AddMelonStringInput(ref avScaleToolCategory, ModSettings.EntryASTScaleParameter, "icon");
|
AddMelonStringInput(ref avScaleToolCategory, ModSettings.EntryASTScaleParameter, "icon");
|
||||||
|
@ -19,5 +19,4 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
ModSettings.EntryASTMaxHeight.ResetToDefault();
|
ModSettings.EntryASTMaxHeight.ResetToDefault();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,16 +1,15 @@
|
||||||
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)
|
|
||||||
{
|
|
||||||
Category debugCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_DEBUG_SettingsCategory);
|
Category debugCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_DEBUG_SettingsCategory);
|
||||||
|
|
||||||
AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkInbound);
|
AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkInbound);
|
||||||
AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkOutbound);
|
AddMelonToggle(ref debugCategory, ModSettings.Debug_NetworkOutbound);
|
||||||
AddMelonToggle(ref debugCategory, ModSettings.Debug_ComponentSearchTime);
|
AddMelonToggle(ref debugCategory, ModSettings.Debug_ComponentSearchTime);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -4,14 +4,14 @@ 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
|
|
||||||
{
|
|
||||||
private static readonly List<QMUIElement> USM_QmUiElements = new();
|
|
||||||
|
|
||||||
private static void Setup_UniversalScalingSettings(Page page)
|
public static partial class BtkUiAddon
|
||||||
{
|
{
|
||||||
|
private static readonly List<QMUIElement> USM_QmUiElements = new();
|
||||||
|
|
||||||
|
private static void Setup_UniversalScalingSettings(Page page)
|
||||||
|
{
|
||||||
Category uniScalingCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_USM_SettingsCategory);
|
Category uniScalingCategory = AddMelonCategory(ref page, ModSettings.Hidden_Foldout_USM_SettingsCategory);
|
||||||
|
|
||||||
SliderFloat scaleSlider = AddMelonSlider(ref uniScalingCategory, ModSettings.EntryHiddenAvatarHeight, AvatarScaleManager.DefaultMinHeight, AvatarScaleManager.DefaultMaxHeight);
|
SliderFloat scaleSlider = AddMelonSlider(ref uniScalingCategory, ModSettings.EntryHiddenAvatarHeight, AvatarScaleManager.DefaultMinHeight, AvatarScaleManager.DefaultMaxHeight);
|
||||||
|
@ -52,24 +52,23 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
ModSettings.EntryUseUniversalScaling.OnEntryValueChanged.Subscribe((_, newValue) => OnUniversalScalingChanged(newValue));
|
ModSettings.EntryUseUniversalScaling.OnEntryValueChanged.Subscribe((_, newValue) => OnUniversalScalingChanged(newValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnUniversalScalingChanged(bool value)
|
private static void OnUniversalScalingChanged(bool value)
|
||||||
{
|
{
|
||||||
foreach (QMUIElement uiElement in USM_QmUiElements)
|
foreach (QMUIElement uiElement in USM_QmUiElements)
|
||||||
uiElement.Disabled = !value;
|
uiElement.Disabled = !value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Slider Events
|
#region Slider Events
|
||||||
|
|
||||||
private static void OnAvatarHeightSliderChanged(float height)
|
private static void OnAvatarHeightSliderChanged(float height)
|
||||||
{
|
{
|
||||||
AvatarScaleManager.Instance.SetTargetHeight(height);
|
AvatarScaleManager.Instance.SetTargetHeight(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnAvatarHeightSliderReset()
|
private static void OnAvatarHeightSliderReset()
|
||||||
{
|
{
|
||||||
AvatarScaleManager.Instance.Setting_UniversalScaling = false;
|
AvatarScaleManager.Instance.Setting_UniversalScaling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -3,15 +3,15 @@ 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 string _selectedPlayer;
|
||||||
private static Button _playerHasModElement;
|
|
||||||
private static string _selectedPlayer;
|
|
||||||
|
|
||||||
private static void Setup_PlayerSelectPage()
|
private static void Setup_PlayerSelectPage()
|
||||||
{
|
{
|
||||||
QuickMenuAPI.OnPlayerSelected += OnPlayerSelected;
|
QuickMenuAPI.OnPlayerSelected += OnPlayerSelected;
|
||||||
|
|
||||||
Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ModSettings.ASM_SettingsCategory, ModSettings.ModName);
|
Category category = QuickMenuAPI.PlayerSelectPage.AddCategory(ModSettings.ASM_SettingsCategory, ModSettings.ModName);
|
||||||
|
@ -22,27 +22,27 @@ namespace NAK.AvatarScaleMod.Integrations
|
||||||
button.OnPress += OnCopyPlayerHeight;
|
button.OnPress += OnCopyPlayerHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region QM Events
|
#region QM Events
|
||||||
|
|
||||||
private static void OnPlayerSelected(string _, string id)
|
private static void OnPlayerSelected(string _, string id)
|
||||||
{
|
{
|
||||||
_selectedPlayer = id;
|
_selectedPlayer = id;
|
||||||
UpdatePlayerHasModIcon();
|
UpdatePlayerHasModIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void OnCopyPlayerHeight()
|
private static void OnCopyPlayerHeight()
|
||||||
{
|
{
|
||||||
float networkHeight = AvatarScaleManager.Instance.GetNetworkHeight(_selectedPlayer);
|
float networkHeight = AvatarScaleManager.Instance.GetNetworkHeight(_selectedPlayer);
|
||||||
if (networkHeight < 0) return;
|
if (networkHeight < 0) return;
|
||||||
AvatarScaleManager.Instance.SetTargetHeight(networkHeight);
|
AvatarScaleManager.Instance.SetTargetHeight(networkHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private static void UpdatePlayerHasModIcon()
|
private static void UpdatePlayerHasModIcon()
|
||||||
{
|
{
|
||||||
if (_playerHasModElement == null)
|
if (_playerHasModElement == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -60,6 +60,5 @@ 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,12 +3,12 @@ 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)
|
|
||||||
{
|
|
||||||
string l_result = "";
|
string l_result = "";
|
||||||
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
Assembly l_assembly = Assembly.GetExecutingAssembly();
|
||||||
string l_assemblyName = l_assembly.GetName().Name;
|
string l_assemblyName = l_assembly.GetName().Name;
|
||||||
|
@ -23,5 +23,4 @@ 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