92 lines
4.7 KiB
C#
92 lines
4.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using VF.Builder;
|
|
using VF.Builder.Exceptions;
|
|
using VF.Feature.Base;
|
|
using VF.Model;
|
|
using VRC.SDK3.Avatars.Components;
|
|
|
|
namespace VF.Feature {
|
|
public class BakeGlobalCollidersBuilder : FeatureBuilder {
|
|
[FeatureBuilderAction]
|
|
public void Apply() {
|
|
|
|
var fakeHead = allBuildersInRun.OfType<FakeHeadBuilder>().First();
|
|
var globalContacts = avatarObject.GetComponentsInChildren<VRCFGlobalCollider>(true);
|
|
var avatar = avatarObject.GetComponent<VRCAvatarDescriptor>();
|
|
|
|
var fingers = new List<(HumanBodyBones, VRCAvatarDescriptor.ColliderConfig, Action<VRCAvatarDescriptor.ColliderConfig>)> {
|
|
( HumanBodyBones.LeftRingIntermediate, avatar.collider_fingerRingL, c => avatar.collider_fingerRingL = c ),
|
|
( HumanBodyBones.RightRingIntermediate, avatar.collider_fingerRingR, c => avatar.collider_fingerRingR = c ),
|
|
( HumanBodyBones.LeftLittleIntermediate, avatar.collider_fingerLittleL, c => avatar.collider_fingerLittleL = c ),
|
|
( HumanBodyBones.RightLittleIntermediate, avatar.collider_fingerLittleR, c => avatar.collider_fingerLittleR = c ),
|
|
( HumanBodyBones.LeftMiddleIntermediate, avatar.collider_fingerMiddleL, c => avatar.collider_fingerMiddleL = c ),
|
|
( HumanBodyBones.RightMiddleIntermediate, avatar.collider_fingerMiddleR, c => avatar.collider_fingerMiddleR = c ),
|
|
};
|
|
|
|
// Put unused fingers on the front of the list
|
|
{
|
|
var unused = new List<(HumanBodyBones, VRCAvatarDescriptor.ColliderConfig, Action<VRCAvatarDescriptor.ColliderConfig>)>();
|
|
var used = new List<(HumanBodyBones, VRCAvatarDescriptor.ColliderConfig, Action<VRCAvatarDescriptor.ColliderConfig>)>();
|
|
while (fingers.Count >= 2) {
|
|
var left = fingers[0];
|
|
var right = fingers[1];
|
|
fingers.RemoveRange(0, 2);
|
|
if (!IsFingerUsed(left.Item1, left.Item2) && (left.Item2.isMirrored || !IsFingerUsed(right.Item1, right.Item2))) {
|
|
unused.Add(left);
|
|
unused.Add(right);
|
|
} else {
|
|
used.Add(left);
|
|
used.Add(right);
|
|
}
|
|
}
|
|
fingers.Clear();
|
|
fingers.AddRange(unused);
|
|
fingers.AddRange(used);
|
|
}
|
|
|
|
if (globalContacts.Length > fingers.Count) {
|
|
throw new VRCFBuilderException("Too many VRCF global colliders are present on this avatar");
|
|
}
|
|
|
|
var i = 0;
|
|
foreach (var globalContact in globalContacts) {
|
|
fakeHead.MarkEligible(globalContact.gameObject);
|
|
var finger = fingers[i].Item2;
|
|
var setFinger = fingers[i].Item3;
|
|
finger.isMirrored = false;
|
|
finger.state = VRCAvatarDescriptor.ColliderConfig.State.Custom;
|
|
// We can't make this height customizable because vrchat does its own weird calculations at runtime,
|
|
// replacing this value with something to do with the distance between the current object and the parent.
|
|
finger.height = 0;
|
|
finger.position = Vector3.zero;
|
|
finger.radius = globalContact.radius;
|
|
finger.rotation = Quaternion.identity;
|
|
// Because vrchat recalculates the capsule length based on distance between child and parent,
|
|
// we place the collider on an identical child object, essentially ensuring the capsule height is 0 (sphere)
|
|
var childObj = new GameObject("GlobalContact");
|
|
childObj.transform.SetParent(globalContact.transform, false);
|
|
finger.transform = childObj.transform;
|
|
setFinger(finger);
|
|
i++;
|
|
}
|
|
if (i % 2 == 1) {
|
|
// If an odd number, disable the matching mirrored finger
|
|
var finger = fingers[i].Item2;
|
|
var setFinger = fingers[i].Item3;
|
|
finger.isMirrored = false;
|
|
finger.state = VRCAvatarDescriptor.ColliderConfig.State.Disabled;
|
|
setFinger(finger);
|
|
}
|
|
}
|
|
|
|
private bool IsFingerUsed(HumanBodyBones bone, VRCAvatarDescriptor.ColliderConfig config) {
|
|
var animator = avatarObject.GetComponent<Animator>();
|
|
if (config.state == VRCAvatarDescriptor.ColliderConfig.State.Disabled) return false;
|
|
if (animator.GetBoneTransform(bone) == null) return false;
|
|
return true;
|
|
}
|
|
}
|
|
} |